From 182d919b84902eece162c63ed3d476c8016b4197 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 19 Feb 2015 23:47:31 +0000 Subject: FS-Cache: Count culled objects and objects rejected due to lack of space Count the number of objects that get culled by the cache backend and the number of objects that the cache backend declines to instantiate due to lack of space in the cache. These numbers are made available through /proc/fs/fscache/stats Signed-off-by: David Howells Reviewed-by: Steve Dickson Acked-by: Jeff Layton --- include/linux/fscache-cache.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include') diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 771484993ca7..c9dafdaf3347 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -371,6 +371,7 @@ struct fscache_object { #define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */ #define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */ #define FSCACHE_OBJECT_RETIRED 6 /* T if object was retired on relinquishment */ +#define FSCACHE_OBJECT_KILLED_BY_CACHE 7 /* T if object was killed by the cache */ struct list_head cache_link; /* link in cache->object_list */ struct hlist_node cookie_link; /* link in cookie->backing_objects */ @@ -551,4 +552,15 @@ extern enum fscache_checkaux fscache_check_aux(struct fscache_object *object, const void *data, uint16_t datalen); +extern void fscache_object_retrying_stale(struct fscache_object *object); + +enum fscache_why_object_killed { + FSCACHE_OBJECT_IS_STALE, + FSCACHE_OBJECT_NO_SPACE, + FSCACHE_OBJECT_WAS_RETIRED, + FSCACHE_OBJECT_WAS_CULLED, +}; +extern void fscache_object_mark_killed(struct fscache_object *object, + enum fscache_why_object_killed why); + #endif /* _LINUX_FSCACHE_CACHE_H */ -- cgit v1.2.3 From 30ceec6284129662efc3a1e7675b2bd857a046fe Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 24 Feb 2015 10:05:27 +0000 Subject: FS-Cache: When submitting an op, cancel it if the target object is dying When submitting an operation, prefer to cancel the operation immediately rather than queuing it for later processing if the object is marked as dying (ie. the object state machine has reached the KILL_OBJECT state). Whilst we're at it, change the series of related test_bit() calls into a READ_ONCE() and bitwise-AND operators to reduce the number of load instructions (test_bit() has a volatile address). Signed-off-by: David Howells Reviewed-by: Steve Dickson Acked-by: Jeff Layton --- fs/fscache/operation.c | 47 +++++++++++++++++++++++++++---------------- include/linux/fscache-cache.h | 9 +++++++-- 2 files changed, 37 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 68ead8482617..dec6defe3be3 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -120,6 +120,8 @@ static void fscache_report_unexpected_submission(struct fscache_object *object, int fscache_submit_exclusive_op(struct fscache_object *object, struct fscache_operation *op) { + const struct fscache_state *ostate; + unsigned long flags; int ret; _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); @@ -132,8 +134,19 @@ int fscache_submit_exclusive_op(struct fscache_object *object, ASSERTCMP(object->n_ops, >=, object->n_exclusive); ASSERT(list_empty(&op->pend_link)); + ostate = object->state; + smp_rmb(); + op->state = FSCACHE_OP_ST_PENDING; - if (fscache_object_is_active(object)) { + flags = READ_ONCE(object->flags); + if (unlikely(!(flags & BIT(FSCACHE_OBJECT_IS_LIVE)))) { + fscache_stat(&fscache_n_op_rejected); + op->state = FSCACHE_OP_ST_CANCELLED; + ret = -ENOBUFS; + } else if (unlikely(fscache_cache_is_broken(object))) { + op->state = FSCACHE_OP_ST_CANCELLED; + ret = -EIO; + } else if (flags & BIT(FSCACHE_OBJECT_IS_AVAILABLE)) { op->object = object; object->n_ops++; object->n_exclusive++; /* reads and writes must wait */ @@ -155,7 +168,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object, /* need to issue a new write op after this */ clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); ret = 0; - } else if (test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) { + } else if (flags & BIT(FSCACHE_OBJECT_IS_LOOKED_UP)) { op->object = object; object->n_ops++; object->n_exclusive++; /* reads and writes must wait */ @@ -164,11 +177,9 @@ int fscache_submit_exclusive_op(struct fscache_object *object, fscache_stat(&fscache_n_op_pend); ret = 0; } else { - /* If we're in any other state, there must have been an I/O - * error of some nature. - */ - ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags)); - ret = -EIO; + fscache_report_unexpected_submission(object, op, ostate); + op->state = FSCACHE_OP_ST_CANCELLED; + ret = -ENOBUFS; } spin_unlock(&object->lock); @@ -187,6 +198,7 @@ int fscache_submit_op(struct fscache_object *object, struct fscache_operation *op) { const struct fscache_state *ostate; + unsigned long flags; int ret; _enter("{OBJ%x OP%x},{%u}", @@ -204,7 +216,15 @@ int fscache_submit_op(struct fscache_object *object, smp_rmb(); op->state = FSCACHE_OP_ST_PENDING; - if (fscache_object_is_active(object)) { + flags = READ_ONCE(object->flags); + if (unlikely(!(flags & BIT(FSCACHE_OBJECT_IS_LIVE)))) { + fscache_stat(&fscache_n_op_rejected); + op->state = FSCACHE_OP_ST_CANCELLED; + ret = -ENOBUFS; + } else if (unlikely(fscache_cache_is_broken(object))) { + op->state = FSCACHE_OP_ST_CANCELLED; + ret = -EIO; + } else if (flags & BIT(FSCACHE_OBJECT_IS_AVAILABLE)) { op->object = object; object->n_ops++; @@ -222,25 +242,18 @@ int fscache_submit_op(struct fscache_object *object, fscache_run_op(object, op); } ret = 0; - } else if (test_bit(FSCACHE_OBJECT_IS_LOOKED_UP, &object->flags)) { + } else if (flags & BIT(FSCACHE_OBJECT_IS_LOOKED_UP)) { op->object = object; object->n_ops++; atomic_inc(&op->usage); list_add_tail(&op->pend_link, &object->pending_ops); fscache_stat(&fscache_n_op_pend); ret = 0; - } else if (fscache_object_is_dying(object)) { - fscache_stat(&fscache_n_op_rejected); - op->state = FSCACHE_OP_ST_CANCELLED; - ret = -ENOBUFS; - } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { + } else { fscache_report_unexpected_submission(object, op, ostate); ASSERT(!fscache_object_is_active(object)); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; - } else { - op->state = FSCACHE_OP_ST_CANCELLED; - ret = -ENOBUFS; } spin_unlock(&object->lock); diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index c9dafdaf3347..2e83a141e465 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -411,17 +411,22 @@ static inline bool fscache_object_is_available(struct fscache_object *object) return test_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); } +static inline bool fscache_cache_is_broken(struct fscache_object *object) +{ + return test_bit(FSCACHE_IOERROR, &object->cache->flags); +} + static inline bool fscache_object_is_active(struct fscache_object *object) { return fscache_object_is_available(object) && fscache_object_is_live(object) && - !test_bit(FSCACHE_IOERROR, &object->cache->flags); + !fscache_cache_is_broken(object); } static inline bool fscache_object_is_dead(struct fscache_object *object) { return fscache_object_is_dying(object) && - test_bit(FSCACHE_IOERROR, &object->cache->flags); + fscache_cache_is_broken(object); } /** -- cgit v1.2.3 From 87021526300f1a292dd966e141e183630ac95317 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 24 Feb 2015 10:52:51 +0000 Subject: FS-Cache: fscache_object_is_dead() has wrong logic, kill it fscache_object_is_dead() returns true only if the object is marked dead and the cache got an I/O error. This should be a logical OR instead. Since two of the callers got split up into handling for separate subcases, expand the other callers and kill the function. This is probably the right thing to do anyway since one of the subcases isn't about the object at all, but rather about the cache. Signed-off-by: David Howells Reviewed-by: Steve Dickson Acked-by: Jeff Layton --- fs/fscache/cookie.c | 3 ++- fs/fscache/page.c | 6 ++++-- include/linux/fscache-cache.h | 6 ------ 3 files changed, 6 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 89acec742e0b..8de22164f5fb 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -327,7 +327,8 @@ static int fscache_alloc_object(struct fscache_cache *cache, object_already_extant: ret = -ENOBUFS; - if (fscache_object_is_dead(object)) { + if (fscache_object_is_dying(object) || + fscache_cache_is_broken(object)) { spin_unlock(&cookie->lock); goto error; } diff --git a/fs/fscache/page.c b/fs/fscache/page.c index de33b3fccca6..d0805e31361c 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -377,11 +377,13 @@ check_if_dead: _leave(" = -ENOBUFS [cancelled]"); return -ENOBUFS; } - if (unlikely(fscache_object_is_dead(object))) { - pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->state); + if (unlikely(fscache_object_is_dying(object) || + fscache_cache_is_broken(object))) { + enum fscache_operation_state state = op->state; fscache_cancel_op(op, do_cancel); if (stat_object_dead) fscache_stat(stat_object_dead); + _leave(" = -ENOBUFS [obj dead %d]", state); return -ENOBUFS; } return 0; diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 2e83a141e465..ca3d550da11e 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -423,12 +423,6 @@ static inline bool fscache_object_is_active(struct fscache_object *object) !fscache_cache_is_broken(object); } -static inline bool fscache_object_is_dead(struct fscache_object *object) -{ - return fscache_object_is_dying(object) && - fscache_cache_is_broken(object); -} - /** * fscache_object_destroyed - Note destruction of an object in a cache * @cache: The cache from which the object came -- cgit v1.2.3 From 1339ec98e32b4bc8efb6fbb71c006a465130aaba Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 25 Feb 2015 13:26:39 +0000 Subject: FS-Cache: Out of line fscache_operation_init() Out of line fscache_operation_init() so that it can access internal FS-Cache features, such as stats, in a later commit. Signed-off-by: David Howells Reviewed-by: Steve Dickson Acked-by: Jeff Layton --- fs/fscache/operation.c | 22 ++++++++++++++++++++++ include/linux/fscache-cache.h | 24 +++--------------------- 2 files changed, 25 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 67594a8d791a..61a6e78b85fa 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -20,6 +20,28 @@ atomic_t fscache_op_debug_id; EXPORT_SYMBOL(fscache_op_debug_id); +/** + * fscache_operation_init - Do basic initialisation of an operation + * @op: The operation to initialise + * @release: The release function to assign + * + * Do basic initialisation of an operation. The caller must still set flags, + * object and processor if needed. + */ +void fscache_operation_init(struct fscache_operation *op, + fscache_operation_processor_t processor, + fscache_operation_release_t release) +{ + INIT_WORK(&op->work, fscache_op_work_func); + atomic_set(&op->usage, 1); + op->state = FSCACHE_OP_ST_INITIALISED; + op->debug_id = atomic_inc_return(&fscache_op_debug_id); + op->processor = processor; + op->release = release; + INIT_LIST_HEAD(&op->pend_link); +} +EXPORT_SYMBOL(fscache_operation_init); + /** * fscache_enqueue_operation - Enqueue an operation for processing * @op: The operation to enqueue diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index ca3d550da11e..0e26d49972e3 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -119,27 +119,9 @@ extern void fscache_op_work_func(struct work_struct *work); extern void fscache_enqueue_operation(struct fscache_operation *); extern void fscache_op_complete(struct fscache_operation *, bool); extern void fscache_put_operation(struct fscache_operation *); - -/** - * fscache_operation_init - Do basic initialisation of an operation - * @op: The operation to initialise - * @release: The release function to assign - * - * Do basic initialisation of an operation. The caller must still set flags, - * object and processor if needed. - */ -static inline void fscache_operation_init(struct fscache_operation *op, - fscache_operation_processor_t processor, - fscache_operation_release_t release) -{ - INIT_WORK(&op->work, fscache_op_work_func); - atomic_set(&op->usage, 1); - op->state = FSCACHE_OP_ST_INITIALISED; - op->debug_id = atomic_inc_return(&fscache_op_debug_id); - op->processor = processor; - op->release = release; - INIT_LIST_HEAD(&op->pend_link); -} +extern void fscache_operation_init(struct fscache_operation *, + fscache_operation_processor_t, + fscache_operation_release_t); /* * data read operation -- cgit v1.2.3 From d3b97ca4a99e4e6c78f5a21c968eadf5c8ba9971 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 24 Feb 2015 10:05:29 +0000 Subject: FS-Cache: The operation cancellation method needs calling in more places Any time an incomplete operation is cancelled, the operation cancellation function needs to be called to clean up. This is currently being passed directly to some of the functions that might want to call it, but not all. Instead, pass the cancellation method pointer to the fscache_operation_init() and have that cache it in the operation struct. Further, plug in a dummy cancellation handler if the caller declines to set one as this allows us to call the function unconditionally (the extra overhead isn't worth bothering about as we don't expect to be calling this typically). The cancellation method must thence be called everywhere the CANCELLED state is set. Note that we call it *before* setting the CANCELLED state such that the method can use the old state value to guide its operation. fscache_do_cancel_retrieval() needs moving higher up in the sources so that the init function can use it now. Without this, the following oops may be seen: FS-Cache: Assertion failed FS-Cache: 3 == 0 is false ------------[ cut here ]------------ kernel BUG at ../fs/fscache/page.c:261! ... RIP: 0010:[] fscache_release_retrieval_op+0x77/0x100 [] fscache_put_operation+0x114/0x2da [] __fscache_read_or_alloc_pages+0x358/0x3b3 [] __nfs_readpages_from_fscache+0x59/0xbf [nfs] [] nfs_readpages+0x10c/0x185 [nfs] [] ? alloc_pages_current+0x119/0x13e [] ? __page_cache_alloc+0xfb/0x10a [] __do_page_cache_readahead+0x188/0x22c [] ondemand_readahead+0x29e/0x2af [] page_cache_sync_readahead+0x38/0x3a [] generic_file_read_iter+0x1a2/0x55a [] ? nfs_revalidate_mapping+0xd6/0x288 [nfs] [] nfs_file_read+0x49/0x70 [nfs] [] new_sync_read+0x78/0x9c [] __vfs_read+0x13/0x38 [] vfs_read+0x95/0x121 [] SyS_read+0x4c/0x8a [] system_call_fastpath+0x12/0x17 The assertion is showing that the remaining number of pages (n_pages) is not 0 when the operation is being released. Signed-off-by: David Howells Reviewed-by: Steve Dickson Acked-by: Jeff Layton --- fs/fscache/cookie.c | 5 ++--- fs/fscache/internal.h | 7 ++----- fs/fscache/object.c | 3 ++- fs/fscache/operation.c | 31 ++++++++++++++++++++++------- fs/fscache/page.c | 46 +++++++++++++++++++++---------------------- include/linux/fscache-cache.h | 5 +++++ 6 files changed, 57 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 8de22164f5fb..d403c69bee08 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c @@ -672,7 +672,7 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) if (!op) return -ENOMEM; - fscache_operation_init(op, NULL, NULL); + fscache_operation_init(op, NULL, NULL, NULL); op->flags = FSCACHE_OP_MYTHREAD | (1 << FSCACHE_OP_WAITING) | (1 << FSCACHE_OP_UNUSE_COOKIE); @@ -696,8 +696,7 @@ int __fscache_check_consistency(struct fscache_cookie *cookie) /* the work queue now carries its own ref on the object */ spin_unlock(&cookie->lock); - ret = fscache_wait_for_operation_activation(object, op, - NULL, NULL, NULL); + ret = fscache_wait_for_operation_activation(object, op, NULL, NULL); if (ret == 0) { /* ask the cache to honour the operation */ ret = object->cache->ops->check_consistency(op); diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index a63225116db6..97ec45110957 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h @@ -124,9 +124,7 @@ extern int fscache_submit_exclusive_op(struct fscache_object *, struct fscache_operation *); extern int fscache_submit_op(struct fscache_object *, struct fscache_operation *); -extern int fscache_cancel_op(struct fscache_operation *, - void (*)(struct fscache_operation *), - bool); +extern int fscache_cancel_op(struct fscache_operation *, bool); extern void fscache_cancel_all_ops(struct fscache_object *); extern void fscache_abort_object(struct fscache_object *); extern void fscache_start_operations(struct fscache_object *); @@ -139,8 +137,7 @@ extern int fscache_wait_for_deferred_lookup(struct fscache_cookie *); extern int fscache_wait_for_operation_activation(struct fscache_object *, struct fscache_operation *, atomic_t *, - atomic_t *, - void (*)(struct fscache_operation *)); + atomic_t *); extern void fscache_invalidate_writes(struct fscache_cookie *); /* diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 40049f7505f0..9e792e30f4db 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -961,7 +961,8 @@ static const struct fscache_state *_fscache_invalidate_object(struct fscache_obj if (!op) goto nomem; - fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); + fscache_operation_init(op, object->cache->ops->invalidate_object, + NULL, NULL); op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE) | (1 << FSCACHE_OP_UNUSE_COOKIE); diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index c76c09730768..57d4abb68656 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -20,6 +20,10 @@ atomic_t fscache_op_debug_id; EXPORT_SYMBOL(fscache_op_debug_id); +static void fscache_operation_dummy_cancel(struct fscache_operation *op) +{ +} + /** * fscache_operation_init - Do basic initialisation of an operation * @op: The operation to initialise @@ -30,6 +34,7 @@ EXPORT_SYMBOL(fscache_op_debug_id); */ void fscache_operation_init(struct fscache_operation *op, fscache_operation_processor_t processor, + fscache_operation_cancel_t cancel, fscache_operation_release_t release) { INIT_WORK(&op->work, fscache_op_work_func); @@ -37,6 +42,7 @@ void fscache_operation_init(struct fscache_operation *op, op->state = FSCACHE_OP_ST_INITIALISED; op->debug_id = atomic_inc_return(&fscache_op_debug_id); op->processor = processor; + op->cancel = cancel ?: fscache_operation_dummy_cancel; op->release = release; INIT_LIST_HEAD(&op->pend_link); fscache_stat(&fscache_n_op_initialised); @@ -164,9 +170,11 @@ int fscache_submit_exclusive_op(struct fscache_object *object, flags = READ_ONCE(object->flags); if (unlikely(!(flags & BIT(FSCACHE_OBJECT_IS_LIVE)))) { fscache_stat(&fscache_n_op_rejected); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; } else if (unlikely(fscache_cache_is_broken(object))) { + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -EIO; } else if (flags & BIT(FSCACHE_OBJECT_IS_AVAILABLE)) { @@ -200,10 +208,12 @@ int fscache_submit_exclusive_op(struct fscache_object *object, fscache_stat(&fscache_n_op_pend); ret = 0; } else if (flags & BIT(FSCACHE_OBJECT_KILLED_BY_CACHE)) { + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; } else { fscache_report_unexpected_submission(object, op, ostate); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; } @@ -245,9 +255,11 @@ int fscache_submit_op(struct fscache_object *object, flags = READ_ONCE(object->flags); if (unlikely(!(flags & BIT(FSCACHE_OBJECT_IS_LIVE)))) { fscache_stat(&fscache_n_op_rejected); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; } else if (unlikely(fscache_cache_is_broken(object))) { + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -EIO; } else if (flags & BIT(FSCACHE_OBJECT_IS_AVAILABLE)) { @@ -276,11 +288,13 @@ int fscache_submit_op(struct fscache_object *object, fscache_stat(&fscache_n_op_pend); ret = 0; } else if (flags & BIT(FSCACHE_OBJECT_KILLED_BY_CACHE)) { + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; } else { fscache_report_unexpected_submission(object, op, ostate); ASSERT(!fscache_object_is_active(object)); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; ret = -ENOBUFS; } @@ -335,7 +349,6 @@ void fscache_start_operations(struct fscache_object *object) * cancel an operation that's pending on an object */ int fscache_cancel_op(struct fscache_operation *op, - void (*do_cancel)(struct fscache_operation *), bool cancel_in_progress_op) { struct fscache_object *object = op->object; @@ -355,9 +368,9 @@ int fscache_cancel_op(struct fscache_operation *op, ASSERT(!list_empty(&op->pend_link)); list_del_init(&op->pend_link); put = true; + fscache_stat(&fscache_n_op_cancelled); - if (do_cancel) - do_cancel(op); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) object->n_exclusive--; @@ -373,8 +386,7 @@ int fscache_cancel_op(struct fscache_operation *op, fscache_start_operations(object); fscache_stat(&fscache_n_op_cancelled); - if (do_cancel) - do_cancel(op); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) object->n_exclusive--; @@ -408,6 +420,7 @@ void fscache_cancel_all_ops(struct fscache_object *object) list_del_init(&op->pend_link); ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); + op->cancel(op); op->state = FSCACHE_OP_ST_CANCELLED; if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) @@ -440,8 +453,12 @@ void fscache_op_complete(struct fscache_operation *op, bool cancelled) spin_lock(&object->lock); - op->state = cancelled ? - FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE; + if (!cancelled) { + op->state = FSCACHE_OP_ST_COMPLETE; + } else { + op->cancel(op); + op->state = FSCACHE_OP_ST_CANCELLED; + } if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) object->n_exclusive--; diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 7db9752252ef..d1b23a67c031 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -213,7 +213,7 @@ int __fscache_attr_changed(struct fscache_cookie *cookie) return -ENOMEM; } - fscache_operation_init(op, fscache_attr_changed_op, NULL); + fscache_operation_init(op, fscache_attr_changed_op, NULL, NULL); op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE) | (1 << FSCACHE_OP_UNUSE_COOKIE); @@ -248,6 +248,17 @@ nobufs: } EXPORT_SYMBOL(__fscache_attr_changed); +/* + * Handle cancellation of a pending retrieval op + */ +static void fscache_do_cancel_retrieval(struct fscache_operation *_op) +{ + struct fscache_retrieval *op = + container_of(_op, struct fscache_retrieval, op); + + atomic_set(&op->n_pages, 0); +} + /* * release a retrieval op reference */ @@ -285,7 +296,9 @@ static struct fscache_retrieval *fscache_alloc_retrieval( return NULL; } - fscache_operation_init(&op->op, NULL, fscache_release_retrieval_op); + fscache_operation_init(&op->op, NULL, + fscache_do_cancel_retrieval, + fscache_release_retrieval_op); op->op.flags = FSCACHE_OP_MYTHREAD | (1UL << FSCACHE_OP_WAITING) | (1UL << FSCACHE_OP_UNUSE_COOKIE); @@ -329,25 +342,13 @@ int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) return 0; } -/* - * Handle cancellation of a pending retrieval op - */ -static void fscache_do_cancel_retrieval(struct fscache_operation *_op) -{ - struct fscache_retrieval *op = - container_of(_op, struct fscache_retrieval, op); - - atomic_set(&op->n_pages, 0); -} - /* * wait for an object to become active (or dead) */ int fscache_wait_for_operation_activation(struct fscache_object *object, struct fscache_operation *op, atomic_t *stat_op_waits, - atomic_t *stat_object_dead, - void (*do_cancel)(struct fscache_operation *)) + atomic_t *stat_object_dead) { int ret; @@ -359,7 +360,7 @@ int fscache_wait_for_operation_activation(struct fscache_object *object, fscache_stat(stat_op_waits); if (wait_on_bit(&op->flags, FSCACHE_OP_WAITING, TASK_INTERRUPTIBLE) != 0) { - ret = fscache_cancel_op(op, do_cancel, false); + ret = fscache_cancel_op(op, false); if (ret == 0) return -ERESTARTSYS; @@ -380,7 +381,7 @@ check_if_dead: if (unlikely(fscache_object_is_dying(object) || fscache_cache_is_broken(object))) { enum fscache_operation_state state = op->state; - fscache_cancel_op(op, do_cancel, true); + fscache_cancel_op(op, true); if (stat_object_dead) fscache_stat(stat_object_dead); _leave(" = -ENOBUFS [obj dead %d]", state); @@ -464,8 +465,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, ret = fscache_wait_for_operation_activation( object, &op->op, __fscache_stat(&fscache_n_retrieval_op_waits), - __fscache_stat(&fscache_n_retrievals_object_dead), - fscache_do_cancel_retrieval); + __fscache_stat(&fscache_n_retrievals_object_dead)); if (ret < 0) goto error; @@ -595,8 +595,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, ret = fscache_wait_for_operation_activation( object, &op->op, __fscache_stat(&fscache_n_retrieval_op_waits), - __fscache_stat(&fscache_n_retrievals_object_dead), - fscache_do_cancel_retrieval); + __fscache_stat(&fscache_n_retrievals_object_dead)); if (ret < 0) goto error; @@ -702,8 +701,7 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, ret = fscache_wait_for_operation_activation( object, &op->op, __fscache_stat(&fscache_n_alloc_op_waits), - __fscache_stat(&fscache_n_allocs_object_dead), - fscache_do_cancel_retrieval); + __fscache_stat(&fscache_n_allocs_object_dead)); if (ret < 0) goto error; @@ -946,7 +944,7 @@ int __fscache_write_page(struct fscache_cookie *cookie, if (!op) goto nomem; - fscache_operation_init(&op->op, fscache_write_op, + fscache_operation_init(&op->op, fscache_write_op, NULL, fscache_release_write_op); op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING) | diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 0e26d49972e3..69c6eb10d858 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -74,6 +74,7 @@ extern wait_queue_head_t fscache_cache_cleared_wq; */ typedef void (*fscache_operation_release_t)(struct fscache_operation *op); typedef void (*fscache_operation_processor_t)(struct fscache_operation *op); +typedef void (*fscache_operation_cancel_t)(struct fscache_operation *op); enum fscache_operation_state { FSCACHE_OP_ST_BLANK, /* Op is not yet submitted */ @@ -109,6 +110,9 @@ struct fscache_operation { * the op in a non-pool thread */ fscache_operation_processor_t processor; + /* Operation cancellation cleanup (optional) */ + fscache_operation_cancel_t cancel; + /* operation releaser */ fscache_operation_release_t release; }; @@ -121,6 +125,7 @@ extern void fscache_op_complete(struct fscache_operation *, bool); extern void fscache_put_operation(struct fscache_operation *); extern void fscache_operation_init(struct fscache_operation *, fscache_operation_processor_t, + fscache_operation_cancel_t, fscache_operation_release_t); /* -- cgit v1.2.3 From 4a47132ff472a0c2c5441baeb50cf97f2580bc43 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 24 Feb 2015 10:05:29 +0000 Subject: FS-Cache: Retain the netfs context in the retrieval op earlier Now that the retrieval operation may be disposed of by fscache_put_operation() before we actually set the context, the retrieval-specific cleanup operation can produce a NULL-pointer dereference when it tries to unconditionally clean up the netfs context. Given that it is expected that we'll get at least as far as the place where we currently set the context pointer and it is unlikely we'll go through the error handling paths prior to that point, retain the context right from the point that the retrieval op is allocated. Concomitant to this, we need to retain the cookie pointer in the retrieval op also so that we can call the netfs to release its context in the release method. In addition, we might now get into fscache_release_retrieval_op() with the op only initialised. To this end, set the operation to DEAD only after the release method has been called and skip the n_pages test upon cleanup if the op is still in the INITIALISED state. Without these changes, the following oops might be seen: BUG: unable to handle kernel NULL pointer dereference at 00000000000000b8 ... RIP: 0010:[] fscache_release_retrieval_op+0xae/0x100 ... Call Trace: [] fscache_put_operation+0x117/0x2e0 [] __fscache_read_or_alloc_pages+0x351/0x3ac [] __nfs_readpages_from_fscache+0x59/0xbf [nfs] [] nfs_readpages+0x10c/0x185 [nfs] [] ? alloc_pages_current+0x119/0x13e [] ? __page_cache_alloc+0xfb/0x10a [] __do_page_cache_readahead+0x188/0x22c [] ondemand_readahead+0x29e/0x2af [] page_cache_sync_readahead+0x38/0x3a [] generic_file_read_iter+0x1a2/0x55a [] ? nfs_revalidate_mapping+0xd6/0x288 [nfs] [] nfs_file_read+0x49/0x70 [nfs] [] new_sync_read+0x78/0x9c [] __vfs_read+0x13/0x38 [] vfs_read+0x95/0x121 [] SyS_read+0x4c/0x8a [] system_call_fastpath+0x12/0x17 Signed-off-by: David Howells Reviewed-by: Steve Dickson Acked-by: Jeff Layton --- fs/fscache/operation.c | 2 +- fs/fscache/page.c | 20 ++++++++++---------- include/linux/fscache-cache.h | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 57d4abb68656..de67745e1cd7 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c @@ -492,7 +492,6 @@ void fscache_put_operation(struct fscache_operation *op) ASSERTIFCMP(op->state != FSCACHE_OP_ST_INITIALISED && op->state != FSCACHE_OP_ST_COMPLETE, op->state, ==, FSCACHE_OP_ST_CANCELLED); - op->state = FSCACHE_OP_ST_DEAD; fscache_stat(&fscache_n_op_release); @@ -500,6 +499,7 @@ void fscache_put_operation(struct fscache_operation *op) op->release(op); op->release = NULL; } + op->state = FSCACHE_OP_ST_DEAD; object = op->object; if (likely(object)) { diff --git a/fs/fscache/page.c b/fs/fscache/page.c index d1b23a67c031..483bbc613bf0 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c @@ -269,11 +269,12 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) _enter("{OP%x}", op->op.debug_id); - ASSERTCMP(atomic_read(&op->n_pages), ==, 0); + ASSERTIFCMP(op->op.state != FSCACHE_OP_ST_INITIALISED, + atomic_read(&op->n_pages), ==, 0); fscache_hist(fscache_retrieval_histogram, op->start_time); if (op->context) - fscache_put_context(op->op.object->cookie, op->context); + fscache_put_context(op->cookie, op->context); _leave(""); } @@ -302,11 +303,18 @@ static struct fscache_retrieval *fscache_alloc_retrieval( op->op.flags = FSCACHE_OP_MYTHREAD | (1UL << FSCACHE_OP_WAITING) | (1UL << FSCACHE_OP_UNUSE_COOKIE); + op->cookie = cookie; op->mapping = mapping; op->end_io_func = end_io_func; op->context = context; op->start_time = jiffies; INIT_LIST_HEAD(&op->to_do); + + /* Pin the netfs read context in case we need to do the actual netfs + * read because we've encountered a cache read failure. + */ + if (context) + fscache_get_context(op->cookie, context); return op; } @@ -456,10 +464,6 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, fscache_stat(&fscache_n_retrieval_ops); - /* pin the netfs read context in case we need to do the actual netfs - * read because we've encountered a cache read failure */ - fscache_get_context(object->cookie, op->context); - /* we wait for the operation to become active, and then process it * *here*, in this thread, and not in the thread pool */ ret = fscache_wait_for_operation_activation( @@ -586,10 +590,6 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, fscache_stat(&fscache_n_retrieval_ops); - /* pin the netfs read context in case we need to do the actual netfs - * read because we've encountered a cache read failure */ - fscache_get_context(object->cookie, op->context); - /* we wait for the operation to become active, and then process it * *here*, in this thread, and not in the thread pool */ ret = fscache_wait_for_operation_activation( diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 69c6eb10d858..604e1526cd00 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h @@ -133,6 +133,7 @@ extern void fscache_operation_init(struct fscache_operation *, */ struct fscache_retrieval { struct fscache_operation op; + struct fscache_cookie *cookie; /* The netfs cookie */ struct address_space *mapping; /* netfs pages */ fscache_rw_complete_t end_io_func; /* function to call on I/O completion */ void *context; /* netfs read context (pinned) */ -- cgit v1.2.3 From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 4 Mar 2015 20:01:14 -0600 Subject: hwspinlock/core: add device tree support This patch adds a new OF-friendly API of_hwspin_lock_get_id() for hwspinlock clients to use/request locks from a hwspinlock device instantiated through a device-tree blob. This new API can be used by hwspinlock clients to get the id for a specific lock using the phandle + args specifier, so that it can be requested using the available hwspin_lock_request_specific() API. Signed-off-by: Suman Anna Reviewed-by: Bjorn Andersson [small comment clarification] Signed-off-by: Ohad Ben-Cohen --- Documentation/hwspinlock.txt | 10 +++++ drivers/hwspinlock/hwspinlock_core.c | 79 ++++++++++++++++++++++++++++++++++++ include/linux/hwspinlock.h | 7 ++++ 3 files changed, 96 insertions(+) (limited to 'include') diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt index 62f7d4ea6e26..61c1ee98e59f 100644 --- a/Documentation/hwspinlock.txt +++ b/Documentation/hwspinlock.txt @@ -48,6 +48,16 @@ independent, drivers. ids for predefined purposes. Should be called from a process context (might sleep). + int of_hwspin_lock_get_id(struct device_node *np, int index); + - retrieve the global lock id for an OF phandle-based specific lock. + This function provides a means for DT users of a hwspinlock module + to get the global lock id of a specific hwspinlock, so that it can + be requested using the normal hwspin_lock_request_specific() API. + The function returns a lock id number on success, -EPROBE_DEFER if + the hwspinlock device is not yet registered with the core, or other + error values. + Should be called from a process context (might sleep). + int hwspin_lock_free(struct hwspinlock *hwlock); - free a previously-assigned hwspinlock; returns 0 on success, or an appropriate error code on failure (e.g. -EINVAL if the hwspinlock diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 461a0d739d75..52f708bcf77f 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "hwspinlock_internal.h" @@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) } EXPORT_SYMBOL_GPL(__hwspin_unlock); +/** + * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id + * @bank: the hwspinlock device bank + * @hwlock_spec: hwlock specifier as found in the device tree + * + * This is a simple translation function, suitable for hwspinlock platform + * drivers that only has a lock specifier length of 1. + * + * Returns a relative index of the lock within a specified bank on success, + * or -EINVAL on invalid specifier cell count. + */ +static inline int +of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec) +{ + if (WARN_ON(hwlock_spec->args_count != 1)) + return -EINVAL; + + return hwlock_spec->args[0]; +} + +/** + * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock + * @np: device node from which to request the specific hwlock + * @index: index of the hwlock in the list of values + * + * This function provides a means for DT users of the hwspinlock module to + * get the global lock id of a specific hwspinlock using the phandle of the + * hwspinlock device, so that it can be requested using the normal + * hwspin_lock_request_specific() API. + * + * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock + * device is not yet registered, -EINVAL on invalid args specifier value or an + * appropriate error as returned from the OF parsing of the DT client node. + */ +int of_hwspin_lock_get_id(struct device_node *np, int index) +{ + struct of_phandle_args args; + struct hwspinlock *hwlock; + struct radix_tree_iter iter; + void **slot; + int id; + int ret; + + ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, + &args); + if (ret) + return ret; + + /* Find the hwspinlock device: we need its base_id */ + ret = -EPROBE_DEFER; + rcu_read_lock(); + radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) { + hwlock = radix_tree_deref_slot(slot); + if (unlikely(!hwlock)) + continue; + + if (hwlock->bank->dev->of_node == args.np) { + ret = 0; + break; + } + } + rcu_read_unlock(); + if (ret < 0) + goto out; + + id = of_hwspin_lock_simple_xlate(&args); + if (id < 0 || id >= hwlock->bank->num_locks) { + ret = -EINVAL; + goto out; + } + id += hwlock->bank->base_id; + +out: + of_node_put(args.np); + return ret ? ret : id; +} +EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id); + static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) { struct hwspinlock *tmp; diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h index 3343298e40e8..859d673d98c8 100644 --- a/include/linux/hwspinlock.h +++ b/include/linux/hwspinlock.h @@ -26,6 +26,7 @@ #define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ struct device; +struct device_node; struct hwspinlock; struct hwspinlock_device; struct hwspinlock_ops; @@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank); struct hwspinlock *hwspin_lock_request(void); struct hwspinlock *hwspin_lock_request_specific(unsigned int id); int hwspin_lock_free(struct hwspinlock *hwlock); +int of_hwspin_lock_get_id(struct device_node *np, int index); int hwspin_lock_get_id(struct hwspinlock *hwlock); int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, unsigned long *); @@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) { } +static inline int of_hwspin_lock_get_id(struct device_node *np, int index) +{ + return 0; +} + static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) { return 0; -- cgit v1.2.3 From 1b852bceb0d111e510d1a15826ecc4a19358d512 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 8 May 2015 23:22:29 -0500 Subject: mnt: Refactor the logic for mounting sysfs and proc in a user namespace Fresh mounts of proc and sysfs are a very special case that works very much like a bind mount. Unfortunately the current structure can not preserve the MNT_LOCK... mount flags. Therefore refactor the logic into a form that can be modified to preserve those lock bits. Add a new filesystem flag FS_USERNS_VISIBLE that requires some mount of the filesystem be fully visible in the current mount namespace, before the filesystem may be mounted. Move the logic for calling fs_fully_visible from proc and sysfs into fs/namespace.c where it has greater access to mount namespace state. Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 8 +++++++- fs/proc/root.c | 5 +---- fs/sysfs/mount.c | 5 +---- include/linux/fs.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/fs/namespace.c b/fs/namespace.c index 1b9e11167bae..8e7edaf60fe1 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2332,6 +2332,8 @@ unlock: return err; } +static bool fs_fully_visible(struct file_system_type *fs_type); + /* * create a new mount for userspace and request it to be added into the * namespace's tree @@ -2363,6 +2365,10 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, flags |= MS_NODEV; mnt_flags |= MNT_NODEV | MNT_LOCK_NODEV; } + if (type->fs_flags & FS_USERNS_VISIBLE) { + if (!fs_fully_visible(type)) + return -EPERM; + } } mnt = vfs_kern_mount(type, flags, name, data); @@ -3164,7 +3170,7 @@ bool current_chrooted(void) return chrooted; } -bool fs_fully_visible(struct file_system_type *type) +static bool fs_fully_visible(struct file_system_type *type) { struct mnt_namespace *ns = current->nsproxy->mnt_ns; struct mount *mnt; diff --git a/fs/proc/root.c b/fs/proc/root.c index b7fa4bfe896a..64e1ab64bde6 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -112,9 +112,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, ns = task_active_pid_ns(current); options = data; - if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) - return ERR_PTR(-EPERM); - /* Does the mounter have privilege over the pid namespace? */ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) return ERR_PTR(-EPERM); @@ -159,7 +156,7 @@ static struct file_system_type proc_fs_type = { .name = "proc", .mount = proc_mount, .kill_sb = proc_kill_sb, - .fs_flags = FS_USERNS_MOUNT, + .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, }; void __init proc_root_init(void) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8a49486bf30c..1c6ac6fcee9f 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -31,9 +31,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, bool new_sb; if (!(flags & MS_KERNMOUNT)) { - if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) - return ERR_PTR(-EPERM); - if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) return ERR_PTR(-EPERM); } @@ -58,7 +55,7 @@ static struct file_system_type sysfs_fs_type = { .name = "sysfs", .mount = sysfs_mount, .kill_sb = sysfs_kill_sb, - .fs_flags = FS_USERNS_MOUNT, + .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT, }; int __init sysfs_init(void) diff --git a/include/linux/fs.h b/include/linux/fs.h index 35ec87e490b1..2d24eeb8e59c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1897,6 +1897,7 @@ struct file_system_type { #define FS_HAS_SUBTYPE 4 #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */ +#define FS_USERNS_VISIBLE 32 /* FS must already be visible */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); @@ -1984,7 +1985,6 @@ extern int vfs_ustat(dev_t, struct kstatfs *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); extern bool our_mnt(struct vfsmount *mnt); -extern bool fs_fully_visible(struct file_system_type *); extern int current_umask(void); -- cgit v1.2.3 From f75b6fae1a1d0a79dcbb9cbaed1d06bf3fe57a3c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Sun, 19 Apr 2015 20:27:19 +0300 Subject: target: Merge sbc_verify_dif_read|write Instead of providing DIF verify routines for read/write that are almost identical and conditionally copy protection information, just let the caller do the right thing. Have a single sbc_dif_verify that handles an sgl (that does NOT copy any data) and a protection information copy routine used by rd_mcp and fileio backend. In the WRITE case, call sbc_dif_verify with cmd->t_prot_sg and then do the copy from it to local sgl (assuming the verify succeeded of course). In the READ case, call sbc_dif_verify with the local sgl and if it succeeds, copy it to t_prot_sg (or not if we are stripping it). (Fix apply breakage from commit c836777 - nab) Tested-by: Akinobu Mita Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 10 ++-- drivers/target/target_core_rd.c | 20 +++++--- drivers/target/target_core_sbc.c | 94 +++------------------------------- drivers/target/target_core_transport.c | 17 +++--- include/target/target_core_backend.h | 8 ++- 5 files changed, 37 insertions(+), 112 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 3f27bfd816d8..deec7560f835 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -643,13 +643,14 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (ret > 0 && cmd->prot_type && dev->dev_attrib.pi_prot_type) { u32 sectors = cmd->data_length / dev->dev_attrib.block_size; - rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, - 0, fd_prot.prot_sg, 0); + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, + 0, fd_prot.prot_sg, 0); if (rc) { kfree(fd_prot.prot_sg); kfree(fd_prot.prot_buf); return rc; } + sbc_dif_copy_prot(cmd, sectors, true, fd_prot.prot_sg, 0); kfree(fd_prot.prot_sg); kfree(fd_prot.prot_buf); } @@ -663,13 +664,14 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (ret < 0) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, - 0, fd_prot.prot_sg, 0); + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, + 0, cmd->t_prot_sg, 0); if (rc) { kfree(fd_prot.prot_sg); kfree(fd_prot.prot_buf); return rc; } + sbc_dif_copy_prot(cmd, sectors, false, fd_prot.prot_sg, 0); } ret = fd_do_rw(cmd, sgl, sgl_nents, 1); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index d16489b6a1a4..55315fd0f5d3 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -403,10 +403,7 @@ static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page return NULL; } -typedef sense_reason_t (*dif_verify)(struct se_cmd *, sector_t, unsigned int, - unsigned int, struct scatterlist *, int); - -static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify) +static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, bool is_read) { struct se_device *se_dev = cmd->se_dev; struct rd_dev *dev = RD_DEV(se_dev); @@ -466,7 +463,16 @@ static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, dif_verify dif_verify) #endif /* !CONFIG_ARCH_HAS_SG_CHAIN */ - rc = dif_verify(cmd, cmd->t_task_lba, sectors, 0, prot_sg, prot_offset); + if (is_read) + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0, + prot_sg, prot_offset); + else + rc = sbc_dif_verify(cmd, cmd->t_task_lba, sectors, 0, + cmd->t_prot_sg, 0); + + if (!rc) + sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, prot_offset); + if (need_to_release) kfree(prot_sg); @@ -512,7 +518,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type && data_direction == DMA_TO_DEVICE) { - rc = rd_do_prot_rw(cmd, sbc_dif_verify_write); + rc = rd_do_prot_rw(cmd, false); if (rc) return rc; } @@ -580,7 +586,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, if (cmd->prot_type && se_dev->dev_attrib.pi_prot_type && data_direction == DMA_FROM_DEVICE) { - rc = rd_do_prot_rw(cmd, sbc_dif_verify_read); + rc = rd_do_prot_rw(cmd, true); if (rc) return rc; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 733824e3825f..ca95fab3521a 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1266,9 +1266,8 @@ check_ref: return 0; } -static void -sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, - struct scatterlist *sg, int sg_off) +void sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, + struct scatterlist *sg, int sg_off) { struct se_device *dev = cmd->se_dev; struct scatterlist *psg; @@ -1309,68 +1308,11 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, kunmap_atomic(paddr); } } +EXPORT_SYMBOL(sbc_dif_copy_prot); sense_reason_t -sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) -{ - struct se_device *dev = cmd->se_dev; - struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg, *psg = cmd->t_prot_sg; - sector_t sector = start; - void *daddr, *paddr; - int i, j, offset = 0; - sense_reason_t rc; - - for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { - daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - - for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { - - if (offset >= psg->length) { - kunmap_atomic(paddr); - psg = sg_next(psg); - paddr = kmap_atomic(sg_page(psg)) + psg->offset; - offset = 0; - } - - sdt = paddr + offset; - - pr_debug("DIF WRITE sector: %llu guard_tag: 0x%04x" - " app_tag: 0x%04x ref_tag: %u\n", - (unsigned long long)sector, sdt->guard_tag, - sdt->app_tag, be32_to_cpu(sdt->ref_tag)); - - rc = sbc_dif_v1_verify(cmd, sdt, daddr + j, sector, - ei_lba); - if (rc) { - kunmap_atomic(paddr); - kunmap_atomic(daddr); - cmd->bad_sector = sector; - return rc; - } - - sector++; - ei_lba++; - offset += sizeof(struct se_dif_v1_tuple); - } - - kunmap_atomic(paddr); - kunmap_atomic(daddr); - } - if (!sg) - return 0; - - sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off); - - return 0; -} -EXPORT_SYMBOL(sbc_dif_verify_write); - -static sense_reason_t -__sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) +sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, + unsigned int ei_lba, struct scatterlist *sg, int sg_off) { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; @@ -1426,28 +1368,4 @@ __sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, return 0; } - -sense_reason_t -sbc_dif_read_strip(struct se_cmd *cmd) -{ - struct se_device *dev = cmd->se_dev; - u32 sectors = cmd->prot_length / dev->prot_length; - - return __sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0, - cmd->t_prot_sg, 0); -} - -sense_reason_t -sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, - unsigned int ei_lba, struct scatterlist *sg, int sg_off) -{ - sense_reason_t rc; - - rc = __sbc_dif_verify_read(cmd, start, sectors, ei_lba, sg, sg_off); - if (rc) - return rc; - - sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off); - return 0; -} -EXPORT_SYMBOL(sbc_dif_verify_read); +EXPORT_SYMBOL(sbc_dif_verify); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 675f2d9d1f14..105f4fd0fad4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1766,8 +1766,8 @@ static int target_write_prot_action(struct se_cmd *cmd) break; sectors = cmd->data_length >> ilog2(cmd->se_dev->dev_attrib.block_size); - cmd->pi_err = sbc_dif_verify_write(cmd, cmd->t_task_lba, - sectors, 0, NULL, 0); + cmd->pi_err = sbc_dif_verify(cmd, cmd->t_task_lba, + sectors, 0, cmd->t_prot_sg, 0); if (unlikely(cmd->pi_err)) { spin_lock_irq(&cmd->t_state_lock); cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT); @@ -1991,16 +1991,17 @@ static void transport_handle_queue_full( static bool target_read_prot_action(struct se_cmd *cmd) { - sense_reason_t rc; - switch (cmd->prot_op) { case TARGET_PROT_DIN_STRIP: if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) { - rc = sbc_dif_read_strip(cmd); - if (rc) { - cmd->pi_err = rc; + u32 sectors = cmd->data_length >> + ilog2(cmd->se_dev->dev_attrib.block_size); + + cmd->pi_err = sbc_dif_verify(cmd, cmd->t_task_lba, + sectors, 0, cmd->t_prot_sg, + 0); + if (cmd->pi_err) return true; - } } break; case TARGET_PROT_DIN_INSERT: diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 5f1225706993..47fafec556f8 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -84,12 +84,10 @@ sense_reason_t sbc_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb), void *priv); void sbc_dif_generate(struct se_cmd *); -sense_reason_t sbc_dif_verify_write(struct se_cmd *, sector_t, unsigned int, +sense_reason_t sbc_dif_verify(struct se_cmd *, sector_t, unsigned int, unsigned int, struct scatterlist *, int); -sense_reason_t sbc_dif_verify_read(struct se_cmd *, sector_t, unsigned int, - unsigned int, struct scatterlist *, int); -sense_reason_t sbc_dif_read_strip(struct se_cmd *); - +void sbc_dif_copy_prot(struct se_cmd *, unsigned int, bool, + struct scatterlist *, int); void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *); int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); -- cgit v1.2.3 From c04a6091c951c88636a569cdd29feb65fb5003af Mon Sep 17 00:00:00 2001 From: Christophe Vu-Brugier Date: Sun, 19 Apr 2015 22:18:33 +0200 Subject: iscsi-target: remove support for obsolete markers Support for markers is currently broken because of a bug in iscsi_enforce_integrity_rules(): the "IFMarkInt_Reject" and "OFMarkInt_Reject" variables are always equal to 1 in iscsi_enforce_integrity_rules(). Moreover, fixed interval markers keys (IFMarker, OFMarker, IFMarkInt and OFMarkInt) are obsolete according to iSCSI RFC 7143: >From http://tools.ietf.org/html/rfc7143#section-13.25: 13.25. Obsoleted Keys This document obsoletes the following keys defined in [RFC3720]: IFMarker, OFMarker, OFMarkInt, and IFMarkInt. However, iSCSI implementations compliant to this document may still receive these obsoleted keys -- i.e., in a responder role -- in a text negotiation. When an IFMarker or OFMarker key is received, a compliant iSCSI implementation SHOULD respond with the constant "Reject" value. The implementation MAY alternatively respond with a "No" value. However, the implementation MUST NOT respond with a "NotUnderstood" value for either of these keys. When an IFMarkInt or OFMarkInt key is received, a compliant iSCSI implementation MUST respond with the constant "Reject" value. The implementation MUST NOT respond with a "NotUnderstood" value for either of these keys. This patch disables markers by turning the corresponding parameters to read-only. The default value of IFMarker and OFMarker remains "No" but the user cannot change it to "Yes" anymore. The new value of IFMarkInt and OFMarkInt is "Reject". (Drop left-over iscsi_get_value_from_number_range + make configfs parameters attrs R/W nops - nab) Signed-off-by: Christophe Vu-Brugier Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 20 +- drivers/target/iscsi/iscsi_target_erl0.c | 53 ----- drivers/target/iscsi/iscsi_target_erl0.h | 1 - drivers/target/iscsi/iscsi_target_login.c | 58 +----- drivers/target/iscsi/iscsi_target_login.h | 1 - drivers/target/iscsi/iscsi_target_parameters.c | 267 +------------------------ drivers/target/iscsi/iscsi_target_parameters.h | 11 +- drivers/target/iscsi/iscsi_target_util.c | 48 ----- drivers/target/iscsi/iscsi_target_util.h | 1 - include/target/iscsi/iscsi_target_core.h | 10 - 10 files changed, 16 insertions(+), 454 deletions(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 74e6114ff18f..21620c751071 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2736,11 +2736,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn) cmd->iov_data_count = iov_count; cmd->tx_size = tx_size; - /* sendpage is preferred but can't insert markers */ - if (!conn->conn_ops->IFMarker) - ret = iscsit_fe_sendpage_sg(cmd, conn); - else - ret = iscsit_send_tx_data(cmd, conn, 0); + ret = iscsit_fe_sendpage_sg(cmd, conn); iscsit_unmap_iovec(cmd); @@ -4072,17 +4068,9 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) " opcode while ERL=0, closing iSCSI connection.\n"); return -1; } - if (!conn->conn_ops->OFMarker) { - pr_err("Unable to recover from unknown" - " opcode while OFMarker=No, closing iSCSI" - " connection.\n"); - return -1; - } - if (iscsit_recover_from_unknown_opcode(conn) < 0) { - pr_err("Unable to recover from unknown" - " opcode, closing iSCSI connection.\n"); - return -1; - } + pr_err("Unable to recover from unknown opcode while OFMarker=No," + " closing iSCSI connection.\n"); + ret = -1; break; } diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 959a14c9dd5d..210f6e4830e3 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -956,56 +956,3 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) iscsit_handle_connection_cleanup(conn); } - -/* - * This is the simple function that makes the magic of - * sync and steering happen in the follow paradoxical order: - * - * 0) Receive conn->of_marker (bytes left until next OFMarker) - * bytes into an offload buffer. When we pass the exact number - * of bytes in conn->of_marker, iscsit_dump_data_payload() and hence - * rx_data() will automatically receive the identical u32 marker - * values and store it in conn->of_marker_offset; - * 1) Now conn->of_marker_offset will contain the offset to the start - * of the next iSCSI PDU. Dump these remaining bytes into another - * offload buffer. - * 2) We are done! - * Next byte in the TCP stream will contain the next iSCSI PDU! - * Cool Huh?! - */ -int iscsit_recover_from_unknown_opcode(struct iscsi_conn *conn) -{ - /* - * Make sure the remaining bytes to next maker is a sane value. - */ - if (conn->of_marker > (conn->conn_ops->OFMarkInt * 4)) { - pr_err("Remaining bytes to OFMarker: %u exceeds" - " OFMarkInt bytes: %u.\n", conn->of_marker, - conn->conn_ops->OFMarkInt * 4); - return -1; - } - - pr_debug("Advancing %u bytes in TCP stream to get to the" - " next OFMarker.\n", conn->of_marker); - - if (iscsit_dump_data_payload(conn, conn->of_marker, 0) < 0) - return -1; - - /* - * Make sure the offset marker we retrived is a valid value. - */ - if (conn->of_marker_offset > (ISCSI_HDR_LEN + (ISCSI_CRC_LEN * 2) + - conn->conn_ops->MaxRecvDataSegmentLength)) { - pr_err("OfMarker offset value: %u exceeds limit.\n", - conn->of_marker_offset); - return -1; - } - - pr_debug("Discarding %u bytes of TCP stream to get to the" - " next iSCSI Opcode.\n", conn->of_marker_offset); - - if (iscsit_dump_data_payload(conn, conn->of_marker_offset, 0) < 0) - return -1; - - return 0; -} diff --git a/drivers/target/iscsi/iscsi_target_erl0.h b/drivers/target/iscsi/iscsi_target_erl0.h index 21acc9a06376..a9e2f9497fb2 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.h +++ b/drivers/target/iscsi/iscsi_target_erl0.h @@ -10,6 +10,5 @@ extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *); extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int); extern void iscsit_fall_back_to_erl0(struct iscsi_session *); extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *); -extern int iscsit_recover_from_unknown_opcode(struct iscsi_conn *); #endif /*** ISCSI_TARGET_ERL0_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 70d799dfab03..3d0fe4ff5590 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -410,8 +410,6 @@ static int iscsi_login_zero_tsih_s2( if (iscsi_change_param_sprintf(conn, "ErrorRecoveryLevel=%d", na->default_erl)) return -1; - if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0) - return -1; /* * Set RDMAExtensions=Yes by default for iSER enabled network portals */ @@ -477,59 +475,6 @@ check_prot: return 0; } -/* - * Remove PSTATE_NEGOTIATE for the four FIM related keys. - * The Initiator node will be able to enable FIM by proposing them itself. - */ -int iscsi_login_disable_FIM_keys( - struct iscsi_param_list *param_list, - struct iscsi_conn *conn) -{ - struct iscsi_param *param; - - param = iscsi_find_param_from_key("OFMarker", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " OFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("OFMarkInt", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("IFMarker", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("IFMarkInt", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - return 0; -} - static int iscsi_login_non_zero_tsih_s1( struct iscsi_conn *conn, unsigned char *buf) @@ -616,7 +561,7 @@ static int iscsi_login_non_zero_tsih_s2( if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt)) return -1; - return iscsi_login_disable_FIM_keys(conn->param_list, conn); + return 0; } int iscsi_login_post_auth_non_zero_tsih( @@ -765,7 +710,6 @@ int iscsi_post_login_handler( conn->conn_state = TARG_CONN_STATE_LOGGED_IN; iscsi_set_connection_parameters(conn->conn_ops, conn->param_list); - iscsit_set_sync_and_steering_values(conn); /* * SCSI Initiator -> SCSI Target Port Mapping */ diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 29d098324b7f..1c7358081533 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h @@ -16,6 +16,5 @@ extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, bool, bool); extern int iscsi_target_login_thread(void *); -extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); #endif /*** ISCSI_TARGET_LOGIN_H ***/ diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index d4f9e9645697..be336df0a887 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -34,13 +34,6 @@ int iscsi_login_rx_data( iov.iov_len = length; iov.iov_base = buf; - /* - * Initial Marker-less Interval. - * Add the values regardless of IFMarker/OFMarker, considering - * it may not be negoitated yet. - */ - conn->of_marker += length; - rx_got = rx_data(conn, &iov, 1, length); if (rx_got != length) { pr_err("rx_data returned %d, expecting %d.\n", @@ -72,13 +65,6 @@ int iscsi_login_tx_data( iov_cnt++; } - /* - * Initial Marker-less Interval. - * Add the values regardless of IFMarker/OFMarker, considering - * it may not be negoitated yet. - */ - conn->if_marker += length; - tx_sent = tx_data(conn, &iov[0], iov_cnt, length); if (tx_sent != length) { pr_err("tx_data returned %d, expecting %d.\n", @@ -97,12 +83,6 @@ void iscsi_dump_conn_ops(struct iscsi_conn_ops *conn_ops) "CRC32C" : "None"); pr_debug("MaxRecvDataSegmentLength: %u\n", conn_ops->MaxRecvDataSegmentLength); - pr_debug("OFMarker: %s\n", (conn_ops->OFMarker) ? "Yes" : "No"); - pr_debug("IFMarker: %s\n", (conn_ops->IFMarker) ? "Yes" : "No"); - if (conn_ops->OFMarker) - pr_debug("OFMarkInt: %u\n", conn_ops->OFMarkInt); - if (conn_ops->IFMarker) - pr_debug("IFMarkInt: %u\n", conn_ops->IFMarkInt); } void iscsi_dump_sess_ops(struct iscsi_sess_ops *sess_ops) @@ -194,10 +174,6 @@ static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *para case TYPERANGE_DIGEST: param->type = TYPE_VALUE_LIST | TYPE_STRING; break; - case TYPERANGE_MARKINT: - param->type = TYPE_NUMBER_RANGE; - param->type_range |= TYPERANGE_1_TO_65535; - break; case TYPERANGE_ISCSINAME: case TYPERANGE_SESSIONTYPE: case TYPERANGE_TARGETADDRESS: @@ -422,13 +398,13 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr) param = iscsi_set_default_param(pl, IFMARKINT, INITIAL_IFMARKINT, PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_MARKINT, USE_INITIAL_ONLY); + TYPERANGE_UTF8, USE_INITIAL_ONLY); if (!param) goto out; param = iscsi_set_default_param(pl, OFMARKINT, INITIAL_OFMARKINT, PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_MARKINT, USE_INITIAL_ONLY); + TYPERANGE_UTF8, USE_INITIAL_ONLY); if (!param) goto out; /* @@ -524,9 +500,9 @@ int iscsi_set_keys_to_negotiate( } else if (!strcmp(param->name, OFMARKER)) { SET_PSTATE_NEGOTIATE(param); } else if (!strcmp(param->name, IFMARKINT)) { - SET_PSTATE_NEGOTIATE(param); + SET_PSTATE_REJECT(param); } else if (!strcmp(param->name, OFMARKINT)) { - SET_PSTATE_NEGOTIATE(param); + SET_PSTATE_REJECT(param); } else if (!strcmp(param->name, RDMAEXTENSIONS)) { if (iser) SET_PSTATE_NEGOTIATE(param); @@ -906,91 +882,6 @@ static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_pt return 0; } -static int iscsi_check_numerical_range_value(struct iscsi_param *param, char *value) -{ - char *left_val_ptr = NULL, *right_val_ptr = NULL; - char *tilde_ptr = NULL; - u32 left_val, right_val, local_left_val; - - if (strcmp(param->name, IFMARKINT) && - strcmp(param->name, OFMARKINT)) { - pr_err("Only parameters \"%s\" or \"%s\" may contain a" - " numerical range value.\n", IFMARKINT, OFMARKINT); - return -1; - } - - if (IS_PSTATE_PROPOSER(param)) - return 0; - - tilde_ptr = strchr(value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range indicator" - " \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = value; - right_val_ptr = value + strlen(left_val_ptr) + 1; - - if (iscsi_check_numerical_value(param, left_val_ptr) < 0) - return -1; - if (iscsi_check_numerical_value(param, right_val_ptr) < 0) - return -1; - - left_val = simple_strtoul(left_val_ptr, NULL, 0); - right_val = simple_strtoul(right_val_ptr, NULL, 0); - *tilde_ptr = '~'; - - if (right_val < left_val) { - pr_err("Numerical range for parameter \"%s\" contains" - " a right value which is less than the left.\n", - param->name); - return -1; - } - - /* - * For now, enforce reasonable defaults for [I,O]FMarkInt. - */ - tilde_ptr = strchr(param->value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range indicator" - " \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = param->value; - right_val_ptr = param->value + strlen(left_val_ptr) + 1; - - local_left_val = simple_strtoul(left_val_ptr, NULL, 0); - *tilde_ptr = '~'; - - if (param->set_param) { - if ((left_val < local_left_val) || - (right_val < local_left_val)) { - pr_err("Passed value range \"%u~%u\" is below" - " minimum left value \"%u\" for key \"%s\"," - " rejecting.\n", left_val, right_val, - local_left_val, param->name); - return -1; - } - } else { - if ((left_val < local_left_val) && - (right_val < local_left_val)) { - pr_err("Received value range \"%u~%u\" is" - " below minimum left value \"%u\" for key" - " \"%s\", rejecting.\n", left_val, right_val, - local_left_val, param->name); - SET_PSTATE_REJECT(param); - if (iscsi_update_param_value(param, REJECT) < 0) - return -1; - } - } - - return 0; -} - static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *value) { if (IS_PSTATE_PROPOSER(param)) @@ -1027,33 +918,6 @@ static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *val return 0; } -/* - * This function is used to pick a value range number, currently just - * returns the lesser of both right values. - */ -static char *iscsi_get_value_from_number_range( - struct iscsi_param *param, - char *value) -{ - char *end_ptr, *tilde_ptr1 = NULL, *tilde_ptr2 = NULL; - u32 acceptor_right_value, proposer_right_value; - - tilde_ptr1 = strchr(value, '~'); - if (!tilde_ptr1) - return NULL; - *tilde_ptr1++ = '\0'; - proposer_right_value = simple_strtoul(tilde_ptr1, &end_ptr, 0); - - tilde_ptr2 = strchr(param->value, '~'); - if (!tilde_ptr2) - return NULL; - *tilde_ptr2++ = '\0'; - acceptor_right_value = simple_strtoul(tilde_ptr2, &end_ptr, 0); - - return (acceptor_right_value >= proposer_right_value) ? - tilde_ptr1 : tilde_ptr2; -} - static char *iscsi_check_valuelist_for_support( struct iscsi_param *param, char *value) @@ -1203,14 +1067,6 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, pr_debug("Updated %s to target MXDSL value: %s\n", param->name, param->value); } - - } else if (IS_TYPE_NUMBER_RANGE(param)) { - negoitated_value = iscsi_get_value_from_number_range( - param, value); - if (!negoitated_value) - return -1; - if (iscsi_update_param_value(param, negoitated_value) < 0) - return -1; } else if (IS_TYPE_VALUE_LIST(param)) { negoitated_value = iscsi_check_valuelist_for_support( param, value); @@ -1239,47 +1095,7 @@ static int iscsi_check_proposer_state(struct iscsi_param *param, char *value) return -1; } - if (IS_TYPE_NUMBER_RANGE(param)) { - u32 left_val = 0, right_val = 0, recieved_value = 0; - char *left_val_ptr = NULL, *right_val_ptr = NULL; - char *tilde_ptr = NULL; - - if (!strcmp(value, IRRELEVANT) || !strcmp(value, REJECT)) { - if (iscsi_update_param_value(param, value) < 0) - return -1; - return 0; - } - - tilde_ptr = strchr(value, '~'); - if (tilde_ptr) { - pr_err("Illegal \"~\" in response for \"%s\".\n", - param->name); - return -1; - } - tilde_ptr = strchr(param->value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range" - " indicator \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = param->value; - right_val_ptr = param->value + strlen(left_val_ptr) + 1; - left_val = simple_strtoul(left_val_ptr, NULL, 0); - right_val = simple_strtoul(right_val_ptr, NULL, 0); - recieved_value = simple_strtoul(value, NULL, 0); - - *tilde_ptr = '~'; - - if ((recieved_value < left_val) || - (recieved_value > right_val)) { - pr_err("Illegal response \"%s=%u\", value must" - " be between %u and %u.\n", param->name, - recieved_value, left_val, right_val); - return -1; - } - } else if (IS_TYPE_VALUE_LIST(param)) { + if (IS_TYPE_VALUE_LIST(param)) { char *comma_ptr = NULL, *tmp_ptr = NULL; comma_ptr = strchr(value, ','); @@ -1361,9 +1177,6 @@ static int iscsi_check_value(struct iscsi_param *param, char *value) } else if (IS_TYPE_NUMBER(param)) { if (iscsi_check_numerical_value(param, value) < 0) return -1; - } else if (IS_TYPE_NUMBER_RANGE(param)) { - if (iscsi_check_numerical_range_value(param, value) < 0) - return -1; } else if (IS_TYPE_STRING(param) || IS_TYPE_VALUE_LIST(param)) { if (iscsi_check_string_or_list_value(param, value) < 0) return -1; @@ -1483,8 +1296,6 @@ static int iscsi_enforce_integrity_rules( char *tmpptr; u8 DataSequenceInOrder = 0; u8 ErrorRecoveryLevel = 0, SessionType = 0; - u8 IFMarker = 0, OFMarker = 0; - u8 IFMarkInt_Reject = 1, OFMarkInt_Reject = 1; u32 FirstBurstLength = 0, MaxBurstLength = 0; struct iscsi_param *param = NULL; @@ -1503,28 +1314,12 @@ static int iscsi_enforce_integrity_rules( if (!strcmp(param->name, MAXBURSTLENGTH)) MaxBurstLength = simple_strtoul(param->value, &tmpptr, 0); - if (!strcmp(param->name, IFMARKER)) - if (!strcmp(param->value, YES)) - IFMarker = 1; - if (!strcmp(param->name, OFMARKER)) - if (!strcmp(param->value, YES)) - OFMarker = 1; - if (!strcmp(param->name, IFMARKINT)) - if (!strcmp(param->value, REJECT)) - IFMarkInt_Reject = 1; - if (!strcmp(param->name, OFMARKINT)) - if (!strcmp(param->value, REJECT)) - OFMarkInt_Reject = 1; } list_for_each_entry(param, ¶m_list->param_list, p_list) { if (!(param->phase & phase)) continue; - if (!SessionType && (!IS_PSTATE_ACCEPTOR(param) && - (strcmp(param->name, IFMARKER) && - strcmp(param->name, OFMARKER) && - strcmp(param->name, IFMARKINT) && - strcmp(param->name, OFMARKINT)))) + if (!SessionType && !IS_PSTATE_ACCEPTOR(param)) continue; if (!strcmp(param->name, MAXOUTSTANDINGR2T) && DataSequenceInOrder && (ErrorRecoveryLevel > 0)) { @@ -1556,38 +1351,6 @@ static int iscsi_enforce_integrity_rules( param->name, param->value); } } - if (!strcmp(param->name, IFMARKER) && IFMarkInt_Reject) { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - IFMarker = 0; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, OFMARKER) && OFMarkInt_Reject) { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - OFMarker = 0; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, IFMARKINT) && !IFMarker) { - if (!strcmp(param->value, REJECT)) - continue; - param->state &= ~PSTATE_NEGOTIATE; - if (iscsi_update_param_value(param, IRRELEVANT) < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, OFMARKINT) && !OFMarker) { - if (!strcmp(param->value, REJECT)) - continue; - param->state &= ~PSTATE_NEGOTIATE; - if (iscsi_update_param_value(param, IRRELEVANT) < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } } return 0; @@ -1824,24 +1587,6 @@ void iscsi_set_connection_parameters( */ pr_debug("MaxRecvDataSegmentLength: %u\n", ops->MaxRecvDataSegmentLength); - } else if (!strcmp(param->name, OFMARKER)) { - ops->OFMarker = !strcmp(param->value, YES); - pr_debug("OFMarker: %s\n", - param->value); - } else if (!strcmp(param->name, IFMARKER)) { - ops->IFMarker = !strcmp(param->value, YES); - pr_debug("IFMarker: %s\n", - param->value); - } else if (!strcmp(param->name, OFMARKINT)) { - ops->OFMarkInt = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("OFMarkInt: %s\n", - param->value); - } else if (!strcmp(param->name, IFMARKINT)) { - ops->IFMarkInt = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("IFMarkInt: %s\n", - param->value); } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { ops->InitiatorRecvDataSegmentLength = simple_strtoul(param->value, &tmpptr, 0); diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index a47046a752aa..a0751e3f0813 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h @@ -138,8 +138,8 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, #define INITIAL_SESSIONTYPE NORMAL #define INITIAL_IFMARKER NO #define INITIAL_OFMARKER NO -#define INITIAL_IFMARKINT "2048~65535" -#define INITIAL_OFMARKINT "2048~65535" +#define INITIAL_IFMARKINT REJECT +#define INITIAL_OFMARKINT REJECT /* * Initial values for iSER parameters following RFC-5046 Section 6 @@ -239,10 +239,9 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, #define TYPERANGE_AUTH 0x0200 #define TYPERANGE_DIGEST 0x0400 #define TYPERANGE_ISCSINAME 0x0800 -#define TYPERANGE_MARKINT 0x1000 -#define TYPERANGE_SESSIONTYPE 0x2000 -#define TYPERANGE_TARGETADDRESS 0x4000 -#define TYPERANGE_UTF8 0x8000 +#define TYPERANGE_SESSIONTYPE 0x1000 +#define TYPERANGE_TARGETADDRESS 0x2000 +#define TYPERANGE_UTF8 0x4000 #define IS_TYPERANGE_0_TO_2(p) ((p)->type_range & TYPERANGE_0_TO_2) #define IS_TYPERANGE_0_TO_3600(p) ((p)->type_range & TYPERANGE_0_TO_3600) diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index b18edda3e8af..37d23e5e08dc 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -809,54 +809,6 @@ void iscsit_inc_session_usage_count(struct iscsi_session *sess) spin_unlock_bh(&sess->session_usage_lock); } -/* - * Setup conn->if_marker and conn->of_marker values based upon - * the initial marker-less interval. (see iSCSI v19 A.2) - */ -int iscsit_set_sync_and_steering_values(struct iscsi_conn *conn) -{ - int login_ifmarker_count = 0, login_ofmarker_count = 0, next_marker = 0; - /* - * IFMarkInt and OFMarkInt are negotiated as 32-bit words. - */ - u32 IFMarkInt = (conn->conn_ops->IFMarkInt * 4); - u32 OFMarkInt = (conn->conn_ops->OFMarkInt * 4); - - if (conn->conn_ops->OFMarker) { - /* - * Account for the first Login Command received not - * via iscsi_recv_msg(). - */ - conn->of_marker += ISCSI_HDR_LEN; - if (conn->of_marker <= OFMarkInt) { - conn->of_marker = (OFMarkInt - conn->of_marker); - } else { - login_ofmarker_count = (conn->of_marker / OFMarkInt); - next_marker = (OFMarkInt * (login_ofmarker_count + 1)) + - (login_ofmarker_count * MARKER_SIZE); - conn->of_marker = (next_marker - conn->of_marker); - } - conn->of_marker_offset = 0; - pr_debug("Setting OFMarker value to %u based on Initial" - " Markerless Interval.\n", conn->of_marker); - } - - if (conn->conn_ops->IFMarker) { - if (conn->if_marker <= IFMarkInt) { - conn->if_marker = (IFMarkInt - conn->if_marker); - } else { - login_ifmarker_count = (conn->if_marker / IFMarkInt); - next_marker = (IFMarkInt * (login_ifmarker_count + 1)) + - (login_ifmarker_count * MARKER_SIZE); - conn->if_marker = (next_marker - conn->if_marker); - } - pr_debug("Setting IFMarker value to %u based on Initial" - " Markerless Interval.\n", conn->if_marker); - } - - return 0; -} - struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid) { struct iscsi_conn *conn; diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 1ab754a671ff..995f1cb29d0e 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -34,7 +34,6 @@ extern void iscsit_free_cmd(struct iscsi_cmd *, bool); extern int iscsit_check_session_usage_count(struct iscsi_session *); extern void iscsit_dec_session_usage_count(struct iscsi_session *); extern void iscsit_inc_session_usage_count(struct iscsi_session *); -extern int iscsit_set_sync_and_steering_values(struct iscsi_conn *); extern struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *, u16); extern struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *, u16); extern void iscsit_check_conn_usage_count(struct iscsi_conn *); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 54e7af301888..39f3d181d39d 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -248,10 +248,6 @@ struct iscsi_conn_ops { u8 DataDigest; /* [0,1] == [None,CRC32C] */ u32 MaxRecvDataSegmentLength; /* [512..2**24-1] */ u32 MaxXmitDataSegmentLength; /* [512..2**24-1] */ - u8 OFMarker; /* [0,1] == [No,Yes] */ - u8 IFMarker; /* [0,1] == [No,Yes] */ - u32 OFMarkInt; /* [1..65535] */ - u32 IFMarkInt; /* [1..65535] */ /* * iSER specific connection parameters */ @@ -532,12 +528,6 @@ struct iscsi_conn { u32 exp_statsn; /* Per connection status sequence number */ u32 stat_sn; - /* IFMarkInt's Current Value */ - u32 if_marker; - /* OFMarkInt's Current Value */ - u32 of_marker; - /* Used for calculating OFMarker offset to next PDU */ - u32 of_marker_offset; #define IPV6_ADDRESS_SPACE 48 unsigned char login_ip[IPV6_ADDRESS_SPACE]; unsigned char local_ip[IPV6_ADDRESS_SPACE]; -- cgit v1.2.3 From 814e5b45182f4aaf6c0b0deac7104bc2cba5109e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 20 Apr 2015 15:00:30 +0200 Subject: target: fix DPO and FUA bit checks Drivers may override the WCE flag, in which case the DPOFUA flag in MODE SENSE might differ from the check used to reject invalid FUA bits in sbc_check_dpofua. Also now that we reject invalid FUA bits early there is no need to duplicate the same buggy check down in the fileio code. As the DPOFUA flag controls th support for FUA bits on read and write commands as well as DPO key off all the checks off a single helper, and deprecate the emulate_dpo and emulate_fua_read attributs. This fixes various failures in the libiscsi testsuite. Personally I'd prefer to also remove the emulate_fua_write attribute as there is no good reason to disable it, but I'll leave that for a separate discussion. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 30 +++++++----------------------- drivers/target/target_core_file.c | 4 +--- drivers/target/target_core_internal.h | 2 ++ drivers/target/target_core_sbc.c | 5 +++-- drivers/target/target_core_spc.c | 12 ++++++++---- drivers/target/target_core_transport.c | 19 +++++++++++++++++++ include/target/target_core_base.h | 6 ------ 7 files changed, 40 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ce5f768181ff..9ee194d1cd4b 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -760,16 +760,8 @@ EXPORT_SYMBOL(se_dev_set_emulate_model_alias); int se_dev_set_emulate_dpo(struct se_device *dev, int flag) { - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (flag) { - pr_err("dpo_emulated not supported\n"); - return -EINVAL; - } - + printk_once(KERN_WARNING + "ignoring deprecated emulate_dpo attribute\n"); return 0; } EXPORT_SYMBOL(se_dev_set_emulate_dpo); @@ -799,16 +791,8 @@ EXPORT_SYMBOL(se_dev_set_emulate_fua_write); int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) { - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (flag) { - pr_err("ua read emulated not supported\n"); - return -EINVAL; - } - + printk_once(KERN_WARNING + "ignoring deprecated emulate_fua_read attribute\n"); return 0; } EXPORT_SYMBOL(se_dev_set_emulate_fua_read); @@ -1513,9 +1497,9 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_attrib.da_dev = dev; dev->dev_attrib.emulate_model_alias = DA_EMULATE_MODEL_ALIAS; - dev->dev_attrib.emulate_dpo = DA_EMULATE_DPO; - dev->dev_attrib.emulate_fua_write = DA_EMULATE_FUA_WRITE; - dev->dev_attrib.emulate_fua_read = DA_EMULATE_FUA_READ; + dev->dev_attrib.emulate_dpo = 1; + dev->dev_attrib.emulate_fua_write = 1; + dev->dev_attrib.emulate_fua_read = 1; dev->dev_attrib.emulate_write_cache = DA_EMULATE_WRITE_CACHE; dev->dev_attrib.emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL; dev->dev_attrib.emulate_tas = DA_EMULATE_TAS; diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index fe6c19c1e001..e865885352da 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -610,9 +610,7 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, * for SCSI WRITEs with Forced Unit Access (FUA) set. * Allow this to happen independent of WCE=0 setting. */ - if (ret > 0 && - dev->dev_attrib.emulate_fua_write > 0 && - (cmd->se_cmd_flags & SCF_FUA)) { + if (ret > 0 && (cmd->se_cmd_flags & SCF_FUA)) { loff_t start = cmd->t_task_lba * dev->dev_attrib.block_size; loff_t end; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 68bd7f5d9f73..75338c348be4 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -81,6 +81,8 @@ int transport_clear_lun_ref(struct se_lun *); void transport_send_task_abort(struct se_cmd *); sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); void target_qf_do_work(struct work_struct *work); +bool target_check_wce(struct se_device *dev); +bool target_check_fua(struct se_device *dev); /* target_core_stat.c */ void target_stat_setup_dev_default_groups(struct se_device *); diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 3df2cd538478..d441975604db 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -738,14 +738,15 @@ static int sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb) { if (cdb[1] & 0x10) { - if (!dev->dev_attrib.emulate_dpo) { + /* see explanation in spc_emulate_modesense */ + if (!target_check_fua(dev)) { pr_err("Got CDB: 0x%02x with DPO bit set, but device" " does not advertise support for DPO\n", cdb[0]); return -EINVAL; } } if (cdb[1] & 0x8) { - if (!dev->dev_attrib.emulate_fua_write || !se_dev_check_wce(dev)) { + if (!target_check_fua(dev)) { pr_err("Got CDB: 0x%02x with FUA bit set, but device" " does not advertise support for FUA write\n", cdb[0]); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 7912aa124385..988c158cf65d 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -481,7 +481,7 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) buf[5] = 0x07; /* If WriteCache emulation is enabled, set V_SUP */ - if (se_dev_check_wce(dev)) + if (target_check_wce(dev)) buf[6] = 0x01; /* If an LBA map is present set R_SUP */ spin_lock(&cmd->se_dev->t10_alua.lba_map_lock); @@ -888,7 +888,7 @@ static int spc_modesense_caching(struct se_cmd *cmd, u8 pc, u8 *p) if (pc == 1) goto out; - if (se_dev_check_wce(dev)) + if (target_check_wce(dev)) p[2] = 0x04; /* Write Cache Enable */ p[12] = 0x20; /* Disabled Read Ahead */ @@ -1000,8 +1000,12 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) spc_modesense_write_protect(&buf[length], type); - if ((se_dev_check_wce(dev)) && - (dev->dev_attrib.emulate_fua_write > 0)) + /* + * SBC only allows us to enable FUA and DPO together. Fortunately + * DPO is explicitly specified as a hint, so a noop is a perfectly + * valid implementation. + */ + if (target_check_fua(dev)) spc_modesense_dpofua(&buf[length], type); ++length; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 105f4fd0fad4..231812d61357 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3075,3 +3075,22 @@ int transport_generic_handle_tmr( return 0; } EXPORT_SYMBOL(transport_generic_handle_tmr); + +bool +target_check_wce(struct se_device *dev) +{ + bool wce = false; + + if (dev->transport->get_write_cache) + wce = dev->transport->get_write_cache(dev); + else if (dev->dev_attrib.emulate_write_cache > 0) + wce = true; + + return wce; +} + +bool +target_check_fua(struct se_device *dev) +{ + return target_check_wce(dev) && dev->dev_attrib.emulate_fua_write > 0; +} diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 480e9f82dfea..7f4c7de3a4ce 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -79,12 +79,6 @@ #define DA_MAX_WRITE_SAME_LEN 0 /* Use a model alias based on the configfs backend device name */ #define DA_EMULATE_MODEL_ALIAS 0 -/* Emulation for Direct Page Out */ -#define DA_EMULATE_DPO 0 -/* Emulation for Forced Unit Access WRITEs */ -#define DA_EMULATE_FUA_WRITE 1 -/* Emulation for Forced Unit Access READs */ -#define DA_EMULATE_FUA_READ 0 /* Emulation for WriteCache and SYNCHRONIZE_CACHE */ #define DA_EMULATE_WRITE_CACHE 0 /* Emulation for UNIT ATTENTION Interlock Control */ -- cgit v1.2.3 From afc16604c06414223478df3e42301ab630b9960a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 27 Apr 2015 13:52:36 +0200 Subject: target: Remove first argument of target_{get,put}_sess_cmd() The first argument of these two functions is always identical to se_cmd->se_sess. Hence remove the first argument. Signed-off-by: Bart Van Assche Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Cc: Andy Grover Cc: Cc: Felipe Balbi Cc: Michael S. Tsirkin Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/isert/ib_isert.c | 6 +++--- drivers/infiniband/ulp/srpt/ib_srpt.c | 10 +++++----- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- drivers/target/iscsi/iscsi_target.c | 15 +++++++-------- drivers/target/iscsi/iscsi_target_configfs.c | 2 +- drivers/target/iscsi/iscsi_target_util.c | 4 ++-- drivers/target/target_core_tmr.c | 2 +- drivers/target/target_core_transport.c | 20 ++++++++++---------- drivers/vhost/scsi.c | 2 +- include/target/target_core_fabric.h | 4 ++-- 10 files changed, 33 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 3f40319a55da..9e3662cce612 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -1332,7 +1332,7 @@ sequence_cmd: if (!rc && dump_payload == false && unsol_data) iscsit_set_unsoliticed_dataout(cmd); else if (dump_payload && imm_data) - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } @@ -1757,7 +1757,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) cmd->se_cmd.t_state == TRANSPORT_WRITE_PENDING) { struct se_cmd *se_cmd = &cmd->se_cmd; - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } } @@ -1930,7 +1930,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc, spin_unlock_bh(&cmd->istate_lock); if (ret) { - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); transport_send_check_condition_and_sense(se_cmd, se_cmd->pi_err, 0); } else { diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 9b84b4c0a000..6fbc7bc824d2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1334,7 +1334,7 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) BUG_ON(ch->sess == NULL); - target_put_sess_cmd(ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); goto out; } @@ -1365,11 +1365,11 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) * not been received in time. */ srpt_unmap_sg_to_ib_sge(ioctx->ch, ioctx); - target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); break; case SRPT_STATE_MGMT_RSP_SENT: srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); - target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); break; default: WARN(1, "Unexpected command state (%d)", state); @@ -1679,7 +1679,7 @@ static int srpt_check_stop_free(struct se_cmd *cmd) struct srpt_send_ioctx *ioctx = container_of(cmd, struct srpt_send_ioctx, cmd); - return target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + return target_put_sess_cmd(&ioctx->cmd); } /** @@ -3074,7 +3074,7 @@ static void srpt_queue_response(struct se_cmd *cmd) ioctx->tag); srpt_unmap_sg_to_ib_sge(ch, ioctx); srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); - target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd); + target_put_sess_cmd(&ioctx->cmd); } } diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 5c9e680aa375..8a6c87547303 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -429,7 +429,7 @@ static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd) cmd->cmd_flags |= BIT_14; } - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); + return target_put_sess_cmd(se_cmd); } /* tcm_qla2xxx_release_cmd - Callback from TCM Core to release underlying diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 21620c751071..866c167c0986 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -715,7 +715,7 @@ static int iscsit_add_reject_from_cmd( */ if (cmd->se_cmd.se_tfo != NULL) { pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n"); - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); } return -1; } @@ -1001,7 +1001,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length, conn->cid); - target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true); + target_get_sess_cmd(&cmd->se_cmd, true); cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, scsilun_to_int(&hdr->lun)); @@ -1067,7 +1067,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) return -1; else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } } @@ -1083,7 +1083,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (!cmd->sense_reason) return 0; - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } @@ -1114,7 +1114,6 @@ static int iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, bool dump_payload) { - struct iscsi_conn *conn = cmd->conn; int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; /* * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. @@ -1141,7 +1140,7 @@ after_immediate_data: rc = iscsit_dump_data_payload(cmd->conn, cmd->first_burst_len, 1); - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return rc; } else if (cmd->unsolicited_data) iscsit_set_unsoliticed_dataout(cmd); @@ -1810,7 +1809,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, conn->sess->se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, cmd->sense_buffer + 2); - target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true); + target_get_sess_cmd(&cmd->se_cmd, true); sess_ref = true; switch (function) { @@ -1952,7 +1951,7 @@ attach: */ if (sess_ref) { pr_debug("Handle TMR, using sess_ref=true check\n"); - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); } iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 469fce44ebad..568e478615a5 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1967,7 +1967,7 @@ static void lio_set_default_node_attributes(struct se_node_acl *se_acl) static int lio_check_stop_free(struct se_cmd *se_cmd) { - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); + return target_put_sess_cmd(se_cmd); } static void lio_release_cmd(struct se_cmd *se_cmd) diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 37d23e5e08dc..c1582e88191e 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -746,7 +746,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); if (!rc && shutdown && se_cmd && se_cmd->se_sess) { __iscsit_free_cmd(cmd, true, shutdown); - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } break; case ISCSI_OP_REJECT: @@ -762,7 +762,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown); if (!rc && shutdown && se_cmd->se_sess) { __iscsit_free_cmd(cmd, true, shutdown); - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } break; } diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 315ec3458eeb..b2e169fba3c6 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -153,7 +153,7 @@ void core_tmr_abort_task( cancel_work_sync(&se_cmd->work); transport_wait_for_tasks(se_cmd); - target_put_sess_cmd(se_sess, se_cmd); + target_put_sess_cmd(se_cmd); transport_cmd_finish_abort(se_cmd, true); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 078d32102cce..9dc1bd5f0e6b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1417,7 +1417,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess * for fabrics using TARGET_SCF_ACK_KREF that expect a second * kref_put() to happen during fabric packet acknowledgement. */ - ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF); if (ret) return ret; /* @@ -1431,7 +1431,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess rc = transport_lookup_cmd_lun(se_cmd, unpacked_lun); if (rc) { transport_send_check_condition_and_sense(se_cmd, rc, 0); - target_put_sess_cmd(se_sess, se_cmd); + target_put_sess_cmd(se_cmd); return 0; } @@ -1582,7 +1582,7 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, se_cmd->se_tmr_req->ref_task_tag = tag; /* See target_submit_cmd for commentary */ - ret = target_get_sess_cmd(se_sess, se_cmd, (flags & TARGET_SCF_ACK_KREF)); + ret = target_get_sess_cmd(se_cmd, flags & TARGET_SCF_ACK_KREF); if (ret) { core_tmr_release_req(se_cmd->se_tmr_req); return ret; @@ -2226,7 +2226,7 @@ static int transport_release_cmd(struct se_cmd *cmd) * If this cmd has been setup with target_get_sess_cmd(), drop * the kref and call ->release_cmd() in kref callback. */ - return target_put_sess_cmd(cmd->se_sess, cmd); + return target_put_sess_cmd(cmd); } /** @@ -2470,13 +2470,12 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) EXPORT_SYMBOL(transport_generic_free_cmd); /* target_get_sess_cmd - Add command to active ->sess_cmd_list - * @se_sess: session to reference * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ -int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, - bool ack_kref) +int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref) { + struct se_session *se_sess = se_cmd->se_sess; unsigned long flags; int ret = 0; @@ -2498,7 +2497,7 @@ out: spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); if (ret && ack_kref) - target_put_sess_cmd(se_sess, se_cmd); + target_put_sess_cmd(se_cmd); return ret; } @@ -2527,11 +2526,12 @@ static void target_release_cmd_kref(struct kref *kref) } /* target_put_sess_cmd - Check for active I/O shutdown via kref_put - * @se_sess: session to reference * @se_cmd: command descriptor to drop */ -int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) +int target_put_sess_cmd(struct se_cmd *se_cmd) { + struct se_session *se_sess = se_cmd->se_sess; + if (!se_sess) { se_cmd->se_tfo->release_cmd(se_cmd); return 1; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index ea32b386797f..636435b41293 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -607,7 +607,7 @@ static void vhost_scsi_free_cmd(struct vhost_scsi_cmd *cmd) static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd) { - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); + return target_put_sess_cmd(se_cmd); } static void diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 0f4dc3768587..24c8d9d0d946 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -155,8 +155,8 @@ bool transport_wait_for_tasks(struct se_cmd *); int transport_check_aborted_status(struct se_cmd *, int); int transport_send_check_condition_and_sense(struct se_cmd *, sense_reason_t, int); -int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); -int target_put_sess_cmd(struct se_session *, struct se_cmd *); +int target_get_sess_cmd(struct se_cmd *, bool); +int target_put_sess_cmd(struct se_cmd *); void target_sess_cmd_list_set_waiting(struct se_session *); void target_wait_for_sess_cmds(struct se_session *); -- cgit v1.2.3 From c7d6a803926bae9bbf4510a18fc8dd8957cc0e01 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:14 +0200 Subject: target: refactor init/drop_nodeacl methods By always allocating and adding, respectively removing and freeing the se_node_acl structure in core code we can remove tons of repeated code in the init_nodeacl and drop_nodeacl routines. Additionally this now respects the get_default_queue_depth method in this code path as well. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 77 ---------------------------- Documentation/target/tcm_mod_builder.txt | 4 +- drivers/infiniband/ulp/srpt/ib_srpt.c | 58 +++++---------------- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 59 +++------------------ drivers/target/iscsi/iscsi_target_configfs.c | 49 ++++-------------- drivers/target/sbp/sbp_target.c | 36 ++----------- drivers/target/target_core_fabric_configfs.c | 22 ++++---- drivers/target/target_core_internal.h | 3 ++ drivers/target/target_core_tpg.c | 46 ++++------------- drivers/target/tcm_fc/tfc_conf.c | 48 +++-------------- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 42 ++------------- drivers/vhost/scsi.c | 39 -------------- drivers/xen/xen-scsiback.c | 6 --- include/target/target_core_fabric.h | 9 +--- 14 files changed, 77 insertions(+), 421 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 3dab9b28f4f0..3e54809b3aa1 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -50,15 +50,6 @@ def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name): buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" buf += "\n" - buf += "struct " + fabric_mod_name + "_nacl {\n" - buf += " /* Binary World Wide unique Port Name for FC Initiator Nport */\n" - buf += " u64 nport_wwpn;\n" - buf += " /* ASCII formatted WWPN for FC Initiator Nport */\n" - buf += " char nport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" - buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" - buf += " struct se_node_acl se_node_acl;\n" - buf += "};\n" - buf += "\n" buf += "struct " + fabric_mod_name + "_tpg {\n" buf += " /* FC lport target portal group tag for TCM */\n" buf += " u16 lport_tpgt;\n" @@ -105,14 +96,6 @@ def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name): buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" buf += "\n" - buf += "struct " + fabric_mod_name + "_nacl {\n" - buf += " /* Binary World Wide unique Port Name for SAS Initiator port */\n" - buf += " u64 iport_wwpn;\n" - buf += " /* ASCII formatted WWPN for Sas Initiator port */\n" - buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" - buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" - buf += " struct se_node_acl se_node_acl;\n" - buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tpg {\n" buf += " /* SAS port target portal group tag for TCM */\n" buf += " u16 tport_tpgt;\n" @@ -158,12 +141,6 @@ def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name): buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n" buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n" buf += "\n" - buf += "struct " + fabric_mod_name + "_nacl {\n" - buf += " /* ASCII formatted InitiatorName */\n" - buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" - buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n" - buf += " struct se_node_acl se_node_acl;\n" - buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tpg {\n" buf += " /* iSCSI target portal group tag for TCM */\n" buf += " u16 tport_tpgt;\n" @@ -239,54 +216,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops;\n\n" - buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct config_group *group,\n" - buf += " const char *name)\n" - buf += "{\n" - buf += " struct se_node_acl *se_nacl, *se_nacl_new;\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl;\n" - - if proto_ident == "FC" or proto_ident == "SAS": - buf += " u64 wwpn = 0;\n" - - buf += " u32 nexus_depth;\n\n" - buf += " /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n" - buf += " return ERR_PTR(-EINVAL); */\n" - buf += " se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n" - buf += " if (!se_nacl_new)\n" - buf += " return ERR_PTR(-ENOMEM);\n" - buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n" - buf += " nexus_depth = 1;\n" - buf += " /*\n" - buf += " * se_nacl_new may be released by core_tpg_add_initiator_node_acl()\n" - buf += " * when converting a NodeACL from demo mode -> explict\n" - buf += " */\n" - buf += " se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,\n" - buf += " name, nexus_depth);\n" - buf += " if (IS_ERR(se_nacl)) {\n" - buf += " " + fabric_mod_name + "_release_fabric_acl(se_tpg, se_nacl_new);\n" - buf += " return se_nacl;\n" - buf += " }\n" - buf += " /*\n" - buf += " * Locate our struct " + fabric_mod_name + "_nacl and set the FC Nport WWPN\n" - buf += " */\n" - buf += " nacl = container_of(se_nacl, struct " + fabric_mod_name + "_nacl, se_node_acl);\n" - - if proto_ident == "FC" or proto_ident == "SAS": - buf += " nacl->" + fabric_mod_init_port + "_wwpn = wwpn;\n" - - buf += " /* " + fabric_mod_name + "_format_wwn(&nacl->" + fabric_mod_init_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n" - buf += " return se_nacl;\n" - buf += "}\n\n" - buf += "static void " + fabric_mod_name + "_drop_nodeacl(struct se_node_acl *se_acl)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n" - buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" - buf += " core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);\n" - buf += " kfree(nacl);\n" - buf += "}\n\n" - buf += "static struct se_portal_group *" + fabric_mod_name + "_make_tpg(\n" buf += " struct se_wwn *wwn,\n" buf += " struct config_group *group,\n" @@ -408,12 +337,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .fabric_drop_wwn = " + fabric_mod_name + "_drop_" + fabric_mod_port + ",\n" buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n" buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n" - buf += " .fabric_post_link = NULL,\n" - buf += " .fabric_pre_unlink = NULL,\n" - buf += " .fabric_make_np = NULL,\n" - buf += " .fabric_drop_np = NULL,\n" - buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n" - buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n" buf += "\n" buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs;\n" buf += "};\n\n" diff --git a/Documentation/target/tcm_mod_builder.txt b/Documentation/target/tcm_mod_builder.txt index 84533d8e747f..ae22f7005540 100644 --- a/Documentation/target/tcm_mod_builder.txt +++ b/Documentation/target/tcm_mod_builder.txt @@ -13,8 +13,8 @@ fabric skeleton, by simply using: This script will create a new drivers/target/$TCM_NEW_MOD/, and will do the following *) Generate new API callers for drivers/target/target_core_fabric_configs.c logic - ->make_nodeacl(), ->drop_nodeacl(), ->make_tpg(), ->drop_tpg() - ->make_wwn(), ->drop_wwn(). These are created into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c + ->make_tpg(), ->drop_tpg(), ->make_wwn(), ->drop_wwn(). These are created + into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c *) Generate basic infrastructure for loading/unloading LKMs and TCM/ConfigFS fabric module using a skeleton struct target_core_fabric_ops API template. *) Based on user defined T10 Proto_Ident for the new fabric module being built, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 8198d4cb0694..c1f3aa52f42b 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3592,40 +3592,19 @@ out: * configfs callback function invoked for * mkdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id */ -static struct se_node_acl *srpt_make_nodeacl(struct se_portal_group *tpg, - struct config_group *group, - const char *name) +static int srpt_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); - struct se_node_acl *se_nacl, *se_nacl_new; - struct srpt_node_acl *nacl; - int ret = 0; - u32 nexus_depth = 1; + struct srpt_port *sport = + container_of(se_nacl->se_tpg, struct srpt_port, port_tpg_1); + struct srpt_node_acl *nacl = + container_of(se_nacl, struct srpt_node_acl, nacl); u8 i_port_id[16]; if (srpt_parse_i_port_id(i_port_id, name) < 0) { pr_err("invalid initiator port ID %s\n", name); - ret = -EINVAL; - goto err; + return -EINVAL; } - se_nacl_new = srpt_alloc_fabric_acl(tpg); - if (!se_nacl_new) { - ret = -ENOMEM; - goto err; - } - /* - * nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a node ACL from demo mode to explict - */ - se_nacl = core_tpg_add_initiator_node_acl(tpg, se_nacl_new, name, - nexus_depth); - if (IS_ERR(se_nacl)) { - ret = PTR_ERR(se_nacl); - goto err; - } - /* Locate our struct srpt_node_acl and set sdev and i_port_id. */ - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); memcpy(&nacl->i_port_id[0], &i_port_id[0], 16); nacl->sport = sport; @@ -3633,29 +3612,22 @@ static struct se_node_acl *srpt_make_nodeacl(struct se_portal_group *tpg, list_add_tail(&nacl->list, &sport->port_acl_list); spin_unlock_irq(&sport->port_acl_lock); - return se_nacl; -err: - return ERR_PTR(ret); + return 0; } /* * configfs callback function invoked for * rmdir /sys/kernel/config/target/$driver/$port/$tpg/acls/$i_port_id */ -static void srpt_drop_nodeacl(struct se_node_acl *se_nacl) +static void srpt_cleanup_nodeacl(struct se_node_acl *se_nacl) { - struct srpt_node_acl *nacl; - struct srpt_device *sdev; - struct srpt_port *sport; + struct srpt_node_acl *nacl = + container_of(se_nacl, struct srpt_node_acl, nacl); + struct srpt_port *sport = nacl->sport; - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); - sport = nacl->sport; - sdev = sport->sdev; spin_lock_irq(&sport->port_acl_lock); list_del(&nacl->list); spin_unlock_irq(&sport->port_acl_lock); - core_tpg_del_initiator_node_acl(&sport->port_tpg_1, se_nacl, 1); - srpt_release_fabric_acl(NULL, se_nacl); } static ssize_t srpt_tpg_attrib_show_srp_max_rdma_size( @@ -3948,12 +3920,8 @@ static const struct target_core_fabric_ops srpt_template = { .fabric_drop_wwn = srpt_drop_tport, .fabric_make_tpg = srpt_make_tpg, .fabric_drop_tpg = srpt_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = srpt_make_nodeacl, - .fabric_drop_nodeacl = srpt_drop_nodeacl, + .fabric_init_nodeacl = srpt_init_nodeacl, + .fabric_cleanup_nodeacl = srpt_cleanup_nodeacl, .tfc_wwn_attrs = srpt_wwn_attrs, .tfc_tpg_base_attrs = srpt_tpg_attrs, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 5d69abcf9ed0..a7ab689f5524 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -847,53 +847,20 @@ static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess) target_sess_cmd_list_set_waiting(sess->se_sess); } -static struct se_node_acl *tcm_qla2xxx_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl, + const char *name) { - struct se_node_acl *se_nacl, *se_nacl_new; - struct tcm_qla2xxx_nacl *nacl; + struct tcm_qla2xxx_nacl *nacl = + container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); u64 wwnn; - u32 qla2xxx_nexus_depth; if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) - return ERR_PTR(-EINVAL); - - se_nacl_new = tcm_qla2xxx_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); -/* #warning FIXME: Hardcoded qla2xxx_nexus depth in tcm_qla2xxx_make_nodeacl */ - qla2xxx_nexus_depth = 1; + return -EINVAL; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, qla2xxx_nexus_depth); - if (IS_ERR(se_nacl)) { - tcm_qla2xxx_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - /* - * Locate our struct tcm_qla2xxx_nacl and set the FC Nport WWPN - */ - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); nacl->nport_wwnn = wwnn; tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); - return se_nacl; -} - -static void tcm_qla2xxx_drop_nodeacl(struct se_node_acl *se_acl) -{ - struct se_portal_group *se_tpg = se_acl->se_tpg; - struct tcm_qla2xxx_nacl *nacl = container_of(se_acl, - struct tcm_qla2xxx_nacl, se_node_acl); - - core_tpg_del_initiator_node_acl(se_tpg, se_acl, 1); - kfree(nacl); + return 0; } /* Start items for tcm_qla2xxx_tpg_attrib_cit */ @@ -2024,12 +1991,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .fabric_drop_wwn = tcm_qla2xxx_drop_lport, .fabric_make_tpg = tcm_qla2xxx_make_tpg, .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, - .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + .fabric_init_nodeacl = tcm_qla2xxx_init_nodeacl, .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, .tfc_tpg_base_attrs = tcm_qla2xxx_tpg_attrs, @@ -2079,12 +2041,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .fabric_drop_wwn = tcm_qla2xxx_npiv_drop_lport, .fabric_make_tpg = tcm_qla2xxx_npiv_make_tpg, .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, - .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, + .fabric_init_nodeacl = tcm_qla2xxx_init_nodeacl, .tfc_wwn_attrs = tcm_qla2xxx_wwn_attrs, .tfc_tpg_base_attrs = tcm_qla2xxx_npiv_tpg_attrs, diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 568e478615a5..7d9ff8cbbb5d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -874,43 +874,19 @@ static struct se_node_acl *lio_tpg_alloc_fabric_acl( return &acl->se_node_acl; } -static struct se_node_acl *lio_target_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int lio_target_init_nodeacl(struct se_node_acl *se_nacl, + const char *name) { - struct config_group *stats_cg; - struct iscsi_node_acl *acl; - struct se_node_acl *se_nacl_new, *se_nacl; - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - u32 cmdsn_depth; - - se_nacl_new = lio_tpg_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - cmdsn_depth = tpg->tpg_attrib.default_cmdsn_depth; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NdoeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, cmdsn_depth); - if (IS_ERR(se_nacl)) - return se_nacl; - - acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); - stats_cg = &se_nacl->acl_fabric_stat_group; + struct iscsi_node_acl *acl = + container_of(se_nacl, struct iscsi_node_acl, se_node_acl); + struct config_group *stats_cg = &se_nacl->acl_fabric_stat_group; stats_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!stats_cg->default_groups) { pr_err("Unable to allocate memory for" " stats_cg->default_groups\n"); - core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1); - kfree(acl); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } stats_cg->default_groups[0] = &acl->node_stat_grps.iscsi_sess_stats_group; @@ -918,13 +894,11 @@ static struct se_node_acl *lio_target_make_nodeacl( config_group_init_type_name(&acl->node_stat_grps.iscsi_sess_stats_group, "iscsi_sess_stats", &iscsi_stat_sess_cit); - return se_nacl; + return 0; } -static void lio_target_drop_nodeacl( - struct se_node_acl *se_nacl) +static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl) { - struct se_portal_group *se_tpg = se_nacl->se_tpg; struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl, se_node_acl); struct config_item *df_item; @@ -938,9 +912,6 @@ static void lio_target_drop_nodeacl( config_item_put(df_item); } kfree(stats_cg->default_groups); - - core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1); - kfree(acl); } /* End items for lio_target_acl_cit */ @@ -2020,8 +1991,8 @@ const struct target_core_fabric_ops iscsi_ops = { .fabric_drop_tpg = lio_target_tiqn_deltpg, .fabric_make_np = lio_target_call_addnptotpg, .fabric_drop_np = lio_target_call_delnpfromtpg, - .fabric_make_nodeacl = lio_target_make_nodeacl, - .fabric_drop_nodeacl = lio_target_drop_nodeacl, + .fabric_init_nodeacl = lio_target_init_nodeacl, + .fabric_cleanup_nodeacl = lio_target_cleanup_nodeacl, .tfc_discovery_attrs = lio_target_discovery_auth_attrs, .tfc_wwn_attrs = lio_target_wwn_attrs, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 0d70d4f58e43..3a47fe46fbca 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2085,40 +2085,13 @@ static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn) return snprintf(buf, len, "%016llx", wwn); } -static struct se_node_acl *sbp_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int sbp_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - struct se_node_acl *se_nacl, *se_nacl_new; u64 guid = 0; - u32 nexus_depth = 1; if (sbp_parse_wwn(name, &guid) < 0) - return ERR_PTR(-EINVAL); - - se_nacl_new = sbp_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, nexus_depth); - if (IS_ERR(se_nacl)) { - sbp_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - - return se_nacl; -} - -static void sbp_drop_nodeacl(struct se_node_acl *se_acl) -{ - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(se_acl); + return -EINVAL; + return 0; } static int sbp_post_link_lun( @@ -2518,8 +2491,7 @@ static const struct target_core_fabric_ops sbp_ops = { .fabric_pre_unlink = sbp_pre_unlink_lun, .fabric_make_np = NULL, .fabric_drop_np = NULL, - .fabric_make_nodeacl = sbp_make_nodeacl, - .fabric_drop_nodeacl = sbp_drop_nodeacl, + .fabric_init_nodeacl = sbp_init_nodeacl, .tfc_wwn_attrs = sbp_wwn_attrs, .tfc_tpg_base_attrs = sbp_tpg_base_attrs, diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 1f7886bb16bf..f4d9467c3e14 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -458,10 +458,11 @@ static void target_fabric_nacl_base_release(struct config_item *item) { struct se_node_acl *se_nacl = container_of(to_config_group(item), struct se_node_acl, acl_group); - struct se_portal_group *se_tpg = se_nacl->se_tpg; - struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct target_fabric_configfs *tf = se_nacl->se_tpg->se_tpg_wwn->wwn_tf; - tf->tf_ops.fabric_drop_nodeacl(se_nacl); + if (tf->tf_ops.fabric_cleanup_nodeacl) + tf->tf_ops.fabric_cleanup_nodeacl(se_nacl); + core_tpg_del_initiator_node_acl(se_nacl); } static struct configfs_item_operations target_fabric_nacl_base_item_ops = { @@ -501,15 +502,18 @@ static struct config_group *target_fabric_make_nodeacl( struct se_node_acl *se_nacl; struct config_group *nacl_cg; - if (!tf->tf_ops.fabric_make_nodeacl) { - pr_err("tf->tf_ops.fabric_make_nodeacl is NULL\n"); - return ERR_PTR(-ENOSYS); - } - - se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name); + se_nacl = core_tpg_add_initiator_node_acl(se_tpg, name); if (IS_ERR(se_nacl)) return ERR_CAST(se_nacl); + if (tf->tf_ops.fabric_init_nodeacl) { + int ret = tf->tf_ops.fabric_init_nodeacl(se_nacl, name); + if (ret) { + core_tpg_del_initiator_node_acl(se_nacl); + return ERR_PTR(ret); + } + } + nacl_cg = &se_nacl->acl_group; nacl_cg->default_groups = se_nacl->acl_default_groups; nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 75338c348be4..058ca71cda81 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -59,6 +59,9 @@ struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32); int core_tpg_add_lun(struct se_portal_group *, struct se_lun *, u32, struct se_device *); void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *); +struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *tpg, + const char *initiatorname); +void core_tpg_del_initiator_node_acl(struct se_node_acl *acl); /* target_core_transport.c */ extern struct kmem_cache *se_tmr_req_cache; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5a9deb2b24af..78dd53ada04a 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -353,17 +353,11 @@ void core_tpg_clear_object_luns(struct se_portal_group *tpg) } EXPORT_SYMBOL(core_tpg_clear_object_luns); -/* core_tpg_add_initiator_node_acl(): - * - * - */ struct se_node_acl *core_tpg_add_initiator_node_acl( struct se_portal_group *tpg, - struct se_node_acl *se_nacl, - const char *initiatorname, - u32 queue_depth) + const char *initiatorname) { - struct se_node_acl *acl = NULL; + struct se_node_acl *acl; spin_lock_irq(&tpg->acl_node_lock); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); @@ -374,14 +368,6 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname); spin_unlock_irq(&tpg->acl_node_lock); - /* - * Release the locally allocated struct se_node_acl - * because * core_tpg_add_initiator_node_acl() returned - * a pointer to an existing demo mode node ACL. - */ - if (se_nacl) - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, - se_nacl); goto done; } @@ -394,16 +380,11 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( } spin_unlock_irq(&tpg->acl_node_lock); - if (!se_nacl) { + acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); + if (!acl) { pr_err("struct se_node_acl pointer is NULL\n"); return ERR_PTR(-EINVAL); } - /* - * For v4.x logic the se_node_acl_s is hanging off a fabric - * dependent structure allocated via - * struct target_core_fabric_ops->fabric_make_nodeacl() - */ - acl = se_nacl; INIT_LIST_HEAD(&acl->acl_list); INIT_LIST_HEAD(&acl->acl_sess_list); @@ -412,7 +393,10 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); atomic_set(&acl->acl_pr_ref_count, 0); - acl->queue_depth = queue_depth; + if (tpg->se_tpg_tfo->tpg_get_default_depth) + acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); + else + acl->queue_depth = 1; snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); acl->se_tpg = tpg; acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX); @@ -443,17 +427,10 @@ done: return acl; } -EXPORT_SYMBOL(core_tpg_add_initiator_node_acl); -/* core_tpg_del_initiator_node_acl(): - * - * - */ -int core_tpg_del_initiator_node_acl( - struct se_portal_group *tpg, - struct se_node_acl *acl, - int force) +void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) { + struct se_portal_group *tpg = acl->se_tpg; LIST_HEAD(sess_list); struct se_session *sess, *sess_tmp; unsigned long flags; @@ -505,9 +482,8 @@ int core_tpg_del_initiator_node_acl( tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, tpg->se_tpg_tfo->get_fabric_name(), acl->initiatorname); - return 0; + tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); } -EXPORT_SYMBOL(core_tpg_del_initiator_node_acl); /* core_tpg_set_initiator_node_queue_depth(): * diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 46b4387460e5..e179fdf76ddb 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -198,48 +198,17 @@ static struct configfs_attribute *ft_nacl_base_attrs[] = { * Add ACL for an initiator. The ACL is named arbitrarily. * The port_name and/or node_name are attributes. */ -static struct se_node_acl *ft_add_acl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) +static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name) { - struct ft_node_acl *acl; - struct ft_tpg *tpg; + struct ft_node_acl *acl = + container_of(nacl, struct ft_node_acl, se_node_acl); u64 wwpn; - u32 q_depth; - - pr_debug("add acl %s\n", name); - tpg = container_of(se_tpg, struct ft_tpg, se_tpg); if (ft_parse_wwn(name, &wwpn, 1) < 0) - return ERR_PTR(-EINVAL); + return -EINVAL; - acl = kzalloc(sizeof(struct ft_node_acl), GFP_KERNEL); - if (!acl) - return ERR_PTR(-ENOMEM); acl->node_auth.port_name = wwpn; - - q_depth = 32; /* XXX bogus default - get from tpg? */ - return core_tpg_add_initiator_node_acl(&tpg->se_tpg, - &acl->se_node_acl, name, q_depth); -} - -static void ft_del_acl(struct se_node_acl *se_acl) -{ - struct se_portal_group *se_tpg = se_acl->se_tpg; - struct ft_tpg *tpg; - struct ft_node_acl *acl = container_of(se_acl, - struct ft_node_acl, se_node_acl); - - pr_debug("del acl %s\n", - config_item_name(&se_acl->acl_group.cg_item)); - - tpg = container_of(se_tpg, struct ft_tpg, se_tpg); - pr_debug("del acl %p se_acl %p tpg %p se_tpg %p\n", - acl, se_acl, tpg, &tpg->se_tpg); - - core_tpg_del_initiator_node_acl(&tpg->se_tpg, se_acl, 1); - kfree(acl); + return 0; } struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) @@ -542,12 +511,7 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .fabric_drop_wwn = &ft_del_wwn, .fabric_make_tpg = &ft_add_tpg, .fabric_drop_tpg = &ft_del_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = &ft_add_acl, - .fabric_drop_nodeacl = &ft_del_acl, + .fabric_init_nodeacl = &ft_init_nodeacl, .tfc_wwn_attrs = ft_wwn_attrs, .tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index b7a78f72fb0e..fccb0ccb355a 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1476,40 +1476,11 @@ static const char *usbg_check_wwn(const char *name) return n; } -static struct se_node_acl *usbg_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct se_node_acl *se_nacl, *se_nacl_new; - u32 nexus_depth; - const char *wnn_name; - - wnn_name = usbg_check_wwn(name); - if (!wnn_name) - return ERR_PTR(-EINVAL); - se_nacl_new = usbg_alloc_fabric_acl(se_tpg); - if (!(se_nacl_new)) - return ERR_PTR(-ENOMEM); - - nexus_depth = 1; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, nexus_depth); - if (IS_ERR(se_nacl)) { - usbg_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - return se_nacl; -} - -static void usbg_drop_nodeacl(struct se_node_acl *se_acl) +static int usbg_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(se_acl); + if (!usbg_check_wwn(name)) + return -EINVAL; + return 0; } struct usbg_tpg *the_only_tpg_I_currently_have; @@ -1879,10 +1850,7 @@ static const struct target_core_fabric_ops usbg_ops = { .fabric_drop_tpg = usbg_drop_tpg, .fabric_post_link = usbg_port_link, .fabric_pre_unlink = usbg_port_unlink, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = usbg_make_nodeacl, - .fabric_drop_nodeacl = usbg_drop_nodeacl, + .fabric_init_nodeacl = usbg_init_nodeacl, .tfc_wwn_attrs = usbg_wwn_attrs, .tfc_tpg_base_attrs = usbg_base_attrs, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index fb8a93d5bfba..8faa7f4abf23 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1798,41 +1798,6 @@ static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg, mutex_unlock(&vhost_scsi_mutex); } -static struct se_node_acl * -vhost_scsi_make_nodeacl(struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct se_node_acl *se_nacl, *se_nacl_new; - u32 nexus_depth; - - /* vhost_scsi_parse_wwn(name, &wwpn, 1) < 0) - return ERR_PTR(-EINVAL); */ - se_nacl_new = vhost_scsi_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - nexus_depth = 1; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, nexus_depth); - if (IS_ERR(se_nacl)) { - vhost_scsi_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - - return se_nacl; -} - -static void vhost_scsi_drop_nodeacl(struct se_node_acl *se_acl) -{ - core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); - kfree(se_acl); -} - static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus, struct se_session *se_sess) { @@ -2330,10 +2295,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .fabric_drop_tpg = vhost_scsi_drop_tpg, .fabric_post_link = vhost_scsi_port_link, .fabric_pre_unlink = vhost_scsi_port_unlink, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = vhost_scsi_make_nodeacl, - .fabric_drop_nodeacl = vhost_scsi_drop_nodeacl, .tfc_wwn_attrs = vhost_scsi_wwn_attrs, .tfc_tpg_base_attrs = vhost_scsi_tpg_attrs, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index c0d4aee0eeb5..8a130ab71733 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1980,12 +1980,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .fabric_drop_tpg = scsiback_drop_tpg, .fabric_post_link = scsiback_port_link, .fabric_pre_unlink = scsiback_port_unlink, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, -#if 0 - .fabric_make_nodeacl = scsiback_make_nodeacl, - .fabric_drop_nodeacl = scsiback_drop_nodeacl, -#endif .tfc_wwn_attrs = scsiback_wwn_attrs, .tfc_tpg_base_attrs = scsiback_tpg_attrs, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 24c8d9d0d946..8b570c49f4d1 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -88,9 +88,8 @@ struct target_core_fabric_ops { struct se_tpg_np *(*fabric_make_np)(struct se_portal_group *, struct config_group *, const char *); void (*fabric_drop_np)(struct se_tpg_np *); - struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *, - struct config_group *, const char *); - void (*fabric_drop_nodeacl)(struct se_node_acl *); + int (*fabric_init_nodeacl)(struct se_node_acl *, const char *); + void (*fabric_cleanup_nodeacl)(struct se_node_acl *); struct configfs_attribute **tfc_discovery_attrs; struct configfs_attribute **tfc_wwn_attrs; @@ -174,10 +173,6 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, unsigned char *); void core_tpg_clear_object_luns(struct se_portal_group *); -struct se_node_acl *core_tpg_add_initiator_node_acl(struct se_portal_group *, - struct se_node_acl *, const char *, u32); -int core_tpg_del_initiator_node_acl(struct se_portal_group *, - struct se_node_acl *, int); int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, -- cgit v1.2.3 From 144bc4c2a42a0f42a32c106d53f5bf2724fbf098 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 13 Apr 2015 19:51:16 +0200 Subject: target: move node ACL allocation to core code Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 27 -------------------------- drivers/infiniband/ulp/srpt/ib_srpt.c | 25 +----------------------- drivers/infiniband/ulp/srpt/ib_srpt.h | 4 ++-- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 29 ++-------------------------- drivers/scsi/qla2xxx/tcm_qla2xxx.h | 4 ++-- drivers/target/iscsi/iscsi_target_configfs.c | 26 +------------------------ drivers/target/loopback/tcm_loop.c | 15 -------------- drivers/target/sbp/sbp_target.c | 14 -------------- drivers/target/target_core_configfs.c | 8 -------- drivers/target/target_core_tpg.c | 9 +++++---- drivers/target/target_core_transport.c | 2 +- drivers/target/tcm_fc/tcm_fc.h | 2 +- drivers/target/tcm_fc/tfc_conf.c | 26 +------------------------ drivers/usb/gadget/legacy/tcm_usb_gadget.c | 14 -------------- drivers/vhost/scsi.c | 15 -------------- drivers/xen/xen-scsiback.c | 15 -------------- include/target/iscsi/iscsi_target_core.h | 2 +- include/target/target_core_fabric.h | 5 +---- 18 files changed, 18 insertions(+), 224 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 3e54809b3aa1..07e7ef3d7429 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -313,8 +313,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n" buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n" buf += " .tpg_check_prod_mode_write_protect = " + fabric_mod_name + "_check_false,\n" - buf += " .tpg_alloc_fabric_acl = " + fabric_mod_name + "_alloc_fabric_acl,\n" - buf += " .tpg_release_fabric_acl = " + fabric_mod_name + "_release_fabric_acl,\n" buf += " .tpg_get_inst_index = " + fabric_mod_name + "_tpg_get_inst_index,\n" buf += " .release_cmd = " + fabric_mod_name + "_release_cmd,\n" buf += " .shutdown_session = " + fabric_mod_name + "_shutdown_session,\n" @@ -624,31 +622,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n" bufi += " const char *, u32 *, char **);\n" - if re.search('alloc_fabric_acl\)\(', fo): - buf += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *se_tpg)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl;\n\n" - buf += " nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n" - buf += " if (!nacl) {\n" - buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_nacl\\n\");\n" - buf += " return NULL;\n" - buf += " }\n\n" - buf += " return &nacl->se_node_acl;\n" - buf += "}\n\n" - bufi += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *);\n" - - if re.search('release_fabric_acl\)\(', fo): - buf += "void " + fabric_mod_name + "_release_fabric_acl(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct se_node_acl *se_nacl)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_nacl,\n" - buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n" - buf += " kfree(nacl);\n" - buf += "}\n\n" - bufi += "void " + fabric_mod_name + "_release_fabric_acl(struct se_portal_group *,\n" - bufi += " struct se_node_acl *);\n" - if re.search('tpg_get_inst_index\)\(', fo): buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index c1f3aa52f42b..38e51f4a17de 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3447,28 +3447,6 @@ static char *srpt_parse_pr_out_transport_id(struct se_portal_group *se_tpg, return (char *)tr_id->i_port_id; } -static struct se_node_acl *srpt_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - struct srpt_node_acl *nacl; - - nacl = kzalloc(sizeof(struct srpt_node_acl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to allocate struct srpt_node_acl\n"); - return NULL; - } - - return &nacl->nacl; -} - -static void srpt_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - struct srpt_node_acl *nacl; - - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); - kfree(nacl); -} - static u32 srpt_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -3883,6 +3861,7 @@ static struct configfs_attribute *srpt_wwn_attrs[] = { static const struct target_core_fabric_ops srpt_template = { .module = THIS_MODULE, .name = "srpt", + .node_acl_size = sizeof(struct srpt_node_acl), .get_fabric_name = srpt_get_fabric_name, .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, @@ -3894,8 +3873,6 @@ static const struct target_core_fabric_ops srpt_template = { .tpg_check_demo_mode_cache = srpt_check_true, .tpg_check_demo_mode_write_protect = srpt_check_true, .tpg_check_prod_mode_write_protect = srpt_check_false, - .tpg_alloc_fabric_acl = srpt_alloc_fabric_acl, - .tpg_release_fabric_acl = srpt_release_fabric_acl, .tpg_get_inst_index = srpt_tpg_get_inst_index, .release_cmd = srpt_release_cmd, .check_stop_free = srpt_check_stop_free, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 3dae156905de..355f6f5ce8b2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -410,15 +410,15 @@ struct srpt_device { /** * struct srpt_node_acl - Per-initiator ACL data (managed via configfs). + * @nacl: Target core node ACL information. * @i_port_id: 128-bit SRP initiator port ID. * @sport: port information. - * @nacl: Target core node ACL information. * @list: Element of the per-HCA ACL list. */ struct srpt_node_acl { + struct se_node_acl nacl; u8 i_port_id[16]; struct srpt_port *sport; - struct se_node_acl nacl; struct list_head list; }; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index a7ab689f5524..cb376e5198d0 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -338,29 +338,6 @@ static int tcm_qla2xxx_check_prot_fabric_only(struct se_portal_group *se_tpg) return tpg->tpg_attrib.fabric_prot_type; } -static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_nacl *nacl; - - nacl = kzalloc(sizeof(struct tcm_qla2xxx_nacl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to allocate struct tcm_qla2xxx_nacl\n"); - return NULL; - } - - return &nacl->se_node_acl; -} - -static void tcm_qla2xxx_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl, - struct tcm_qla2xxx_nacl, se_node_acl); - kfree(nacl); -} - static u32 tcm_qla2xxx_tpg_get_inst_index(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -1949,6 +1926,7 @@ static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .module = THIS_MODULE, .name = "qla2xxx", + .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -1964,8 +1942,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { tcm_qla2xxx_check_prod_write_protect, .tpg_check_prot_fabric_only = tcm_qla2xxx_check_prot_fabric_only, .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only, - .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, @@ -2001,6 +1977,7 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .module = THIS_MODULE, .name = "qla2xxx_npiv", + .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, @@ -2014,8 +1991,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_prod_write_protect, .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only, - .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 23295115c9fc..3d805a07061c 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -13,6 +13,8 @@ #include "qla_target.h" struct tcm_qla2xxx_nacl { + struct se_node_acl se_node_acl; + /* From libfc struct fc_rport->port_id */ u32 nport_id; /* Binary World Wide unique Node Name for remote FC Initiator Nport */ @@ -23,8 +25,6 @@ struct tcm_qla2xxx_nacl { struct qla_tgt_sess *qla_tgt_sess; /* Pointer to TCM FC nexus */ struct se_session *nport_nexus; - /* Returned by tcm_qla2xxx_make_nodeacl() */ - struct se_node_acl se_node_acl; }; struct tcm_qla2xxx_tpg_attrib { diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 7d9ff8cbbb5d..643024c1ee8d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -860,20 +860,6 @@ static struct configfs_attribute *lio_target_initiator_attrs[] = { NULL, }; -static struct se_node_acl *lio_tpg_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - struct iscsi_node_acl *acl; - - acl = kzalloc(sizeof(struct iscsi_node_acl), GFP_KERNEL); - if (!acl) { - pr_err("Unable to allocate memory for struct iscsi_node_acl\n"); - return NULL; - } - - return &acl->se_node_acl; -} - static int lio_target_init_nodeacl(struct se_node_acl *se_nacl, const char *name) { @@ -1868,15 +1854,6 @@ static int lio_tpg_check_prot_fabric_only( return tpg->tpg_attrib.fabric_prot_type; } -static void lio_tpg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_acl) -{ - struct iscsi_node_acl *acl = container_of(se_acl, - struct iscsi_node_acl, se_node_acl); - kfree(acl); -} - /* * Called with spin_lock_bh(struct se_portal_group->session_lock) held.. * @@ -1952,6 +1929,7 @@ static void lio_release_cmd(struct se_cmd *se_cmd) const struct target_core_fabric_ops iscsi_ops = { .module = THIS_MODULE, .name = "iscsi", + .node_acl_size = sizeof(struct iscsi_node_acl), .get_fabric_name = iscsi_get_fabric_name, .get_fabric_proto_ident = iscsi_get_fabric_proto_ident, .tpg_get_wwn = lio_tpg_get_endpoint_wwn, @@ -1967,8 +1945,6 @@ const struct target_core_fabric_ops iscsi_ops = { .tpg_check_prod_mode_write_protect = lio_tpg_check_prod_mode_write_protect, .tpg_check_prot_fabric_only = &lio_tpg_check_prot_fabric_only, - .tpg_alloc_fabric_acl = lio_tpg_alloc_fabric_acl, - .tpg_release_fabric_acl = lio_tpg_release_fabric_acl, .tpg_get_inst_index = lio_tpg_get_inst_index, .check_stop_free = lio_check_stop_free, .release_cmd = lio_release_cmd, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 12b85b03e9ae..5a71c9f2ee66 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -698,19 +698,6 @@ static int tcm_loop_check_prot_fabric_only(struct se_portal_group *se_tpg) return tl_tpg->tl_fabric_prot_type; } -static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void tcm_loop_tpg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1383,8 +1370,6 @@ static const struct target_core_fabric_ops loop_ops = { .tpg_check_prod_mode_write_protect = tcm_loop_check_prod_mode_write_protect, .tpg_check_prot_fabric_only = tcm_loop_check_prot_fabric_only, - .tpg_alloc_fabric_acl = tcm_loop_tpg_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_loop_tpg_release_fabric_acl, .tpg_get_inst_index = tcm_loop_get_inst_index, .check_stop_free = tcm_loop_check_stop_free, .release_cmd = tcm_loop_release_cmd, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 3a47fe46fbca..5df2a61714fb 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1707,18 +1707,6 @@ static u16 sbp_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void sbp_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -2465,8 +2453,6 @@ static const struct target_core_fabric_ops sbp_ops = { .tpg_check_demo_mode_cache = sbp_check_true, .tpg_check_demo_mode_write_protect = sbp_check_false, .tpg_check_prod_mode_write_protect = sbp_check_false, - .tpg_alloc_fabric_acl = sbp_alloc_fabric_acl, - .tpg_release_fabric_acl = sbp_release_fabric_acl, .tpg_get_inst_index = sbp_tpg_get_inst_index, .release_cmd = sbp_release_cmd, .shutdown_session = sbp_shutdown_session, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index c87ca0c50545..2b10499264d3 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -354,14 +354,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->tpg_check_prod_mode_write_protect()\n"); return -EINVAL; } - if (!tfo->tpg_alloc_fabric_acl) { - pr_err("Missing tfo->tpg_alloc_fabric_acl()\n"); - return -EINVAL; - } - if (!tfo->tpg_release_fabric_acl) { - pr_err("Missing tfo->tpg_release_fabric_acl()\n"); - return -EINVAL; - } if (!tfo->tpg_get_inst_index) { pr_err("Missing tfo->tpg_get_inst_index()\n"); return -EINVAL; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 0cd86ff9a792..42f3bd9561c8 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -259,7 +259,8 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, { struct se_node_acl *acl; - acl = tpg->se_tpg_tfo->tpg_alloc_fabric_acl(tpg); + acl = kzalloc(max(sizeof(*acl), tpg->se_tpg_tfo->node_acl_size), + GFP_KERNEL); if (!acl) return NULL; @@ -290,7 +291,7 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, out_free_device_list: core_free_device_list_for_node(acl, tpg); out_free_acl: - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + kfree(acl); return NULL; } @@ -461,7 +462,7 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) tpg->se_tpg_tfo->tpg_get_tag(tpg), acl->queue_depth, tpg->se_tpg_tfo->get_fabric_name(), acl->initiatorname); - tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl); + kfree(acl); } /* core_tpg_set_initiator_node_queue_depth(): @@ -725,7 +726,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) core_tpg_wait_for_nacl_pr_ref(nacl); core_free_device_list_for_node(nacl, se_tpg); - se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg, nacl); + kfree(nacl); spin_lock_irq(&se_tpg->acl_node_lock); } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 9dc1bd5f0e6b..0fc4f5cb4bea 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -533,7 +533,7 @@ void transport_deregister_session(struct se_session *se_sess) spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); core_tpg_wait_for_nacl_pr_ref(se_nacl); core_free_device_list_for_node(se_nacl, se_tpg); - se_tfo->tpg_release_fabric_acl(se_tpg, se_nacl); + kfree(se_nacl); comp_nacl = false; spin_lock_irqsave(&se_tpg->acl_node_lock, flags); diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 881deb3d499a..4ceaeb9a4b93 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -80,8 +80,8 @@ struct ft_node_auth { * Node ACL for FC remote port session. */ struct ft_node_acl { - struct ft_node_auth node_auth; struct se_node_acl se_node_acl; + struct ft_node_auth node_auth; }; struct ft_lun { diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index e179fdf76ddb..8da159352315 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -236,29 +236,6 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) return found; } -static struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - struct ft_node_acl *acl; - - acl = kzalloc(sizeof(*acl), GFP_KERNEL); - if (!acl) { - pr_err("Unable to allocate struct ft_node_acl\n"); - return NULL; - } - pr_debug("acl %p\n", acl); - return &acl->se_node_acl; -} - -static void ft_tpg_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_acl) -{ - struct ft_node_acl *acl = container_of(se_acl, - struct ft_node_acl, se_node_acl); - - pr_debug("acl %p\n", acl); - kfree(acl); -} - /* * local_port port_group (tpg) ops. */ @@ -474,6 +451,7 @@ static u32 ft_tpg_get_inst_index(struct se_portal_group *se_tpg) static const struct target_core_fabric_ops ft_fabric_ops = { .module = THIS_MODULE, .name = "fc", + .node_acl_size = sizeof(struct ft_node_acl), .get_fabric_name = ft_get_fabric_name, .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, @@ -485,8 +463,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .tpg_check_demo_mode_cache = ft_check_false, .tpg_check_demo_mode_write_protect = ft_check_false, .tpg_check_prod_mode_write_protect = ft_check_false, - .tpg_alloc_fabric_acl = ft_tpg_alloc_fabric_acl, - .tpg_release_fabric_acl = ft_tpg_release_fabric_acl, .tpg_get_inst_index = ft_tpg_get_inst_index, .check_stop_free = ft_check_stop_free, .release_cmd = ft_release_cmd, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index fccb0ccb355a..82f4da8bfe41 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1373,18 +1373,6 @@ static char *usbg_parse_pr_out_transport_id( return tid; } -static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void usbg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1825,8 +1813,6 @@ static const struct target_core_fabric_ops usbg_ops = { .tpg_check_demo_mode_cache = usbg_check_false, .tpg_check_demo_mode_write_protect = usbg_check_false, .tpg_check_prod_mode_write_protect = usbg_check_false, - .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, - .tpg_release_fabric_acl = usbg_release_fabric_acl, .tpg_get_inst_index = usbg_tpg_get_inst_index, .release_cmd = usbg_release_cmd, .shutdown_session = usbg_shutdown_session, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 8faa7f4abf23..b93c03935964 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -425,19 +425,6 @@ static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg) return tpg->tv_fabric_prot_type; } -static struct se_node_acl * -vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void -vhost_scsi_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -2268,8 +2255,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .tpg_check_demo_mode_write_protect = vhost_scsi_check_false, .tpg_check_prod_mode_write_protect = vhost_scsi_check_false, .tpg_check_prot_fabric_only = vhost_scsi_check_prot_fabric_only, - .tpg_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl, - .tpg_release_fabric_acl = vhost_scsi_release_fabric_acl, .tpg_get_inst_index = vhost_scsi_tpg_get_inst_index, .release_cmd = vhost_scsi_release_cmd, .check_stop_free = vhost_scsi_check_stop_free, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 8a130ab71733..3756953b385b 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1449,19 +1449,6 @@ static void scsiback_drop_tport(struct se_wwn *wwn) kfree(tport); } -static struct se_node_acl * -scsiback_alloc_fabric_acl(struct se_portal_group *se_tpg) -{ - return kzalloc(sizeof(struct se_node_acl), GFP_KERNEL); -} - -static void -scsiback_release_fabric_acl(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - kfree(se_nacl); -} - static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1952,8 +1939,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .tpg_check_demo_mode_cache = scsiback_check_true, .tpg_check_demo_mode_write_protect = scsiback_check_false, .tpg_check_prod_mode_write_protect = scsiback_check_false, - .tpg_alloc_fabric_acl = scsiback_alloc_fabric_acl, - .tpg_release_fabric_acl = scsiback_release_fabric_acl, .tpg_get_inst_index = scsiback_tpg_get_inst_index, .check_stop_free = scsiback_check_stop_free, .release_cmd = scsiback_release_cmd, diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 39f3d181d39d..f7b16ca67504 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -745,10 +745,10 @@ struct iscsi_node_stat_grps { }; struct iscsi_node_acl { + struct se_node_acl se_node_acl; struct iscsi_node_attrib node_attrib; struct iscsi_node_auth node_auth; struct iscsi_node_stat_grps node_stat_grps; - struct se_node_acl se_node_acl; }; struct iscsi_tpg_attrib { diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 8b570c49f4d1..e5414744bf2d 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -4,6 +4,7 @@ struct target_core_fabric_ops { struct module *module; const char *name; + size_t node_acl_size; char *(*get_fabric_name)(void); u8 (*get_fabric_proto_ident)(struct se_portal_group *); char *(*tpg_get_wwn)(struct se_portal_group *); @@ -36,10 +37,6 @@ struct target_core_fabric_ops { * WRITE_STRIP and READ_INSERT operations. */ int (*tpg_check_prot_fabric_only)(struct se_portal_group *); - struct se_node_acl *(*tpg_alloc_fabric_acl)( - struct se_portal_group *); - void (*tpg_release_fabric_acl)(struct se_portal_group *, - struct se_node_acl *); u32 (*tpg_get_inst_index)(struct se_portal_group *); /* * Optional to release struct se_cmd and fabric dependent allocated -- cgit v1.2.3 From 5835812f13e56483f2c4907664bb43b0a78546b6 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 1 May 2015 15:23:49 +0900 Subject: target: ensure se_cmd->t_prot_sg is allocated when required Even if the device backend is initialized with protection info is enabled, some requests don't have the protection info attached for WRITE SAME command issued by block device helpers, WRITE command with WRPROTECT=0 by SG_IO ioctl, etc. So when TCM loopback fabric module is used, se_cmd->t_prot_sg is NULL for these requests and performing WRITE_INSERT of PI using software emulation by sbc_dif_generate() causes kernel crash. To fix this, introduce SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC for se_cmd_flags, which is used to determine that se_cmd->t_prot_sg needs to be allocated or use pre-allocated protection information by scsi mid-layer. Signed-off-by: Akinobu Mita Cc: Nicholas Bellinger Cc: Sagi Grimberg Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: "James E.J. Bottomley" Cc: target-devel@vger.kernel.org Cc: linux-scsi@vger.kernel.org Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 27 +++++++++++++++------------ include/target/target_core_base.h | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0fc4f5cb4bea..85b021e749e6 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1448,6 +1448,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess if (sgl_prot_count) { se_cmd->t_prot_sg = sgl_prot; se_cmd->t_prot_nents = sgl_prot_count; + se_cmd->se_cmd_flags |= SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC; } /* @@ -2178,6 +2179,12 @@ static inline void transport_reset_sgl_orig(struct se_cmd *cmd) static inline void transport_free_pages(struct se_cmd *cmd) { + if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC)) { + transport_free_sgl(cmd->t_prot_sg, cmd->t_prot_nents); + cmd->t_prot_sg = NULL; + cmd->t_prot_nents = 0; + } + if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { /* * Release special case READ buffer payload required for @@ -2201,10 +2208,6 @@ static inline void transport_free_pages(struct se_cmd *cmd) transport_free_sgl(cmd->t_bidi_data_sg, cmd->t_bidi_data_nents); cmd->t_bidi_data_sg = NULL; cmd->t_bidi_data_nents = 0; - - transport_free_sgl(cmd->t_prot_sg, cmd->t_prot_nents); - cmd->t_prot_sg = NULL; - cmd->t_prot_nents = 0; } /** @@ -2343,6 +2346,14 @@ transport_generic_new_cmd(struct se_cmd *cmd) int ret = 0; bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); + if (cmd->prot_op != TARGET_PROT_NORMAL && + !(cmd->se_cmd_flags & SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC)) { + ret = target_alloc_sgl(&cmd->t_prot_sg, &cmd->t_prot_nents, + cmd->prot_length, true); + if (ret < 0) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + /* * Determine is the TCM fabric module has already allocated physical * memory, and is directly calling transport_generic_map_mem_to_cmd() @@ -2368,14 +2379,6 @@ transport_generic_new_cmd(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (cmd->prot_op != TARGET_PROT_NORMAL) { - ret = target_alloc_sgl(&cmd->t_prot_sg, - &cmd->t_prot_nents, - cmd->prot_length, true); - if (ret < 0) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents, cmd->data_length, zero_flag); if (ret < 0) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7f4c7de3a4ce..9f8f5a1b527d 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -161,6 +161,7 @@ enum se_cmd_flags_table { SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, + SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ -- cgit v1.2.3 From 10081fb532a2a2216b7d8e4ad585c985075b6f60 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 1 May 2015 15:23:50 +0900 Subject: lib: introduce crc_t10dif_update() This introduces crc_t10dif_update() which enables to calculate CRC for a block which straddles multiple SG elements by calling multiple times. This also converts crc_t10dif() to use crc_t10dif_update() as they are almost same. (remove extra function call in crc_t10dif() and crc_t10dif_update - Tim + Herbert) Signed-off-by: Akinobu Mita Acked-by: Martin K. Petersen Cc: Tim Chen Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Cc: Nicholas Bellinger Cc: Sagi Grimberg Cc: "Martin K. Petersen" Cc: Christoph Hellwig Cc: "James E.J. Bottomley" Cc: target-devel@vger.kernel.org Signed-off-by: Nicholas Bellinger --- include/linux/crc-t10dif.h | 1 + lib/crc-t10dif.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/crc-t10dif.h b/include/linux/crc-t10dif.h index cf53d0773ce3..d81961e9e37d 100644 --- a/include/linux/crc-t10dif.h +++ b/include/linux/crc-t10dif.h @@ -9,5 +9,6 @@ extern __u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len); extern __u16 crc_t10dif(unsigned char const *, size_t); +extern __u16 crc_t10dif_update(__u16 crc, unsigned char const *, size_t); #endif diff --git a/lib/crc-t10dif.c b/lib/crc-t10dif.c index dfe6ec17c0a5..1ad33e555805 100644 --- a/lib/crc-t10dif.c +++ b/lib/crc-t10dif.c @@ -19,7 +19,7 @@ static struct crypto_shash *crct10dif_tfm; static struct static_key crct10dif_fallback __read_mostly; -__u16 crc_t10dif(const unsigned char *buffer, size_t len) +__u16 crc_t10dif_update(__u16 crc, const unsigned char *buffer, size_t len) { struct { struct shash_desc shash; @@ -28,17 +28,23 @@ __u16 crc_t10dif(const unsigned char *buffer, size_t len) int err; if (static_key_false(&crct10dif_fallback)) - return crc_t10dif_generic(0, buffer, len); + return crc_t10dif_generic(crc, buffer, len); desc.shash.tfm = crct10dif_tfm; desc.shash.flags = 0; - *(__u16 *)desc.ctx = 0; + *(__u16 *)desc.ctx = crc; err = crypto_shash_update(&desc.shash, buffer, len); BUG_ON(err); return *(__u16 *)desc.ctx; } +EXPORT_SYMBOL(crc_t10dif_update); + +__u16 crc_t10dif(const unsigned char *buffer, size_t len) +{ + return crc_t10dif_update(0, buffer, len); +} EXPORT_SYMBOL(crc_t10dif); static int __init crc_t10dif_mod_init(void) -- cgit v1.2.3 From e4aae5af810eaa61c2cd7ba79d95ebfe0d88fe9b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:56 +0200 Subject: target: change core_tpg_register prototype Remove the unneeded fabric_ptr argument, and change the type argument to pass in a SPC protocol identifier. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 3 +-- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 8 +++---- drivers/target/iscsi/iscsi_target_configfs.c | 2 +- drivers/target/iscsi/iscsi_target_tpg.c | 3 +-- drivers/target/loopback/tcm_loop.c | 4 ++-- drivers/target/sbp/sbp_target.c | 3 +-- drivers/target/target_core_tpg.c | 31 ++++++++++++---------------- drivers/target/tcm_fc/tfc_conf.c | 2 +- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 4 ++-- drivers/vhost/scsi.c | 4 ++-- drivers/xen/xen-scsiback.c | 4 ++-- include/target/target_core_base.h | 16 ++++++-------- include/target/target_core_fabric.h | 2 +- 14 files changed, 38 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 07e7ef3d7429..b04846e985d4 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -238,8 +238,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n" buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n" buf += " ret = core_tpg_register(&" + fabric_mod_name + "_ops, wwn,\n" - buf += " &tpg->se_tpg, tpg,\n" - buf += " TRANSPORT_TPG_TYPE_NORMAL);\n" + buf += " &tpg->se_tpg, SCSI_PROTOCOL_SAS);\n" buf += " if (ret < 0) {\n" buf += " kfree(tpg);\n" buf += " return NULL;\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 38e51f4a17de..8eed6089c5d7 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3791,7 +3791,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, /* Initialize sport->port_wwn and sport->port_tpg_1 */ res = core_tpg_register(&srpt_template, &sport->port_wwn, - &sport->port_tpg_1, sport, TRANSPORT_TPG_TYPE_NORMAL); + &sport->port_tpg_1, SCSI_PROTOCOL_SRP); if (res) return ERR_PTR(res); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index cb376e5198d0..30cbfa6dc3e6 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1113,8 +1113,8 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, &tpg->se_tpg, + SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; @@ -1233,8 +1233,8 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, &tpg->se_tpg, + SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 03b2e15c1b6c..0d5d88817a47 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1421,7 +1421,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( return NULL; ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg, - tpg, TRANSPORT_TPG_TYPE_NORMAL); + SCSI_PROTOCOL_ISCSI); if (ret < 0) return NULL; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 5e3295fe404d..dcb7ede1d4aa 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -68,8 +68,7 @@ int iscsit_load_discovery_tpg(void) return -1; } - ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, - tpg, TRANSPORT_TPG_TYPE_DISCOVERY); + ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, -1); if (ret < 0) { kfree(tpg); return -1; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 9436bdfef091..3f264d436737 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -1204,8 +1204,8 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ - ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, tl_tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, + tl_hba->tl_proto_id); if (ret < 0) return ERR_PTR(-ENOMEM); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 5df2a61714fb..40b9f516cf9b 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2152,8 +2152,7 @@ static struct se_portal_group *sbp_make_tpg( goto out_free_tpg; } - ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, SCSI_PROTOCOL_SBP); if (ret < 0) goto out_unreg_mgt_agt; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 42f3bd9561c8..c0c1f67facb5 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -634,8 +634,7 @@ int core_tpg_register( const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, - void *tpg_fabric_ptr, - int se_tpg_type) + int proto_id) { struct se_lun *lun; u32 i; @@ -661,8 +660,7 @@ int core_tpg_register( init_completion(&lun->lun_ref_comp); } - se_tpg->se_tpg_type = se_tpg_type; - se_tpg->se_tpg_fabric_ptr = tpg_fabric_ptr; + se_tpg->proto_id = proto_id; se_tpg->se_tpg_tfo = tfo; se_tpg->se_tpg_wwn = se_wwn; atomic_set(&se_tpg->tpg_pr_ref_count, 0); @@ -673,7 +671,7 @@ int core_tpg_register( spin_lock_init(&se_tpg->session_lock); spin_lock_init(&se_tpg->tpg_lun_lock); - if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) { + if (se_tpg->proto_id >= 0) { if (core_tpg_setup_virtual_lun0(se_tpg) < 0) { array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); @@ -685,11 +683,10 @@ int core_tpg_register( list_add_tail(&se_tpg->se_tpg_node, &tpg_list); spin_unlock_bh(&tpg_lock); - pr_debug("TARGET_CORE[%s]: Allocated %s struct se_portal_group for" - " endpoint: %s, Portal Tag: %u\n", tfo->get_fabric_name(), - (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? - "Normal" : "Discovery", (tfo->tpg_get_wwn(se_tpg) == NULL) ? - "None" : tfo->tpg_get_wwn(se_tpg), tfo->tpg_get_tag(se_tpg)); + pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, " + "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), + tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, + se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); return 0; } @@ -697,14 +694,13 @@ EXPORT_SYMBOL(core_tpg_register); int core_tpg_deregister(struct se_portal_group *se_tpg) { + const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; struct se_node_acl *nacl, *nacl_tmp; - pr_debug("TARGET_CORE[%s]: Deallocating %s struct se_portal_group" - " for endpoint: %s Portal Tag %u\n", - (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? - "Normal" : "Discovery", se_tpg->se_tpg_tfo->get_fabric_name(), - se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg), - se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); + pr_debug("TARGET_CORE[%s]: Deallocating portal_group for endpoint: %s, " + "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), + tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, + se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); spin_lock_bh(&tpg_lock); list_del(&se_tpg->se_tpg_node); @@ -732,10 +728,9 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) } spin_unlock_irq(&se_tpg->acl_node_lock); - if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) + if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); - se_tpg->se_tpg_fabric_ptr = NULL; array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); return 0; } diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 4bdf7a25ae67..8309c3d91387 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -284,7 +284,7 @@ static struct se_portal_group *ft_add_tpg( } ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg, - tpg, TRANSPORT_TPG_TYPE_NORMAL); + SCSI_PROTOCOL_FCP); if (ret < 0) { destroy_workqueue(wq); kfree(tpg); diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 82f4da8bfe41..08b4f48aa49e 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1508,8 +1508,8 @@ static struct se_portal_group *usbg_make_tpg( tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, tpg, - TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, + tport->tport_proto_id); if (ret < 0) { destroy_workqueue(tpg->workqueue); kfree(tpg); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index b93c03935964..8295e7be0fcb 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -2119,8 +2119,8 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&vhost_scsi_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&vhost_scsi_ops, wwn, &tpg->se_tpg, + tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 3756953b385b..223d493878eb 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1883,8 +1883,8 @@ scsiback_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&scsiback_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); + ret = core_tpg_register(&scsiback_ops, wwn, &tpg->se_tpg, + tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 9f8f5a1b527d..c462fb0a47f4 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -125,12 +125,6 @@ enum transport_lun_status_table { TRANSPORT_LUN_STATUS_ACTIVE = 1, }; -/* struct se_portal_group->se_tpg_type */ -enum transport_tpg_type_table { - TRANSPORT_TPG_TYPE_NORMAL = 0, - TRANSPORT_TPG_TYPE_DISCOVERY = 1, -}; - /* Special transport agnostic struct se_cmd->t_states */ enum transport_state_table { TRANSPORT_NO_STATE = 0, @@ -864,8 +858,12 @@ struct se_tpg_np { }; struct se_portal_group { - /* Type of target portal group, see transport_tpg_type_table */ - enum transport_tpg_type_table se_tpg_type; + /* + * PROTOCOL IDENTIFIER value per SPC4, 7.5.1. + * + * Negative values can be used by fabric drivers for internal use TPGs. + */ + int proto_id; /* Number of ACLed Initiator Nodes for this TPG */ u32 num_node_acls; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ @@ -875,8 +873,6 @@ struct se_portal_group { /* Spinlock for adding/removing sessions */ spinlock_t session_lock; spinlock_t tpg_lun_lock; - /* Pointer to $FABRIC_MOD portal group */ - void *se_tpg_fabric_ptr; struct list_head se_tpg_node; /* linked list for initiator ACL list */ struct list_head acl_node_list; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index e5414744bf2d..e0adc141de07 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -175,7 +175,7 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, int core_tpg_set_initiator_node_tag(struct se_portal_group *, struct se_node_acl *, const char *); int core_tpg_register(const struct target_core_fabric_ops *, - struct se_wwn *, struct se_portal_group *, void *, int); + struct se_wwn *, struct se_portal_group *, int); int core_tpg_deregister(struct se_portal_group *); /* SAS helpers */ -- cgit v1.2.3 From 2aeeafae6bb9f04dbe17b521bcd8f0d03516c393 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:57 +0200 Subject: target: remove the get_fabric_proto_ident method Now that we store the protocol identifier in the tpg structure we don't need this method. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 31 ---------------------------- drivers/infiniband/ulp/srpt/ib_srpt.c | 6 ------ drivers/scsi/qla2xxx/tcm_qla2xxx.c | 19 ----------------- drivers/target/iscsi/iscsi_target_configfs.c | 1 - drivers/target/loopback/tcm_loop.c | 27 ------------------------ drivers/target/sbp/sbp_target.c | 13 ------------ drivers/target/target_core_configfs.c | 4 ---- drivers/target/target_core_fabric_lib.c | 27 ------------------------ drivers/target/target_core_pr.c | 12 +++++------ drivers/target/target_core_spc.c | 12 ++++------- drivers/target/tcm_fc/tfc_conf.c | 1 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 18 ---------------- drivers/vhost/scsi.c | 23 --------------------- drivers/xen/xen-scsiback.c | 23 --------------------- include/target/target_core_fabric.h | 4 ---- 15 files changed, 9 insertions(+), 212 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index b04846e985d4..29176c29537c 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -300,9 +300,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n" buf += " .module = THIS_MODULE,\n" buf += " .name = " + fabric_mod_name + ",\n" - buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" - buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" @@ -461,35 +459,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): bufi += "char *" + fabric_mod_name + "_get_fabric_name(void);\n" continue - if re.search('get_fabric_proto_ident', fo): - buf += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *se_tpg)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " u8 proto_id;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " proto_id = fc_get_fabric_proto_ident(se_tpg);\n" - buf += " break;\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " proto_id = sas_get_fabric_proto_ident(se_tpg);\n" - buf += " break;\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " proto_id = iscsi_get_fabric_proto_ident(se_tpg);\n" - buf += " break;\n" - - buf += " }\n\n" - buf += " return proto_id;\n" - buf += "}\n\n" - bufi += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *);\n" - if re.search('get_wwn', fo): buf += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *se_tpg)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 8eed6089c5d7..9213c2de28fc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3394,11 +3394,6 @@ static char *srpt_get_fabric_name(void) return "srpt"; } -static u8 srpt_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - return SCSI_TRANSPORTID_PROTOCOLID_SRP; -} - static char *srpt_get_fabric_wwn(struct se_portal_group *tpg) { struct srpt_port *sport = container_of(tpg, struct srpt_port, port_tpg_1); @@ -3863,7 +3858,6 @@ static const struct target_core_fabric_ops srpt_template = { .name = "srpt", .node_acl_size = sizeof(struct srpt_node_acl), .get_fabric_name = srpt_get_fabric_name, - .get_fabric_proto_ident = srpt_get_fabric_proto_ident, .tpg_get_wwn = srpt_get_fabric_wwn, .tpg_get_tag = srpt_get_tag, .tpg_get_pr_transport_id = srpt_get_pr_transport_id, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 30cbfa6dc3e6..4566c4649751 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -190,23 +190,6 @@ static char *tcm_qla2xxx_npiv_get_fabric_name(void) return "qla2xxx_npiv"; } -static u8 tcm_qla2xxx_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - u8 proto_id; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - proto_id = fc_get_fabric_proto_ident(se_tpg); - break; - } - - return proto_id; -} - static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -1928,7 +1911,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .name = "qla2xxx", .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_get_fabric_name, - .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, @@ -1979,7 +1961,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .name = "qla2xxx_npiv", .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, - .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 0d5d88817a47..9dec9f39139f 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1918,7 +1918,6 @@ const struct target_core_fabric_ops iscsi_ops = { .name = "iscsi", .node_acl_size = sizeof(struct iscsi_node_acl), .get_fabric_name = iscsi_get_fabric_name, - .get_fabric_proto_ident = iscsi_get_fabric_proto_ident, .tpg_get_wwn = lio_tpg_get_endpoint_wwn, .tpg_get_tag = lio_tpg_get_tag, .tpg_get_default_depth = lio_tpg_get_default_depth, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 3f264d436737..0eed0209a7f4 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -525,32 +525,6 @@ static inline struct tcm_loop_tpg *tl_tpg(struct se_portal_group *se_tpg) return container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); } -static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - /* - * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() - * time based on the protocol dependent prefix of the passed configfs group. - * - * Based upon tl_proto_id, TCM_Loop emulates the requested fabric - * ProtocolID using target_core_fabric_lib.c symbols. - */ - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_FCP: - return fc_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_fabric_proto_ident(se_tpg); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_get_fabric_proto_ident(se_tpg); -} - static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) { /* @@ -1356,7 +1330,6 @@ static const struct target_core_fabric_ops loop_ops = { .module = THIS_MODULE, .name = "loopback", .get_fabric_name = tcm_loop_get_fabric_name, - .get_fabric_proto_ident = tcm_loop_get_fabric_proto_ident, .tpg_get_wwn = tcm_loop_get_endpoint_wwn, .tpg_get_tag = tcm_loop_get_tag, .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 40b9f516cf9b..8acb37fd9ebc 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1832,18 +1832,6 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) return 1; } -/* - * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3) - */ -static u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - /* - * Return a IEEE 1394 SCSI Protocol identifier for loopback operations - * This is defined in section 7.5.1 Table 362 in spc4r17 - */ - return SCSI_PROTOCOL_SBP; -} - static u32 sbp_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -2442,7 +2430,6 @@ static const struct target_core_fabric_ops sbp_ops = { .module = THIS_MODULE, .name = "sbp", .get_fabric_name = sbp_get_fabric_name, - .get_fabric_proto_ident = sbp_get_fabric_proto_ident, .tpg_get_wwn = sbp_get_fabric_wwn, .tpg_get_tag = sbp_get_tag, .tpg_get_pr_transport_id = sbp_get_pr_transport_id, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 2b10499264d3..21c9f7d79d5e 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -318,10 +318,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->get_fabric_name()\n"); return -EINVAL; } - if (!tfo->get_fabric_proto_ident) { - pr_err("Missing tfo->get_fabric_proto_ident()\n"); - return -EINVAL; - } if (!tfo->tpg_get_wwn) { pr_err("Missing tfo->tpg_get_wwn()\n"); return -EINVAL; diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 35bfe77160d8..6fed14adbe61 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -42,16 +42,6 @@ /* * Handlers for Serial Attached SCSI (SAS) */ -u8 sas_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - /* - * Return a SAS Serial SCSI Protocol identifier for loopback operations - * This is defined in section 7.5.1 Table 362 in spc4r17 - */ - return 0x6; -} -EXPORT_SYMBOL(sas_get_fabric_proto_ident); - u32 sas_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -128,12 +118,6 @@ EXPORT_SYMBOL(sas_parse_pr_out_transport_id); /* * Handlers for Fibre Channel Protocol (FCP) */ -u8 fc_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - return 0x0; /* 0 = fcp-2 per SPC4 section 7.5.1 */ -} -EXPORT_SYMBOL(fc_get_fabric_proto_ident); - u32 fc_get_pr_transport_id_len( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, @@ -208,17 +192,6 @@ EXPORT_SYMBOL(fc_parse_pr_out_transport_id); /* * Handlers for Internet Small Computer Systems Interface (iSCSI) */ - -u8 iscsi_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - /* - * This value is defined for "Internet SCSI (iSCSI)" - * in spc4r17 section 7.5.1 Table 362 - */ - return 0x5; -} -EXPORT_SYMBOL(iscsi_get_fabric_proto_ident); - u32 iscsi_get_pr_transport_id( struct se_portal_group *se_tpg, struct se_node_acl *se_nacl, diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index a15411c79ae9..23c065f83a56 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1447,7 +1447,7 @@ core_scsi3_decode_spec_i_port( struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; const struct target_core_fabric_ops *tmp_tf_ops; unsigned char *buf; - unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident; + unsigned char *ptr, *i_str = NULL, proto_ident; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; @@ -1536,15 +1536,13 @@ core_scsi3_decode_spec_i_port( tmp_tf_ops = tmp_tpg->se_tpg_tfo; if (!tmp_tf_ops) continue; - if (!tmp_tf_ops->get_fabric_proto_ident || - !tmp_tf_ops->tpg_parse_pr_out_transport_id) + if (!tmp_tf_ops->tpg_parse_pr_out_transport_id) continue; /* * Look for the matching proto_ident provided by * the received TransportID */ - tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg); - if (tmp_proto_ident != proto_ident) + if (tmp_tpg->proto_id != proto_ident) continue; dest_rtpi = tmp_port->sep_rtpi; @@ -3230,11 +3228,11 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, pr_debug("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:" " 0x%02x\n", proto_ident); - if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) { + if (proto_ident != dest_se_tpg->proto_id) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Received" " proto_ident: 0x%02x does not match ident: 0x%02x" " from fabric: %s\n", proto_ident, - dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), + dest_se_tpg->proto_id, dest_tf_ops->get_fabric_name()); ret = TCM_INVALID_PARAMETER_LIST; goto out; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 988c158cf65d..78c0b40fa5c0 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -286,8 +286,7 @@ check_t10_vend_desc: * Get the PROTOCOL IDENTIFIER as defined by spc4r17 * section 7.5.1 Table 362 */ - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x1; /* CODE SET == Binary */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target port: 01b */ @@ -322,8 +321,7 @@ check_t10_vend_desc: tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x1; /* CODE SET == Binary */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target port: 01b */ @@ -371,8 +369,7 @@ check_lu_gp: * section 7.5.1 Table 362 */ check_scsi_name: - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x3; /* CODE SET == UTF-8 */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target port: 01b */ @@ -412,8 +409,7 @@ check_scsi_name: /* * Target device designator */ - buf[off] = - (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4); + buf[off] = tpg->proto_id << 4; buf[off++] |= 0x3; /* CODE SET == UTF-8 */ buf[off] = 0x80; /* Set PIV=1 */ /* Set ASSOCIATION == target device: 10b */ diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8309c3d91387..fabc7bacf693 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -452,7 +452,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .name = "fc", .node_acl_size = sizeof(struct ft_node_acl), .get_fabric_name = ft_get_fabric_name, - .get_fabric_proto_ident = fc_get_fabric_proto_ident, .tpg_get_wwn = ft_get_fabric_wwn, .tpg_get_tag = ft_get_tag, .tpg_get_pr_transport_id = fc_get_pr_transport_id, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 08b4f48aa49e..d6b03178262f 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1274,23 +1274,6 @@ static char *usbg_get_fabric_name(void) return "usb_gadget"; } -static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - u8 proto_id; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - proto_id = sas_get_fabric_proto_ident(se_tpg); - break; - } - - return proto_id; -} - static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg) { struct usbg_tpg *tpg = container_of(se_tpg, @@ -1803,7 +1786,6 @@ static const struct target_core_fabric_ops usbg_ops = { .module = THIS_MODULE, .name = "usb_gadget", .get_fabric_name = usbg_get_fabric_name, - .get_fabric_proto_ident = usbg_get_fabric_proto_ident, .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, .tpg_get_pr_transport_id = usbg_get_pr_transport_id, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 8295e7be0fcb..022860ccd008 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -288,28 +288,6 @@ static char *vhost_scsi_get_fabric_name(void) return "vhost"; } -static u8 vhost_scsi_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_FCP: - return fc_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_fabric_proto_ident(se_tpg); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_get_fabric_proto_ident(se_tpg); -} - static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, @@ -2244,7 +2222,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .module = THIS_MODULE, .name = "vhost", .get_fabric_name = vhost_scsi_get_fabric_name, - .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, .tpg_get_tag = vhost_scsi_get_tpgt, .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 223d493878eb..8bf9448bd7fd 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1254,28 +1254,6 @@ static char *scsiback_dump_proto_id(struct scsiback_tport *tport) return "Unknown"; } -static u8 scsiback_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_FCP: - return fc_get_fabric_proto_ident(se_tpg); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_fabric_proto_ident(se_tpg); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_get_fabric_proto_ident(se_tpg); -} - static char *scsiback_get_fabric_wwn(struct se_portal_group *se_tpg) { struct scsiback_tpg *tpg = container_of(se_tpg, @@ -1929,7 +1907,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .module = THIS_MODULE, .name = "xen-pvscsi", .get_fabric_name = scsiback_get_fabric_name, - .get_fabric_proto_ident = scsiback_get_fabric_proto_ident, .tpg_get_wwn = scsiback_get_fabric_wwn, .tpg_get_tag = scsiback_get_tag, .tpg_get_pr_transport_id = scsiback_get_pr_transport_id, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index e0adc141de07..495606382546 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -6,7 +6,6 @@ struct target_core_fabric_ops { const char *name; size_t node_acl_size; char *(*get_fabric_name)(void); - u8 (*get_fabric_proto_ident)(struct se_portal_group *); char *(*tpg_get_wwn)(struct se_portal_group *); u16 (*tpg_get_tag)(struct se_portal_group *); u32 (*tpg_get_default_depth)(struct se_portal_group *); @@ -179,7 +178,6 @@ int core_tpg_register(const struct target_core_fabric_ops *, int core_tpg_deregister(struct se_portal_group *); /* SAS helpers */ -u8 sas_get_fabric_proto_ident(struct se_portal_group *); u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, struct t10_pr_registration *, int *, unsigned char *); u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, @@ -188,7 +186,6 @@ char *sas_parse_pr_out_transport_id(struct se_portal_group *, const char *, u32 *, char **); /* FC helpers */ -u8 fc_get_fabric_proto_ident(struct se_portal_group *); u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, struct t10_pr_registration *, int *, unsigned char *); u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, @@ -197,7 +194,6 @@ char *fc_parse_pr_out_transport_id(struct se_portal_group *, const char *, u32 *, char **); /* iSCSI helpers */ -u8 iscsi_get_fabric_proto_ident(struct se_portal_group *); u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, struct t10_pr_registration *, int *, unsigned char *); u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, -- cgit v1.2.3 From 2650d71e244fb3637b5f58a0080682a8bf9c7091 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 1 May 2015 17:47:58 +0200 Subject: target: move transport ID handling to the core Now that struct se_portal_group contains a protocol identifier field we can take all the code to format an parse protocol identifiers in CDBs into common code instead of leaving this to low-level drivers. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 121 ------------ drivers/infiniband/ulp/srpt/ib_srpt.c | 39 ---- drivers/infiniband/ulp/srpt/ib_srpt.h | 18 -- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 73 -------- drivers/scsi/qla2xxx/tcm_qla2xxx.h | 2 - drivers/target/iscsi/iscsi_target_configfs.c | 3 - drivers/target/loopback/tcm_loop.c | 92 ---------- drivers/target/sbp/sbp_target.c | 70 ------- drivers/target/target_core_configfs.c | 8 - drivers/target/target_core_fabric_lib.c | 263 ++++++++++++++------------- drivers/target/target_core_internal.h | 9 + drivers/target/target_core_pr.c | 49 +++-- drivers/target/tcm_fc/tfc_conf.c | 3 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 75 +------- drivers/usb/gadget/legacy/tcm_usb_gadget.h | 2 - drivers/vhost/scsi.c | 94 ---------- drivers/xen/xen-scsiback.c | 94 ---------- include/target/target_core_fabric.h | 33 ---- 18 files changed, 173 insertions(+), 875 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 29176c29537c..0dbd70cccde1 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -60,8 +60,6 @@ def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name): buf += "};\n" buf += "\n" buf += "struct " + fabric_mod_name + "_lport {\n" - buf += " /* SCSI protocol the lport is providing */\n" - buf += " u8 lport_proto_id;\n" buf += " /* Binary World Wide unique Port Name for FC Target Lport */\n" buf += " u64 lport_wwpn;\n" buf += " /* ASCII formatted WWPN for FC Target Lport */\n" @@ -105,8 +103,6 @@ def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name): buf += " struct se_portal_group se_tpg;\n" buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tport {\n" - buf += " /* SCSI protocol the tport is providing */\n" - buf += " u8 tport_proto_id;\n" buf += " /* Binary World Wide unique Port Name for SAS Target port */\n" buf += " u64 tport_wwpn;\n" buf += " /* ASCII formatted WWPN for SAS Target port */\n" @@ -150,8 +146,6 @@ def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name): buf += " struct se_portal_group se_tpg;\n" buf += "};\n\n" buf += "struct " + fabric_mod_name + "_tport {\n" - buf += " /* SCSI protocol the tport is providing */\n" - buf += " u8 tport_proto_id;\n" buf += " /* ASCII formatted TargetName for IQN */\n" buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n" buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n" @@ -303,9 +297,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n" buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n" buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n" - buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n" - buf += " .tpg_get_pr_transport_id_len = " + fabric_mod_name + "_get_pr_transport_id_len,\n" - buf += " .tpg_parse_pr_out_transport_id = " + fabric_mod_name + "_parse_pr_out_transport_id,\n" buf += " .tpg_check_demo_mode = " + fabric_mod_name + "_check_false,\n" buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n" buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n" @@ -478,118 +469,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *);\n" - if re.search('get_pr_transport_id\)\(', fo): - buf += "u32 " + fabric_mod_name + "_get_pr_transport_id(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct se_node_acl *se_nacl,\n" - buf += " struct t10_pr_registration *pr_reg,\n" - buf += " int *format_code,\n" - buf += " unsigned char *buf)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " int ret = 0;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code, buf);\n" - buf += " break;\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code, buf);\n" - buf += " break;\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " ret = iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code, buf);\n" - buf += " break;\n" - - buf += " }\n\n" - buf += " return ret;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id(struct se_portal_group *,\n" - bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" - bufi += " int *, unsigned char *);\n" - - if re.search('get_pr_transport_id_len\)\(', fo): - buf += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " struct se_node_acl *se_nacl,\n" - buf += " struct t10_pr_registration *pr_reg,\n" - buf += " int *format_code)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " int ret = 0;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code);\n" - buf += " break;\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code);\n" - buf += " break;\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " ret = iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n" - buf += " format_code);\n" - buf += " break;\n" - - - buf += " }\n\n" - buf += " return ret;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(struct se_portal_group *,\n" - bufi += " struct se_node_acl *, struct t10_pr_registration *,\n" - bufi += " int *);\n" - - if re.search('parse_pr_out_transport_id\)\(', fo): - buf += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(\n" - buf += " struct se_portal_group *se_tpg,\n" - buf += " const char *buf,\n" - buf += " u32 *out_tid_len,\n" - buf += " char **port_nexus_ptr)\n" - buf += "{\n" - buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n" - buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n" - buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n" - buf += " char *tid = NULL;\n\n" - buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n" - if proto_ident == "FC": - buf += " case SCSI_PROTOCOL_FCP:\n" - buf += " default:\n" - buf += " tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" - buf += " port_nexus_ptr);\n" - elif proto_ident == "SAS": - buf += " case SCSI_PROTOCOL_SAS:\n" - buf += " default:\n" - buf += " tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" - buf += " port_nexus_ptr);\n" - elif proto_ident == "iSCSI": - buf += " case SCSI_PROTOCOL_ISCSI:\n" - buf += " default:\n" - buf += " tid = iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n" - buf += " port_nexus_ptr);\n" - - buf += " }\n\n" - buf += " return tid;\n" - buf += "}\n\n" - bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n" - bufi += " const char *, u32 *, char **);\n" - if re.search('tpg_get_inst_index\)\(', fo): buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 9213c2de28fc..98e00360f97e 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3406,42 +3406,6 @@ static u16 srpt_get_tag(struct se_portal_group *tpg) return 1; } -static u32 srpt_get_pr_transport_id(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, unsigned char *buf) -{ - struct srpt_node_acl *nacl; - struct spc_rdma_transport_id *tr_id; - - nacl = container_of(se_nacl, struct srpt_node_acl, nacl); - tr_id = (void *)buf; - tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP; - memcpy(tr_id->i_port_id, nacl->i_port_id, sizeof(tr_id->i_port_id)); - return sizeof(*tr_id); -} - -static u32 srpt_get_pr_transport_id_len(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - return sizeof(struct spc_rdma_transport_id); -} - -static char *srpt_parse_pr_out_transport_id(struct se_portal_group *se_tpg, - const char *buf, u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct spc_rdma_transport_id *tr_id; - - *port_nexus_ptr = NULL; - *out_tid_len = sizeof(struct spc_rdma_transport_id); - tr_id = (void *)buf; - return (char *)tr_id->i_port_id; -} - static u32 srpt_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -3860,9 +3824,6 @@ static const struct target_core_fabric_ops srpt_template = { .get_fabric_name = srpt_get_fabric_name, .tpg_get_wwn = srpt_get_fabric_wwn, .tpg_get_tag = srpt_get_tag, - .tpg_get_pr_transport_id = srpt_get_pr_transport_id, - .tpg_get_pr_transport_id_len = srpt_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = srpt_parse_pr_out_transport_id, .tpg_check_demo_mode = srpt_check_false, .tpg_check_demo_mode_cache = srpt_check_true, .tpg_check_demo_mode_write_protect = srpt_check_true, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 355f6f5ce8b2..33b2c88b73ba 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -422,22 +422,4 @@ struct srpt_node_acl { struct list_head list; }; -/* - * SRP-releated SCSI persistent reservation definitions. - * - * See also SPC4r28, section 7.6.1 (Protocol specific parameters introduction). - * See also SPC4r28, section 7.6.4.5 (TransportID for initiator ports using - * SCSI over an RDMA interface). - */ - -enum { - SCSI_TRANSPORTID_PROTOCOLID_SRP = 4, -}; - -struct spc_rdma_transport_id { - uint8_t protocol_identifier; - uint8_t reserved[7]; - uint8_t i_port_id[16]; -}; - #endif /* IB_SRPT_H */ diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 4566c4649751..bd0f9eb67901 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -206,73 +206,6 @@ static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg) return tpg->lport_tpgt; } -static u32 tcm_qla2xxx_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - int ret = 0; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - break; - } - - return ret; -} - -static u32 tcm_qla2xxx_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - int ret = 0; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - break; - } - - return ret; -} - -static char *tcm_qla2xxx_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - char *tid = NULL; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - break; - } - - return tid; -} - static int tcm_qla2xxx_check_demo_mode(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -1913,9 +1846,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .get_fabric_name = tcm_qla2xxx_get_fabric_name, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, .tpg_check_demo_mode_cache = tcm_qla2xxx_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = @@ -1963,9 +1893,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, .tpg_check_demo_mode_cache = tcm_qla2xxx_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_demo_mode, diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 3d805a07061c..3bbf4cb6fd97 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -57,8 +57,6 @@ struct tcm_qla2xxx_fc_loopid { }; struct tcm_qla2xxx_lport { - /* SCSI protocol the lport is providing */ - u8 lport_proto_id; /* Binary World Wide unique Port Name for FC Target Lport */ u64 lport_wwpn; /* Binary World Wide unique Port Name for FC NPIV Target Lport */ diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 9dec9f39139f..bd8af8764f4b 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1921,9 +1921,6 @@ const struct target_core_fabric_ops iscsi_ops = { .tpg_get_wwn = lio_tpg_get_endpoint_wwn, .tpg_get_tag = lio_tpg_get_tag, .tpg_get_default_depth = lio_tpg_get_default_depth, - .tpg_get_pr_transport_id = iscsi_get_pr_transport_id, - .tpg_get_pr_transport_id_len = iscsi_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = iscsi_parse_pr_out_transport_id, .tpg_check_demo_mode = lio_tpg_check_demo_mode, .tpg_check_demo_mode_cache = lio_tpg_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 0eed0209a7f4..b788406977f6 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -542,95 +542,6 @@ static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) return tl_tpg(se_tpg)->tl_tpgt; } -static u32 tcm_loop_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); -} - -static u32 tcm_loop_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); -} - -/* - * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above - * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. - */ -static char *tcm_loop_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct tcm_loop_hba *tl_hba = tl_tpg(se_tpg)->tl_hba; - - switch (tl_hba->tl_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_FCP: - return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_ISCSI: - return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - default: - pr_err("Unknown tl_proto_id: 0x%02x, using" - " SAS emulation\n", tl_hba->tl_proto_id); - break; - } - - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); -} - /* * Returning (1) here allows for target_core_mod struct se_node_acl to be generated * based upon the incoming fabric dependent SCSI Initiator Port @@ -1332,9 +1243,6 @@ static const struct target_core_fabric_ops loop_ops = { .get_fabric_name = tcm_loop_get_fabric_name, .tpg_get_wwn = tcm_loop_get_endpoint_wwn, .tpg_get_tag = tcm_loop_get_tag, - .tpg_get_pr_transport_id = tcm_loop_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_loop_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_loop_parse_pr_out_transport_id, .tpg_check_demo_mode = tcm_loop_check_demo_mode, .tpg_check_demo_mode_cache = tcm_loop_check_demo_mode_cache, .tpg_check_demo_mode_write_protect = diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 8acb37fd9ebc..89f172dc8678 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1832,73 +1832,6 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) return 1; } -static u32 sbp_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - int ret; - - /* - * Set PROTOCOL IDENTIFIER to 3h for SBP - */ - buf[0] = SCSI_PROTOCOL_SBP; - /* - * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI - * over IEEE 1394 - */ - ret = hex2bin(&buf[8], se_nacl->initiatorname, 8); - if (ret < 0) - pr_debug("sbp transport_id: invalid hex string\n"); - - /* - * The IEEE 1394 Transport ID is a hardcoded 24-byte length - */ - return 24; -} - -static u32 sbp_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - /* - * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI - * over IEEE 1394 - * - * The SBP Transport ID is a hardcoded 24-byte length - */ - return 24; -} - -/* - * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above - * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. - */ -static char *sbp_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - /* - * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID - * for initiator ports using SCSI over SBP Serial SCSI Protocol - * - * The TransportID for a IEEE 1394 Initiator Port is of fixed size of - * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier, - * so we return the **port_nexus_ptr set to NULL. - */ - *port_nexus_ptr = NULL; - *out_tid_len = 24; - - return (char *)&buf[8]; -} - static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) { int i, count = 0; @@ -2432,9 +2365,6 @@ static const struct target_core_fabric_ops sbp_ops = { .get_fabric_name = sbp_get_fabric_name, .tpg_get_wwn = sbp_get_fabric_wwn, .tpg_get_tag = sbp_get_tag, - .tpg_get_pr_transport_id = sbp_get_pr_transport_id, - .tpg_get_pr_transport_id_len = sbp_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = sbp_parse_pr_out_transport_id, .tpg_check_demo_mode = sbp_check_true, .tpg_check_demo_mode_cache = sbp_check_true, .tpg_check_demo_mode_write_protect = sbp_check_false, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 21c9f7d79d5e..5e2649fc6919 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -326,14 +326,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->tpg_get_tag()\n"); return -EINVAL; } - if (!tfo->tpg_get_pr_transport_id) { - pr_err("Missing tfo->tpg_get_pr_transport_id()\n"); - return -EINVAL; - } - if (!tfo->tpg_get_pr_transport_id_len) { - pr_err("Missing tfo->tpg_get_pr_transport_id_len()\n"); - return -EINVAL; - } if (!tfo->tpg_check_demo_mode) { pr_err("Missing tfo->tpg_check_demo_mode()\n"); return -EINVAL; diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 6fed14adbe61..89720b2f37c2 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -24,6 +24,11 @@ * ******************************************************************************/ +/* + * See SPC4, section 7.5 "Protocol specific parameters" for details + * on the formats implemented in this file. + */ + #include #include #include @@ -39,103 +44,26 @@ #include "target_core_internal.h" #include "target_core_pr.h" -/* - * Handlers for Serial Attached SCSI (SAS) - */ -u32 sas_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, + +static int sas_get_pr_transport_id( + struct se_node_acl *nacl, int *format_code, unsigned char *buf) { - unsigned char *ptr; int ret; - /* - * Set PROTOCOL IDENTIFIER to 6h for SAS - */ - buf[0] = 0x06; - /* - * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI - * over SAS Serial SCSI Protocol - */ - ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */ - - ret = hex2bin(&buf[4], ptr, 8); - if (ret < 0) - pr_debug("sas transport_id: invalid hex string\n"); - - /* - * The SAS Transport ID is a hardcoded 24-byte length - */ - return 24; -} -EXPORT_SYMBOL(sas_get_pr_transport_id); - -u32 sas_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - /* - * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI - * over SAS Serial SCSI Protocol - * - * The SAS Transport ID is a hardcoded 24-byte length - */ - return 24; -} -EXPORT_SYMBOL(sas_get_pr_transport_id_len); - -/* - * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above - * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. - */ -char *sas_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - /* - * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID - * for initiator ports using SCSI over SAS Serial SCSI Protocol - * - * The TransportID for a SAS Initiator Port is of fixed size of - * 24 bytes, and SAS does not contain a I_T nexus identifier, - * so we return the **port_nexus_ptr set to NULL. - */ - *port_nexus_ptr = NULL; - *out_tid_len = 24; - - return (char *)&buf[4]; -} -EXPORT_SYMBOL(sas_parse_pr_out_transport_id); + /* Skip over 'naa. prefix */ + ret = hex2bin(&buf[4], &nacl->initiatorname[4], 8); + if (ret) { + pr_debug("%s: invalid hex string\n", __func__); + return ret; + } -/* - * Handlers for Fibre Channel Protocol (FCP) - */ -u32 fc_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - *format_code = 0; - /* - * The FC Transport ID is a hardcoded 24-byte length - */ return 24; } -EXPORT_SYMBOL(fc_get_pr_transport_id_len); -u32 fc_get_pr_transport_id( - struct se_portal_group *se_tpg, +static int fc_get_pr_transport_id( struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, int *format_code, unsigned char *buf) { @@ -144,24 +72,20 @@ u32 fc_get_pr_transport_id( u32 off = 8; /* - * PROTOCOL IDENTIFIER is 0h for FCP-2 - * - * From spc4r17, 7.5.4.2 TransportID for initiator ports using - * SCSI over Fibre Channel - * * We convert the ASCII formatted N Port name into a binary * encoded TransportID. */ ptr = &se_nacl->initiatorname[0]; - for (i = 0; i < 24; ) { if (!strncmp(&ptr[i], ":", 1)) { i++; continue; } ret = hex2bin(&buf[off++], &ptr[i], 1); - if (ret < 0) - pr_debug("fc transport_id: invalid hex string\n"); + if (ret < 0) { + pr_debug("%s: invalid hex string\n", __func__); + return ret; + } i += 2; } /* @@ -169,31 +93,52 @@ u32 fc_get_pr_transport_id( */ return 24; } -EXPORT_SYMBOL(fc_get_pr_transport_id); -char *fc_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) +static int sbp_get_pr_transport_id( + struct se_node_acl *nacl, + int *format_code, + unsigned char *buf) { - /* - * The TransportID for a FC N Port is of fixed size of - * 24 bytes, and FC does not contain a I_T nexus identifier, - * so we return the **port_nexus_ptr set to NULL. - */ - *port_nexus_ptr = NULL; - *out_tid_len = 24; + int ret; + + ret = hex2bin(&buf[8], nacl->initiatorname, 8); + if (ret) { + pr_debug("%s: invalid hex string\n", __func__); + return ret; + } - return (char *)&buf[8]; + return 24; } -EXPORT_SYMBOL(fc_parse_pr_out_transport_id); -/* - * Handlers for Internet Small Computer Systems Interface (iSCSI) - */ -u32 iscsi_get_pr_transport_id( - struct se_portal_group *se_tpg, +static int srp_get_pr_transport_id( + struct se_node_acl *nacl, + int *format_code, + unsigned char *buf) +{ + const char *p; + unsigned len, count, leading_zero_bytes; + int rc; + + p = nacl->initiatorname; + if (strncasecmp(p, "0x", 2) == 0) + p += 2; + len = strlen(p); + if (len % 2) + return -EINVAL; + + count = min(len / 2, 16U); + leading_zero_bytes = 16 - count; + memset(buf + 8, 0, leading_zero_bytes); + rc = hex2bin(buf + 8 + leading_zero_bytes, p, count); + if (rc < 0) { + pr_debug("hex2bin failed for %s: %d\n", __func__, rc); + return rc; + } + + return 24; +} + +static int iscsi_get_pr_transport_id( struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg, int *format_code, @@ -203,10 +148,6 @@ u32 iscsi_get_pr_transport_id( u16 len = 0; spin_lock_irq(&se_nacl->nacl_sess_lock); - /* - * Set PROTOCOL IDENTIFIER to 5h for iSCSI - */ - buf[0] = 0x05; /* * From spc4r17 Section 7.5.4.6: TransportID for initiator * ports using SCSI over iSCSI. @@ -286,10 +227,8 @@ u32 iscsi_get_pr_transport_id( return len; } -EXPORT_SYMBOL(iscsi_get_pr_transport_id); -u32 iscsi_get_pr_transport_id_len( - struct se_portal_group *se_tpg, +static int iscsi_get_pr_transport_id_len( struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg, int *format_code) @@ -332,9 +271,8 @@ u32 iscsi_get_pr_transport_id_len( return len; } -EXPORT_SYMBOL(iscsi_get_pr_transport_id_len); -char *iscsi_parse_pr_out_transport_id( +static char *iscsi_parse_pr_out_transport_id( struct se_portal_group *se_tpg, const char *buf, u32 *out_tid_len, @@ -421,4 +359,79 @@ char *iscsi_parse_pr_out_transport_id( return (char *)&buf[4]; } -EXPORT_SYMBOL(iscsi_parse_pr_out_transport_id); + +int target_get_pr_transport_id_len(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code) +{ + switch (nacl->se_tpg->proto_id) { + case SCSI_PROTOCOL_FCP: + case SCSI_PROTOCOL_SBP: + case SCSI_PROTOCOL_SRP: + case SCSI_PROTOCOL_SAS: + break; + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_pr_transport_id_len(nacl, pr_reg, format_code); + default: + pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); + return -EINVAL; + } + + /* + * Most transports use a fixed length 24 byte identifier. + */ + *format_code = 0; + return 24; +} + +int target_get_pr_transport_id(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code, + unsigned char *buf) +{ + switch (nacl->se_tpg->proto_id) { + case SCSI_PROTOCOL_SAS: + return sas_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_SBP: + return sbp_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_SRP: + return srp_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_FCP: + return fc_get_pr_transport_id(nacl, format_code, buf); + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_pr_transport_id(nacl, pr_reg, format_code, + buf); + default: + pr_err("Unknown proto_id: 0x%02x\n", nacl->se_tpg->proto_id); + return -EINVAL; + } +} + +const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, + const char *buf, u32 *out_tid_len, char **port_nexus_ptr) +{ + u32 offset; + + switch (tpg->proto_id) { + case SCSI_PROTOCOL_SAS: + /* + * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID + * for initiator ports using SCSI over SAS Serial SCSI Protocol. + */ + offset = 4; + break; + case SCSI_PROTOCOL_SBP: + case SCSI_PROTOCOL_SRP: + case SCSI_PROTOCOL_FCP: + offset = 8; + break; + case SCSI_PROTOCOL_ISCSI: + return iscsi_parse_pr_out_transport_id(tpg, buf, out_tid_len, + port_nexus_ptr); + default: + pr_err("Unknown proto_id: 0x%02x\n", tpg->proto_id); + return NULL; + } + + *port_nexus_ptr = NULL; + *out_tid_len = 24; + return buf + offset; +} diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 058ca71cda81..d0344ad9b0d8 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -38,6 +38,15 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name); int target_configure_device(struct se_device *dev); void target_free_device(struct se_device *); +/* target_core_fabric_lib.c */ +int target_get_pr_transport_id_len(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code); +int target_get_pr_transport_id(struct se_node_acl *nacl, + struct t10_pr_registration *pr_reg, int *format_code, + unsigned char *buf); +const char *target_parse_pr_out_transport_id(struct se_portal_group *tpg, + const char *buf, u32 *out_tid_len, char **port_nexus_ptr); + /* target_core_hba.c */ struct se_hba *core_alloc_hba(const char *, u32, u32); int core_delete_hba(struct se_hba *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 23c065f83a56..d396b3b87025 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1445,9 +1445,8 @@ core_scsi3_decode_spec_i_port( struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp; - const struct target_core_fabric_ops *tmp_tf_ops; - unsigned char *buf; - unsigned char *ptr, *i_str = NULL, proto_ident; + unsigned char *buf, *ptr, proto_ident; + const unsigned char *i_str; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; @@ -1533,11 +1532,7 @@ core_scsi3_decode_spec_i_port( tmp_tpg = tmp_port->sep_tpg; if (!tmp_tpg) continue; - tmp_tf_ops = tmp_tpg->se_tpg_tfo; - if (!tmp_tf_ops) - continue; - if (!tmp_tf_ops->tpg_parse_pr_out_transport_id) - continue; + /* * Look for the matching proto_ident provided by * the received TransportID @@ -1546,9 +1541,8 @@ core_scsi3_decode_spec_i_port( continue; dest_rtpi = tmp_port->sep_rtpi; - i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id( - tmp_tpg, (const char *)ptr, &tid_len, - &iport_ptr); + i_str = target_parse_pr_out_transport_id(tmp_tpg, + (const char *)ptr, &tid_len, &iport_ptr); if (!i_str) continue; @@ -3105,7 +3099,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; - unsigned char *initiator_str; + const unsigned char *initiator_str; char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; u32 tid_len, tmp_tid_len; int new_reg = 0, type, scope, matching_iname; @@ -3237,14 +3231,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, ret = TCM_INVALID_PARAMETER_LIST; goto out; } - if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { - pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not" - " containg a valid tpg_parse_pr_out_transport_id" - " function pointer\n"); - ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - goto out; - } - initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, + initiator_str = target_parse_pr_out_transport_id(dest_se_tpg, (const char *)&buf[24], &tmp_tid_len, &iport_ptr); if (!initiator_str) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" @@ -3881,9 +3868,10 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char *buf; - u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len; + u32 add_desc_len = 0, add_len = 0; u32 off = 8; /* off into first Full Status descriptor */ int format_code = 0, pr_res_type = 0, pr_res_scope = 0; + int exp_desc_len, desc_len; bool all_reg = false; if (cmd->data_length < 8) { @@ -3928,10 +3916,10 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) * Determine expected length of $FABRIC_MOD specific * TransportID full status descriptor.. */ - exp_desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id_len( - se_tpg, se_nacl, pr_reg, &format_code); - - if ((exp_desc_len + add_len) > cmd->data_length) { + exp_desc_len = target_get_pr_transport_id_len(se_nacl, pr_reg, + &format_code); + if (exp_desc_len < 0 || + exp_desc_len + add_len > cmd->data_length) { pr_warn("SPC-3 PRIN READ_FULL_STATUS ran" " out of buffer: %d\n", cmd->data_length); spin_lock(&pr_tmpl->registration_lock); @@ -3995,14 +3983,19 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) } else off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */ + buf[off+4] = se_tpg->proto_id; + /* - * Now, have the $FABRIC_MOD fill in the protocol identifier + * Now, have the $FABRIC_MOD fill in the transport ID. */ - desc_len = se_tpg->se_tpg_tfo->tpg_get_pr_transport_id(se_tpg, - se_nacl, pr_reg, &format_code, &buf[off+4]); + desc_len = target_get_pr_transport_id(se_nacl, pr_reg, + &format_code, &buf[off+4]); spin_lock(&pr_tmpl->registration_lock); atomic_dec_mb(&pr_reg->pr_res_holders); + + if (desc_len < 0) + break; /* * Set the ADDITIONAL DESCRIPTOR LENGTH */ diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index fabc7bacf693..6ad7404b7dd1 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -454,9 +454,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .get_fabric_name = ft_get_fabric_name, .tpg_get_wwn = ft_get_fabric_wwn, .tpg_get_tag = ft_get_tag, - .tpg_get_pr_transport_id = fc_get_pr_transport_id, - .tpg_get_pr_transport_id_len = fc_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = fc_parse_pr_out_transport_id, .tpg_check_demo_mode = ft_check_false, .tpg_check_demo_mode_cache = ft_check_false, .tpg_check_demo_mode_write_protect = ft_check_false, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index d6b03178262f..77cdbb56e1d5 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1290,72 +1290,6 @@ static u16 usbg_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 usbg_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - int ret = 0; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - break; - } - - return ret; -} - -static u32 usbg_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - int ret = 0; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - break; - } - - return ret; -} - -static char *usbg_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct usbg_tpg *tpg = container_of(se_tpg, - struct usbg_tpg, se_tpg); - struct usbg_tport *tport = tpg->tport; - char *tid = NULL; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - default: - tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - } - - return tid; -} - static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) { return 1; @@ -1491,8 +1425,12 @@ static struct se_portal_group *usbg_make_tpg( tpg->tport = tport; tpg->tport_tpgt = tpgt; + /* + * SPC doesn't assign a protocol identifier for USB-SCSI, so we + * pretend to be SAS.. + */ ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, - tport->tport_proto_id); + SCSI_PROTOCOL_SAS); if (ret < 0) { destroy_workqueue(tpg->workqueue); kfree(tpg); @@ -1788,9 +1726,6 @@ static const struct target_core_fabric_ops usbg_ops = { .get_fabric_name = usbg_get_fabric_name, .tpg_get_wwn = usbg_get_fabric_wwn, .tpg_get_tag = usbg_get_tag, - .tpg_get_pr_transport_id = usbg_get_pr_transport_id, - .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id, .tpg_check_demo_mode = usbg_check_true, .tpg_check_demo_mode_cache = usbg_check_false, .tpg_check_demo_mode_write_protect = usbg_check_false, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.h b/drivers/usb/gadget/legacy/tcm_usb_gadget.h index b254aec521da..4c1c22a964b4 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.h +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.h @@ -44,8 +44,6 @@ struct usbg_tpg { }; struct usbg_tport { - /* SCSI protocol the tport is providing */ - u8 tport_proto_id; /* Binary World Wide unique Port Name for SAS Target port */ u64 tport_wwpn; /* ASCII formatted WWPN for SAS Target port */ diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 022860ccd008..db9f4b474214 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -304,97 +304,6 @@ static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 -vhost_scsi_get_pr_transport_id(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); -} - -static u32 -vhost_scsi_get_pr_transport_id_len(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); -} - -static char * -vhost_scsi_parse_pr_out_transport_id(struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct vhost_scsi_tpg *tpg = container_of(se_tpg, - struct vhost_scsi_tpg, se_tpg); - struct vhost_scsi_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_FCP: - return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_ISCSI: - return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using" - " SAS emulation\n", tport->tport_proto_id); - break; - } - - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); -} - static int vhost_scsi_check_prot_fabric_only(struct se_portal_group *se_tpg) { struct vhost_scsi_tpg *tpg = container_of(se_tpg, @@ -2224,9 +2133,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .get_fabric_name = vhost_scsi_get_fabric_name, .tpg_get_wwn = vhost_scsi_get_fabric_wwn, .tpg_get_tag = vhost_scsi_get_tpgt, - .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id, - .tpg_get_pr_transport_id_len = vhost_scsi_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = vhost_scsi_parse_pr_out_transport_id, .tpg_check_demo_mode = vhost_scsi_check_true, .tpg_check_demo_mode_cache = vhost_scsi_check_true, .tpg_check_demo_mode_write_protect = vhost_scsi_check_false, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 8bf9448bd7fd..10c71a5616fa 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1270,97 +1270,6 @@ static u16 scsiback_get_tag(struct se_portal_group *se_tpg) return tpg->tport_tpgt; } -static u32 -scsiback_get_pr_transport_id(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); -} - -static u32 -scsiback_get_pr_transport_id_len(struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_FCP: - return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - case SCSI_PROTOCOL_ISCSI: - return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); -} - -static char * -scsiback_parse_pr_out_transport_id(struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct scsiback_tpg *tpg = container_of(se_tpg, - struct scsiback_tpg, se_tpg); - struct scsiback_tport *tport = tpg->tport; - - switch (tport->tport_proto_id) { - case SCSI_PROTOCOL_SAS: - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_FCP: - return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - case SCSI_PROTOCOL_ISCSI: - return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - default: - pr_err("Unknown tport_proto_id: 0x%02x, using SAS emulation\n", - tport->tport_proto_id); - break; - } - - return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); -} - static struct se_wwn * scsiback_make_tport(struct target_fabric_configfs *tf, struct config_group *group, @@ -1909,9 +1818,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .get_fabric_name = scsiback_get_fabric_name, .tpg_get_wwn = scsiback_get_fabric_wwn, .tpg_get_tag = scsiback_get_tag, - .tpg_get_pr_transport_id = scsiback_get_pr_transport_id, - .tpg_get_pr_transport_id_len = scsiback_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = scsiback_parse_pr_out_transport_id, .tpg_check_demo_mode = scsiback_check_true, .tpg_check_demo_mode_cache = scsiback_check_true, .tpg_check_demo_mode_write_protect = scsiback_check_false, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 495606382546..a420f434c6c5 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -9,15 +9,6 @@ struct target_core_fabric_ops { char *(*tpg_get_wwn)(struct se_portal_group *); u16 (*tpg_get_tag)(struct se_portal_group *); u32 (*tpg_get_default_depth)(struct se_portal_group *); - u32 (*tpg_get_pr_transport_id)(struct se_portal_group *, - struct se_node_acl *, - struct t10_pr_registration *, int *, - unsigned char *); - u32 (*tpg_get_pr_transport_id_len)(struct se_portal_group *, - struct se_node_acl *, - struct t10_pr_registration *, int *); - char *(*tpg_parse_pr_out_transport_id)(struct se_portal_group *, - const char *, u32 *, char **); int (*tpg_check_demo_mode)(struct se_portal_group *); int (*tpg_check_demo_mode_cache)(struct se_portal_group *); int (*tpg_check_demo_mode_write_protect)(struct se_portal_group *); @@ -177,30 +168,6 @@ int core_tpg_register(const struct target_core_fabric_ops *, struct se_wwn *, struct se_portal_group *, int); int core_tpg_deregister(struct se_portal_group *); -/* SAS helpers */ -u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -char *sas_parse_pr_out_transport_id(struct se_portal_group *, const char *, - u32 *, char **); - -/* FC helpers */ -u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -char *fc_parse_pr_out_transport_id(struct se_portal_group *, const char *, - u32 *, char **); - -/* iSCSI helpers */ -u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *, unsigned char *); -u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *, - struct t10_pr_registration *, int *); -char *iscsi_parse_pr_out_transport_id(struct se_portal_group *, const char *, - u32 *, char **); - /* * The LIO target core uses DMA_TO_DEVICE to mean that data is going * to the target (eg handling a WRITE) and DMA_FROM_DEVICE to mean -- cgit v1.2.3 From 649ee05499d1257a3af0e10d961a1c52d9ef95b7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 14 Apr 2015 13:26:44 +0200 Subject: target: Move task tag into struct se_cmd + support 64-bit tags Simplify target core and target drivers by storing the task tag a.k.a. command identifier inside struct se_cmd. For several transports (e.g. SRP) tags are 64 bits wide. Hence add support for 64-bit tags. (Fix core_tmr_abort_task conversion spec warnings - nab) (Fix up usb-gadget to use 16-bit tags - HCH + bart) Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Andy Grover Cc: Sagi Grimberg Cc: Cc: Felipe Balbi Cc: Michael S. Tsirkin Cc: Juergen Gross Signed-off-by: Nicholas Bellinger --- Documentation/target/tcm_mod_builder.py | 8 ----- drivers/infiniband/ulp/srpt/ib_srpt.c | 27 +++++---------- drivers/infiniband/ulp/srpt/ib_srpt.h | 1 - drivers/scsi/qla2xxx/qla_target.c | 52 ++++++++++++---------------- drivers/scsi/qla2xxx/qla_target.h | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 15 -------- drivers/target/iscsi/iscsi_target.c | 2 ++ drivers/target/iscsi/iscsi_target_configfs.c | 9 ----- drivers/target/loopback/tcm_loop.c | 10 +----- drivers/target/sbp/sbp_target.c | 12 ++----- drivers/target/target_core_configfs.c | 4 --- drivers/target/target_core_tmr.c | 21 +++++------ drivers/target/target_core_transport.c | 41 +++++++++++----------- drivers/target/target_core_xcopy.c | 7 +--- drivers/target/tcm_fc/tcm_fc.h | 1 - drivers/target/tcm_fc/tfc_cmd.c | 10 +----- drivers/target/tcm_fc/tfc_conf.c | 1 - drivers/usb/gadget/legacy/tcm_usb_gadget.c | 15 ++------ drivers/vhost/scsi.c | 7 +--- drivers/xen/xen-scsiback.c | 10 +----- include/target/target_core_base.h | 3 +- include/target/target_core_fabric.h | 1 - 22 files changed, 76 insertions(+), 182 deletions(-) (limited to 'include') diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py index 0dbd70cccde1..71e1f5863310 100755 --- a/Documentation/target/tcm_mod_builder.py +++ b/Documentation/target/tcm_mod_builder.py @@ -310,7 +310,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += " .write_pending = " + fabric_mod_name + "_write_pending,\n" buf += " .write_pending_status = " + fabric_mod_name + "_write_pending_status,\n" buf += " .set_default_node_attributes = " + fabric_mod_name + "_set_default_node_attrs,\n" - buf += " .get_task_tag = " + fabric_mod_name + "_get_task_tag,\n" buf += " .get_cmd_state = " + fabric_mod_name + "_get_cmd_state,\n" buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n" buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n" @@ -525,13 +524,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name): buf += "}\n\n" bufi += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *);\n" - if re.search('get_task_tag\)\(', fo): - buf += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *se_cmd)\n" - buf += "{\n" - buf += " return 0;\n" - buf += "}\n\n" - bufi += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *);\n" - if re.search('get_cmd_state\)\(', fo): buf += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *se_cmd)\n" buf += "{\n" diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 98e00360f97e..56df5cd918c5 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1339,7 +1339,7 @@ static int srpt_abort_cmd(struct srpt_send_ioctx *ioctx) } pr_debug("Aborting cmd with state %d and tag %lld\n", state, - ioctx->tag); + ioctx->cmd.tag); switch (state) { case SRPT_STATE_NEW: @@ -1701,7 +1701,7 @@ static int srpt_handle_cmd(struct srpt_rdma_ch *ch, srp_cmd = recv_ioctx->ioctx.buf; cmd = &send_ioctx->cmd; - send_ioctx->tag = srp_cmd->tag; + cmd->tag = srp_cmd->tag; switch (srp_cmd->task_attr) { case SRP_CMD_SIMPLE_Q: @@ -1772,7 +1772,7 @@ static int srpt_rx_mgmt_fn_tag(struct srpt_send_ioctx *ioctx, u64 tag) for (i = 0; i < ch->rq_size; ++i) { target = ch->ioctx_ring[i]; if (target->cmd.se_lun == ioctx->cmd.se_lun && - target->tag == tag && + target->cmd.tag == tag && srpt_get_cmd_state(target) != SRPT_STATE_DONE) { ret = 0; /* now let the target core abort &target->cmd; */ @@ -1831,7 +1831,7 @@ static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch, srp_tsk->task_tag, srp_tsk->tag, ch->cm_id, ch->sess); srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT); - send_ioctx->tag = srp_tsk->tag; + send_ioctx->cmd.tag = srp_tsk->tag; tcm_tmr = srp_tmr_to_tcm(srp_tsk->tsk_mgmt_func); if (tcm_tmr < 0) { send_ioctx->cmd.se_tmr_req->response = @@ -2979,7 +2979,7 @@ static int srpt_write_pending(struct se_cmd *se_cmd) case CH_DRAINING: case CH_RELEASING: pr_debug("cmd with tag %lld: channel disconnecting\n", - ioctx->tag); + ioctx->cmd.tag); srpt_set_cmd_state(ioctx, SRPT_STATE_DATA_IN); ret = -EINVAL; goto out; @@ -3054,24 +3054,24 @@ static void srpt_queue_response(struct se_cmd *cmd) ret = srpt_xfer_data(ch, ioctx); if (ret) { pr_err("xfer_data failed for tag %llu\n", - ioctx->tag); + ioctx->cmd.tag); return; } } if (state != SRPT_STATE_MGMT) - resp_len = srpt_build_cmd_rsp(ch, ioctx, ioctx->tag, + resp_len = srpt_build_cmd_rsp(ch, ioctx, ioctx->cmd.tag, cmd->scsi_status); else { srp_tm_status = tcm_to_srp_tsk_mgmt_status(cmd->se_tmr_req->response); resp_len = srpt_build_tskmgmt_rsp(ch, ioctx, srp_tm_status, - ioctx->tag); + ioctx->cmd.tag); } ret = srpt_post_send(ch, ioctx, resp_len); if (ret) { pr_err("sending cmd response failed for tag %llu\n", - ioctx->tag); + ioctx->cmd.tag); srpt_unmap_sg_to_ib_sge(ch, ioctx); srpt_set_cmd_state(ioctx, SRPT_STATE_DONE); target_put_sess_cmd(&ioctx->cmd); @@ -3479,14 +3479,6 @@ static void srpt_set_default_node_attrs(struct se_node_acl *nacl) { } -static u32 srpt_get_task_tag(struct se_cmd *se_cmd) -{ - struct srpt_send_ioctx *ioctx; - - ioctx = container_of(se_cmd, struct srpt_send_ioctx, cmd); - return ioctx->tag; -} - /* Note: only used from inside debug printk's by the TCM core. */ static int srpt_get_tcm_cmd_state(struct se_cmd *se_cmd) { @@ -3838,7 +3830,6 @@ static const struct target_core_fabric_ops srpt_template = { .write_pending = srpt_write_pending, .write_pending_status = srpt_write_pending_status, .set_default_node_attributes = srpt_set_default_node_attrs, - .get_task_tag = srpt_get_task_tag, .get_cmd_state = srpt_get_tcm_cmd_state, .queue_data_in = srpt_queue_data_in, .queue_status = srpt_queue_status, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 33b2c88b73ba..6fec740742bd 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -238,7 +238,6 @@ struct srpt_send_ioctx { bool rdma_aborted; struct se_cmd cmd; struct completion tx_done; - u64 tag; int sg_cnt; int mapped_sg_count; u16 n_rdma_ius; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index fe8a8d157e22..e7515069e1ce 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1191,7 +1191,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - if (cmd->tag == abts->exchange_addr_to_abort) { + if (se_cmd->tag == abts->exchange_addr_to_abort) { lun = cmd->unpacked_lun; found_lun = true; break; @@ -1728,9 +1728,8 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, if (unlikely(cmd->aborted)) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, - "qla_target(%d): terminating exchange " - "for aborted cmd=%p (se_cmd=%p, tag=%d)", vha->vp_idx, cmd, - se_cmd, cmd->tag); + "qla_target(%d): terminating exchange for aborted cmd=%p (se_cmd=%p, tag=%lld)", + vha->vp_idx, cmd, se_cmd, se_cmd->tag); cmd->state = QLA_TGT_STATE_ABORTED; cmd->cmd_flags |= BIT_6; @@ -1765,18 +1764,17 @@ static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { prm->residual = se_cmd->residual_count; ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x305c, - "Residual underflow: %d (tag %d, " - "op %x, bufflen %d, rq_result %x)\n", prm->residual, - cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->bufflen, prm->rq_result); + "Residual underflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", + prm->residual, se_cmd->tag, + se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, + cmd->bufflen, prm->rq_result); prm->rq_result |= SS_RESIDUAL_UNDER; } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { prm->residual = se_cmd->residual_count; ql_dbg(ql_dbg_io, vha, 0x305d, - "Residual overflow: %d (tag %d, " - "op %x, bufflen %d, rq_result %x)\n", prm->residual, - cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->bufflen, prm->rq_result); + "Residual overflow: %d (tag %lld, op %x, bufflen %d, rq_result %x)\n", + prm->residual, se_cmd->tag, se_cmd->t_task_cdb ? + se_cmd->t_task_cdb[0] : 0, cmd->bufflen, prm->rq_result); prm->rq_result |= SS_RESIDUAL_OVER; } @@ -1849,7 +1847,7 @@ static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) == 50) { *xmit_type &= ~QLA_TGT_XMIT_STATUS; ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf015, - "Dropping cmd %p (tag %d) status", cmd, cmd->tag); + "Dropping cmd %p (tag %d) status", cmd, se_cmd->tag); } #endif /* @@ -1873,7 +1871,7 @@ static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf016, "Cutting cmd %p (tag %d) buffer" " tail to len %d, sg_cnt %d (cmd->bufflen %d," - " cmd->sg_cnt %d)", cmd, cmd->tag, tot_len, leave, + " cmd->sg_cnt %d)", cmd, se_cmd->tag, tot_len, leave, cmd->bufflen, cmd->sg_cnt); cmd->bufflen = tot_len; @@ -1885,13 +1883,13 @@ static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf017, "Cutting cmd %p (tag %d) buffer head " - "to offset %d (cmd->bufflen %d)", cmd, cmd->tag, offset, + "to offset %d (cmd->bufflen %d)", cmd, se_cmd->tag, offset, cmd->bufflen); if (offset == 0) *xmit_type &= ~QLA_TGT_XMIT_DATA; else if (qlt_set_data_offset(cmd, offset)) { ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf018, - "qlt_set_data_offset() failed (tag %d)", cmd->tag); + "qlt_set_data_offset() failed (tag %d)", se_cmd->tag); } } } @@ -3194,7 +3192,7 @@ skip_term: return; } else if (cmd->state == QLA_TGT_STATE_ABORTED) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, - "Aborted command %p (tag %d) finished\n", cmd, cmd->tag); + "Aborted command %p (tag %lld) finished\n", cmd, se_cmd->tag); } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, "qla_target(%d): A command in state (%d) should " @@ -3266,7 +3264,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd) goto out_term; cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; - cmd->tag = atio->u.isp24.exchange_addr; + cmd->se_cmd.tag = atio->u.isp24.exchange_addr; cmd->unpacked_lun = scsilun_to_int( (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); @@ -3891,9 +3889,8 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, resp = 1; } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf064, - "qla_target(%d): SRR for in data for cmd " - "without them (tag %d, SCSI status %d), " - "reject", vha->vp_idx, cmd->tag, + "qla_target(%d): SRR for in data for cmd without them (tag %lld, SCSI status %d), reject", + vha->vp_idx, se_cmd->tag, cmd->se_cmd.scsi_status); goto out_reject; } @@ -3927,10 +3924,8 @@ static void qlt_handle_srr(struct scsi_qla_host *vha, } } else { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf066, - "qla_target(%d): SRR for out data for cmd " - "without them (tag %d, SCSI status %d), " - "reject", vha->vp_idx, cmd->tag, - cmd->se_cmd.scsi_status); + "qla_target(%d): SRR for out data for cmd without them (tag %lld, SCSI status %d), reject", + vha->vp_idx, se_cmd->tag, cmd->se_cmd.scsi_status); goto out_reject; } break; @@ -4051,10 +4046,9 @@ restart: cmd->sg = se_cmd->t_data_sg; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c, - "SRR cmd %p (se_cmd %p, tag %d, op %x), " - "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag, - se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->sg_cnt, cmd->offset); + "SRR cmd %p (se_cmd %p, tag %lld, op %x), sg_cnt=%d, offset=%d", + cmd, &cmd->se_cmd, se_cmd->tag, se_cmd->t_task_cdb ? + se_cmd->t_task_cdb[0] : 0, cmd->sg_cnt, cmd->offset); qlt_handle_srr(vha, sctio, imm); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 332086776dfe..985d76dd706b 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -924,7 +924,6 @@ struct qla_tgt_cmd { int sg_cnt; /* SG segments count */ int bufflen; /* cmd buffer length */ int offset; - uint32_t tag; uint32_t unpacked_lun; enum dma_data_direction dma_data_direction; uint32_t reset_count; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index bd0f9eb67901..8e331220adda 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -421,19 +421,6 @@ static void tcm_qla2xxx_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 tcm_qla2xxx_get_task_tag(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd; - - /* check for task mgmt cmd */ - if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - return 0xffffffff; - - cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - - return cmd->tag; -} - static int tcm_qla2xxx_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -1865,7 +1852,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .write_pending = tcm_qla2xxx_write_pending, .write_pending_status = tcm_qla2xxx_write_pending_status, .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, - .get_task_tag = tcm_qla2xxx_get_task_tag, .get_cmd_state = tcm_qla2xxx_get_cmd_state, .queue_data_in = tcm_qla2xxx_queue_data_in, .queue_status = tcm_qla2xxx_queue_status, @@ -1910,7 +1896,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .write_pending = tcm_qla2xxx_write_pending, .write_pending_status = tcm_qla2xxx_write_pending_status, .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, - .get_task_tag = tcm_qla2xxx_get_task_tag, .get_cmd_state = tcm_qla2xxx_get_cmd_state, .queue_data_in = tcm_qla2xxx_queue_data_in, .queue_status = tcm_qla2xxx_queue_status, diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 866c167c0986..3c4431f71158 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1008,6 +1008,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (cmd->sense_reason) goto attach_cmd; + /* only used for printks or comparing with ->ref_task_tag */ + cmd->se_cmd.tag = (__force u32)cmd->init_task_tag; cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb); if (cmd->sense_reason) { if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) { diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index bd8af8764f4b..aa4fc4d8e176 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1692,14 +1692,6 @@ static char *iscsi_get_fabric_name(void) return "iSCSI"; } -static u32 iscsi_get_task_tag(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - /* only used for printks or comparism with ->ref_task_tag */ - return (__force u32)cmd->init_task_tag; -} - static int iscsi_get_cmd_state(struct se_cmd *se_cmd) { struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); @@ -1938,7 +1930,6 @@ const struct target_core_fabric_ops iscsi_ops = { .write_pending = lio_write_pending, .write_pending_status = lio_write_pending_status, .set_default_node_attributes = lio_set_default_node_attributes, - .get_task_tag = iscsi_get_task_tag, .get_cmd_state = iscsi_get_cmd_state, .queue_data_in = lio_queue_data_in, .queue_status = lio_queue_status, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b788406977f6..07d3b52c88eb 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -165,6 +165,7 @@ static void tcm_loop_submission_work(struct work_struct *work) transfer_length = scsi_bufflen(sc); } + se_cmd->tag = tl_cmd->sc_cmd_tag; rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, transfer_length, TCM_SIMPLE_TAG, @@ -597,14 +598,6 @@ static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) return; } -static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) -{ - struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, - struct tcm_loop_cmd, tl_se_cmd); - - return tl_cmd->sc_cmd_tag; -} - static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) { struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, @@ -1259,7 +1252,6 @@ static const struct target_core_fabric_ops loop_ops = { .write_pending = tcm_loop_write_pending, .write_pending_status = tcm_loop_write_pending_status, .set_default_node_attributes = tcm_loop_set_default_node_attributes, - .get_task_tag = tcm_loop_get_task_tag, .get_cmd_state = tcm_loop_get_cmd_state, .queue_data_in = tcm_loop_queue_data_in, .queue_status = tcm_loop_queue_status, diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 89f172dc8678..2916a4023e71 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1234,6 +1234,8 @@ static void sbp_handle_command(struct sbp_target_request *req) pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", req->orb_pointer, unpacked_lun, data_length, data_dir); + /* only used for printk until we do TMRs */ + req->se_cmd.tag = req->orb_pointer; if (target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf, req->sense_buf, unpacked_lun, data_length, TCM_SIMPLE_TAG, data_dir, 0)) @@ -1768,15 +1770,6 @@ static void sbp_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 sbp_get_task_tag(struct se_cmd *se_cmd) -{ - struct sbp_target_request *req = container_of(se_cmd, - struct sbp_target_request, se_cmd); - - /* only used for printk until we do TMRs */ - return (u32)req->orb_pointer; -} - static int sbp_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -2377,7 +2370,6 @@ static const struct target_core_fabric_ops sbp_ops = { .write_pending = sbp_write_pending, .write_pending_status = sbp_write_pending_status, .set_default_node_attributes = sbp_set_default_node_attrs, - .get_task_tag = sbp_get_task_tag, .get_cmd_state = sbp_get_cmd_state, .queue_data_in = sbp_queue_data_in, .queue_status = sbp_queue_status, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 5e2649fc6919..fc598c084523 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -374,10 +374,6 @@ static int target_fabric_tf_ops_check(const struct target_core_fabric_ops *tfo) pr_err("Missing tfo->set_default_node_attributes()\n"); return -EINVAL; } - if (!tfo->get_task_tag) { - pr_err("Missing tfo->get_task_tag()\n"); - return -EINVAL; - } if (!tfo->get_cmd_state) { pr_err("Missing tfo->get_cmd_state()\n"); return -EINVAL; diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index b2e169fba3c6..393aca8bb3eb 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -117,7 +117,7 @@ void core_tmr_abort_task( { struct se_cmd *se_cmd; unsigned long flags; - int ref_tag; + u64 ref_tag; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) { @@ -129,16 +129,17 @@ void core_tmr_abort_task( if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) continue; - ref_tag = se_cmd->se_tfo->get_task_tag(se_cmd); + ref_tag = se_cmd->tag; if (tmr->ref_task_tag != ref_tag) continue; - printk("ABORT_TASK: Found referenced %s task_tag: %u\n", + printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); spin_lock(&se_cmd->t_state_lock); if (se_cmd->transport_state & CMD_T_COMPLETE) { - printk("ABORT_TASK: ref_tag: %u already complete, skipping\n", ref_tag); + printk("ABORT_TASK: ref_tag: %llu already complete," + " skipping\n", ref_tag); spin_unlock(&se_cmd->t_state_lock); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); goto out; @@ -157,14 +158,14 @@ void core_tmr_abort_task( transport_cmd_finish_abort(se_cmd, true); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" - " ref_tag: %d\n", ref_tag); + " ref_tag: %llu\n", ref_tag); tmr->response = TMR_FUNCTION_COMPLETE; return; } spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); out: - printk("ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST for ref_tag: %d\n", + printk("ABORT_TASK: Sending TMR_TASK_DOES_NOT_EXIST for ref_tag: %lld\n", tmr->ref_task_tag); tmr->response = TMR_TASK_DOES_NOT_EXIST; } @@ -289,16 +290,16 @@ static void core_tmr_drain_state_list( list_del(&cmd->state_list); pr_debug("LUN_RESET: %s cmd: %p" - " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state: %d" + " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d" "cdb: 0x%02x\n", (preempt_and_abort_list) ? "Preempt" : "", cmd, - cmd->se_tfo->get_task_tag(cmd), 0, + cmd->tag, 0, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, cmd->t_task_cdb[0]); - pr_debug("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx" + pr_debug("LUN_RESET: ITT[0x%08llx] - pr_res_key: 0x%016Lx" " -- CMD_T_ACTIVE: %d" " CMD_T_STOP: %d CMD_T_SENT: %d\n", - cmd->se_tfo->get_task_tag(cmd), cmd->pr_res_key, + cmd->tag, cmd->pr_res_key, (cmd->transport_state & CMD_T_ACTIVE) != 0, (cmd->transport_state & CMD_T_STOP) != 0, (cmd->transport_state & CMD_T_SENT) != 0); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 85b021e749e6..0d8662bb470e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -600,9 +600,8 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, * this command for frontend exceptions. */ if (cmd->transport_state & CMD_T_STOP) { - pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", - __func__, __LINE__, - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", + __func__, __LINE__, cmd->tag); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -1155,6 +1154,8 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) /* * Used by fabric modules containing a local struct se_cmd within their * fabric dependent per I/O descriptor. + * + * Preserves the value of @cmd->tag. */ void transport_init_se_cmd( struct se_cmd *cmd, @@ -1380,6 +1381,8 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, * @sgl_prot: struct scatterlist memory protection information * @sgl_prot_count: scatterlist count for protection information * + * Task tags are supported if the caller has set @se_cmd->tag. + * * Returns non zero to signal active I/O shutdown failure. All other * setup exceptions will be returned as a SCSI CHECK_CONDITION response, * but still return zero here. @@ -1512,6 +1515,8 @@ EXPORT_SYMBOL(target_submit_cmd_map_sgls); * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables * + * Task tags are supported if the caller has set @se_cmd->tag. + * * Returns non zero to signal active I/O shutdown failure. All other * setup exceptions will be returned as a SCSI CHECK_CONDITION response, * but still return zero here. @@ -1639,9 +1644,8 @@ void transport_generic_request_failure(struct se_cmd *cmd, { int ret = 0; - pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x" - " CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd), - cmd->t_task_cdb[0]); + pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx" + " CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]); pr_debug("-----[ i_state: %d t_state: %d sense_reason: %d\n", cmd->se_tfo->get_cmd_state(cmd), cmd->t_state, sense_reason); @@ -1849,9 +1853,8 @@ void target_execute_cmd(struct se_cmd *cmd) */ spin_lock_irq(&cmd->t_state_lock); if (cmd->transport_state & CMD_T_STOP) { - pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08x\n", - __func__, __LINE__, - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", + __func__, __LINE__, cmd->tag); spin_unlock_irq(&cmd->t_state_lock); complete_all(&cmd->t_transport_stop_comp); @@ -2658,10 +2661,8 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) cmd->transport_state |= CMD_T_STOP; - pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08x" - " i_state: %d, t_state: %d, CMD_T_STOP\n", - cmd, cmd->se_tfo->get_task_tag(cmd), - cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); + pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n", + cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2670,9 +2671,8 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); - pr_debug("wait_for_tasks: Stopped wait_for_completion(" - "&cmd->t_transport_stop_comp) for ITT: 0x%08x\n", - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n", + cmd->tag); spin_unlock_irqrestore(&cmd->t_state_lock, flags); @@ -2974,8 +2974,8 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status) if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) return 1; - pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", - cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); + pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n", + cmd->t_task_cdb[0], cmd->tag); cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; cmd->scsi_status = SAM_STAT_TASK_ABORTED; @@ -3014,9 +3014,8 @@ void transport_send_task_abort(struct se_cmd *cmd) transport_lun_remove_cmd(cmd); - pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x," - " ITT: 0x%08x\n", cmd->t_task_cdb[0], - cmd->se_tfo->get_task_tag(cmd)); + pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x, ITT: 0x%08llx\n", + cmd->t_task_cdb[0], cmd->tag); trace_target_cmd_complete(cmd); cmd->se_tfo->queue_status(cmd); diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 8fd680ac941b..5545619d3045 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -359,11 +359,6 @@ static char *xcopy_pt_get_fabric_name(void) return "xcopy-pt"; } -static u32 xcopy_pt_get_tag(struct se_cmd *se_cmd) -{ - return 0; -} - static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -424,7 +419,6 @@ static int xcopy_pt_queue_status(struct se_cmd *se_cmd) static const struct target_core_fabric_ops xcopy_pt_tfo = { .get_fabric_name = xcopy_pt_get_fabric_name, - .get_task_tag = xcopy_pt_get_tag, .get_cmd_state = xcopy_pt_get_cmd_state, .release_cmd = xcopy_pt_release_cmd, .check_stop_free = xcopy_pt_check_stop_free, @@ -575,6 +569,7 @@ static int target_xcopy_setup_pt_cmd( xpt_cmd->xcopy_op = xop; target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port); + cmd->tag = 0; sense_rc = target_setup_cmd_from_cdb(cmd, cdb); if (sense_rc) { ret = -EINVAL; diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index 4ceaeb9a4b93..39909dadef3e 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -157,7 +157,6 @@ int ft_queue_status(struct se_cmd *); int ft_queue_data_in(struct se_cmd *); int ft_write_pending(struct se_cmd *); int ft_write_pending_status(struct se_cmd *); -u32 ft_get_task_tag(struct se_cmd *); int ft_get_cmd_state(struct se_cmd *); void ft_queue_tm_resp(struct se_cmd *); void ft_aborted_task(struct se_cmd *); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index edcafa4490c0..a8fe6ed5262f 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -247,15 +247,6 @@ int ft_write_pending(struct se_cmd *se_cmd) return 0; } -u32 ft_get_task_tag(struct se_cmd *se_cmd) -{ - struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); - - if (cmd->aborted) - return ~0; - return fc_seq_exch(cmd->seq)->rxid; -} - int ft_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -568,6 +559,7 @@ static void ft_send_work(struct work_struct *work) } fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd); + cmd->se_cmd.tag = fc_seq_exch(cmd->seq)->rxid; /* * Use a single se_cmd->cmd_kref as we expect to release se_cmd * directly from ft_check_stop_free callback in response path. diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 6ad7404b7dd1..f0821967f0a1 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -468,7 +468,6 @@ static const struct target_core_fabric_ops ft_fabric_ops = { .write_pending = ft_write_pending, .write_pending_status = ft_write_pending_status, .set_default_node_attributes = ft_set_default_node_attr, - .get_task_tag = ft_get_task_tag, .get_cmd_state = ft_get_cmd_state, .queue_data_in = ft_queue_data_in, .queue_status = ft_queue_status, diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 77cdbb56e1d5..a000d89dc78a 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -1112,6 +1112,7 @@ static int usbg_submit_command(struct f_uas *fu, memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); cmd->tag = be16_to_cpup(&cmd_iu->tag); + cmd->se_cmd.tag = cmd->tag; if (fu->flags & USBG_USE_STREAMS) { if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) goto err; @@ -1245,6 +1246,7 @@ static int bot_submit_command(struct f_uas *fu, cmd->unpacked_lun = cbw->Lun; cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; cmd->data_len = le32_to_cpu(cbw->DataTransferLength); + cmd->se_cmd.tag = le32_to_cpu(cmd->bot_tag); INIT_WORK(&cmd->work, bot_cmd_work); ret = queue_work(tpg->workqueue, &cmd->work); @@ -1340,18 +1342,6 @@ static void usbg_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 usbg_get_task_tag(struct se_cmd *se_cmd) -{ - struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, - se_cmd); - struct f_uas *fu = cmd->fu; - - if (fu->flags & USBG_IS_BOT) - return le32_to_cpu(cmd->bot_tag); - else - return cmd->tag; -} - static int usbg_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -1739,7 +1729,6 @@ static const struct target_core_fabric_ops usbg_ops = { .write_pending = usbg_send_write_request, .write_pending_status = usbg_write_pending_status, .set_default_node_attributes = usbg_set_default_node_attrs, - .get_task_tag = usbg_get_task_tag, .get_cmd_state = usbg_get_cmd_state, .queue_data_in = usbg_send_read_response, .queue_status = usbg_send_status_response, diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index db9f4b474214..4a003948b07f 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -369,11 +369,6 @@ static void vhost_scsi_set_default_node_attrs(struct se_node_acl *nacl) return; } -static u32 vhost_scsi_get_task_tag(struct se_cmd *se_cmd) -{ - return 0; -} - static int vhost_scsi_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -818,6 +813,7 @@ static void vhost_scsi_submission_work(struct work_struct *work) } tv_nexus = cmd->tvc_nexus; + se_cmd->tag = 0; rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess, cmd->tvc_cdb, &cmd->tvc_sense_buf[0], cmd->tvc_lun, cmd->tvc_exp_data_len, @@ -2148,7 +2144,6 @@ static struct target_core_fabric_ops vhost_scsi_ops = { .write_pending = vhost_scsi_write_pending, .write_pending_status = vhost_scsi_write_pending_status, .set_default_node_attributes = vhost_scsi_set_default_node_attrs, - .get_task_tag = vhost_scsi_get_task_tag, .get_cmd_state = vhost_scsi_get_cmd_state, .queue_data_in = vhost_scsi_queue_data_in, .queue_status = vhost_scsi_queue_status, diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 10c71a5616fa..ea929baf7ad0 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -400,6 +400,7 @@ static void scsiback_cmd_exec(struct vscsibk_pend *pending_req) memset(se_cmd, 0, sizeof(*se_cmd)); scsiback_get(pending_req->info); + se_cmd->tag = pending_req->rqid; rc = target_submit_cmd_map_sgls(se_cmd, sess, pending_req->cmnd, pending_req->sense_buffer, pending_req->v2p->lun, pending_req->data_len, 0, @@ -1394,14 +1395,6 @@ static void scsiback_set_default_node_attrs(struct se_node_acl *nacl) { } -static u32 scsiback_get_task_tag(struct se_cmd *se_cmd) -{ - struct vscsibk_pend *pending_req = container_of(se_cmd, - struct vscsibk_pend, se_cmd); - - return pending_req->rqid; -} - static int scsiback_get_cmd_state(struct se_cmd *se_cmd) { return 0; @@ -1833,7 +1826,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .write_pending = scsiback_write_pending, .write_pending_status = scsiback_write_pending_status, .set_default_node_attributes = scsiback_set_default_node_attrs, - .get_task_tag = scsiback_get_task_tag, .get_cmd_state = scsiback_get_cmd_state, .queue_data_in = scsiback_queue_data_in, .queue_status = scsiback_queue_status, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c462fb0a47f4..042a73464966 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -420,7 +420,7 @@ struct se_tmr_req { u8 response; int call_transport; /* Reference to ITT that Task Mgmt should be performed */ - u32 ref_task_tag; + u64 ref_task_tag; void *fabric_tmr_ptr; struct se_cmd *task_cmd; struct se_device *tmr_dev; @@ -473,6 +473,7 @@ struct se_cmd { u8 scsi_asc; u8 scsi_ascq; u16 scsi_sense_length; + u64 tag; /* SAM command identifier aka task tag */ /* Delay for ALUA Active/NonOptimized state access in milliseconds */ int alua_nonop_delay; /* See include/linux/dma-mapping.h */ diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index a420f434c6c5..f64d493f888b 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -53,7 +53,6 @@ struct target_core_fabric_ops { int (*write_pending)(struct se_cmd *); int (*write_pending_status)(struct se_cmd *); void (*set_default_node_attributes)(struct se_node_acl *); - u32 (*get_task_tag)(struct se_cmd *); int (*get_cmd_state)(struct se_cmd *); int (*queue_data_in)(struct se_cmd *); int (*queue_status)(struct se_cmd *); -- cgit v1.2.3 From ef0caf8dd149992796ee453b65dd0d77ff848f57 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:53 +0200 Subject: target: don't copy fabric ops Now that we don't need to set up ->tf_subsys we don't need to copy around the ops vector anymore. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 2 +- drivers/target/target_core_fabric_configfs.c | 38 ++++++++++++++-------------- include/target/target_core_configfs.h | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 86caeb26f996..43c9ed1d1b92 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -444,7 +444,7 @@ int target_register_template(const struct target_core_fabric_ops *fo) tf->tf_module = fo->module; snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); - tf->tf_ops = *fo; + tf->tf_ops = fo; target_fabric_setup_cits(tf); mutex_lock(&g_tf_lock); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index f4d9467c3e14..93564c0b7576 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -61,7 +61,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) { \ struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ - struct configfs_attribute **attrs = tf->tf_ops.tfc_##_name##_attrs; \ + struct configfs_attribute **attrs = tf->tf_ops->tfc_##_name##_attrs; \ \ cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ @@ -460,8 +460,8 @@ static void target_fabric_nacl_base_release(struct config_item *item) struct se_node_acl, acl_group); struct target_fabric_configfs *tf = se_nacl->se_tpg->se_tpg_wwn->wwn_tf; - if (tf->tf_ops.fabric_cleanup_nodeacl) - tf->tf_ops.fabric_cleanup_nodeacl(se_nacl); + if (tf->tf_ops->fabric_cleanup_nodeacl) + tf->tf_ops->fabric_cleanup_nodeacl(se_nacl); core_tpg_del_initiator_node_acl(se_nacl); } @@ -506,8 +506,8 @@ static struct config_group *target_fabric_make_nodeacl( if (IS_ERR(se_nacl)) return ERR_CAST(se_nacl); - if (tf->tf_ops.fabric_init_nodeacl) { - int ret = tf->tf_ops.fabric_init_nodeacl(se_nacl, name); + if (tf->tf_ops->fabric_init_nodeacl) { + int ret = tf->tf_ops->fabric_init_nodeacl(se_nacl, name); if (ret) { core_tpg_del_initiator_node_acl(se_nacl); return ERR_PTR(ret); @@ -579,7 +579,7 @@ static void target_fabric_np_base_release(struct config_item *item) struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - tf->tf_ops.fabric_drop_np(se_tpg_np); + tf->tf_ops->fabric_drop_np(se_tpg_np); } static struct configfs_item_operations target_fabric_np_base_item_ops = { @@ -603,12 +603,12 @@ static struct config_group *target_fabric_make_np( struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_tpg_np *se_tpg_np; - if (!tf->tf_ops.fabric_make_np) { + if (!tf->tf_ops->fabric_make_np) { pr_err("tf->tf_ops.fabric_make_np is NULL\n"); return ERR_PTR(-ENOSYS); } - se_tpg_np = tf->tf_ops.fabric_make_np(se_tpg, group, name); + se_tpg_np = tf->tf_ops->fabric_make_np(se_tpg, group, name); if (!se_tpg_np || IS_ERR(se_tpg_np)) return ERR_PTR(-EINVAL); @@ -808,13 +808,13 @@ static int target_fabric_port_link( goto out; } - if (tf->tf_ops.fabric_post_link) { + if (tf->tf_ops->fabric_post_link) { /* * Call the optional fabric_post_link() to allow a * fabric module to setup any additional state once * core_dev_add_lun() has been called.. */ - tf->tf_ops.fabric_post_link(se_tpg, lun); + tf->tf_ops->fabric_post_link(se_tpg, lun); } return 0; @@ -831,13 +831,13 @@ static int target_fabric_port_unlink( struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - if (tf->tf_ops.fabric_pre_unlink) { + if (tf->tf_ops->fabric_pre_unlink) { /* * Call the optional fabric_pre_unlink() to allow a * fabric module to release any additional stat before * core_dev_del_lun() is called. */ - tf->tf_ops.fabric_pre_unlink(se_tpg, lun); + tf->tf_ops->fabric_pre_unlink(se_tpg, lun); } core_dev_del_lun(se_tpg, lun); @@ -1027,7 +1027,7 @@ static void target_fabric_tpg_release(struct config_item *item) struct se_wwn *wwn = se_tpg->se_tpg_wwn; struct target_fabric_configfs *tf = wwn->wwn_tf; - tf->tf_ops.fabric_drop_tpg(se_tpg); + tf->tf_ops->fabric_drop_tpg(se_tpg); } static struct configfs_item_operations target_fabric_tpg_base_item_ops = { @@ -1050,12 +1050,12 @@ static struct config_group *target_fabric_make_tpg( struct target_fabric_configfs *tf = wwn->wwn_tf; struct se_portal_group *se_tpg; - if (!tf->tf_ops.fabric_make_tpg) { - pr_err("tf->tf_ops.fabric_make_tpg is NULL\n"); + if (!tf->tf_ops->fabric_make_tpg) { + pr_err("tf->tf_ops->fabric_make_tpg is NULL\n"); return ERR_PTR(-ENOSYS); } - se_tpg = tf->tf_ops.fabric_make_tpg(wwn, group, name); + se_tpg = tf->tf_ops->fabric_make_tpg(wwn, group, name); if (!se_tpg || IS_ERR(se_tpg)) return ERR_PTR(-EINVAL); /* @@ -1116,7 +1116,7 @@ static void target_fabric_release_wwn(struct config_item *item) struct se_wwn, wwn_group); struct target_fabric_configfs *tf = wwn->wwn_tf; - tf->tf_ops.fabric_drop_wwn(wwn); + tf->tf_ops->fabric_drop_wwn(wwn); } static struct configfs_item_operations target_fabric_tpg_item_ops = { @@ -1152,12 +1152,12 @@ static struct config_group *target_fabric_make_wwn( struct target_fabric_configfs, tf_group); struct se_wwn *wwn; - if (!tf->tf_ops.fabric_make_wwn) { + if (!tf->tf_ops->fabric_make_wwn) { pr_err("tf->tf_ops.fabric_make_wwn is NULL\n"); return ERR_PTR(-ENOSYS); } - wwn = tf->tf_ops.fabric_make_wwn(tf, group, name); + wwn = tf->tf_ops->fabric_make_wwn(tf, group, name); if (!wwn || IS_ERR(wwn)) return ERR_PTR(-EINVAL); diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index b99c01170392..10402e5526e7 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -42,7 +42,7 @@ struct target_fabric_configfs { struct config_item_type *tf_fabric_cit; /* Pointer to fabric's struct module */ struct module *tf_module; - struct target_core_fabric_ops tf_ops; + const struct target_core_fabric_ops *tf_ops; struct target_fabric_configfs_template tf_cit_tmpl; }; -- cgit v1.2.3 From 0dc2e8d1435318dc448ac390d6d31e6cd2516684 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:54 +0200 Subject: target: put struct target_fabric_configfs on a diet Remove all fields that are either unused or can be replaced by trivially following pointers. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 24 ++++-------------------- drivers/target/target_core_fabric_configfs.c | 4 ++-- include/target/target_core_configfs.h | 7 ------- 3 files changed, 6 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 43c9ed1d1b92..f63e4dda8a90 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -116,7 +116,7 @@ static struct target_fabric_configfs *target_core_get_fabric( mutex_lock(&g_tf_lock); list_for_each_entry(tf, &g_tf_list, tf_list) { - if (!strcmp(tf->tf_name, name)) { + if (!strcmp(tf->tf_ops->name, name)) { atomic_inc(&tf->tf_access_cnt); mutex_unlock(&g_tf_lock); return tf; @@ -193,7 +193,7 @@ static struct config_group *target_core_register_fabric( return ERR_PTR(-EINVAL); } pr_debug("Target_Core_ConfigFS: REGISTER -> Located fabric:" - " %s\n", tf->tf_name); + " %s\n", tf->tf_ops->name); /* * On a successful target_core_get_fabric() look, the returned * struct target_fabric_configfs *tf will contain a usage reference. @@ -212,10 +212,6 @@ static struct config_group *target_core_register_fabric( pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" " %s\n", tf->tf_group.cg_item.ci_name); - tf->tf_fabric = &tf->tf_group.cg_item; - pr_debug("Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric" - " for %s\n", name); - return &tf->tf_group; } @@ -236,13 +232,9 @@ static void target_core_deregister_fabric( " tf list\n", config_item_name(item)); pr_debug("Target_Core_ConfigFS: DEREGISTER -> located fabric:" - " %s\n", tf->tf_name); + " %s\n", tf->tf_ops->name); atomic_dec(&tf->tf_access_cnt); - pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing" - " tf->tf_fabric for %s\n", tf->tf_name); - tf->tf_fabric = NULL; - pr_debug("Target_Core_ConfigFS: DEREGISTER -> Releasing ci" " %s\n", config_item_name(item)); @@ -436,14 +428,6 @@ int target_register_template(const struct target_core_fabric_ops *fo) INIT_LIST_HEAD(&tf->tf_list); atomic_set(&tf->tf_access_cnt, 0); - - /* - * Setup the default generic struct config_item_type's (cits) in - * struct target_fabric_configfs->tf_cit_tmpl - */ - tf->tf_module = fo->module; - snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", fo->name); - tf->tf_ops = fo; target_fabric_setup_cits(tf); @@ -461,7 +445,7 @@ void target_unregister_template(const struct target_core_fabric_ops *fo) mutex_lock(&g_tf_lock); list_for_each_entry(t, &g_tf_list, tf_list) { - if (!strcmp(t->tf_name, fo->name)) { + if (!strcmp(t->tf_ops->name, fo->name)) { BUG_ON(atomic_read(&t->tf_access_cnt)); list_del(&t->tf_list); kfree(t); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 93564c0b7576..d2ce61a07afd 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -52,7 +52,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ cit->ct_attrs = _attrs; \ - cit->ct_owner = tf->tf_module; \ + cit->ct_owner = tf->tf_ops->module; \ pr_debug("Setup generic %s\n", __stringify(_name)); \ } @@ -66,7 +66,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ cit->ct_attrs = attrs; \ - cit->ct_owner = tf->tf_module; \ + cit->ct_owner = tf->tf_ops->module; \ pr_debug("Setup generic %s\n", __stringify(_name)); \ } diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 10402e5526e7..3f11d2ead63d 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -30,18 +30,11 @@ struct target_fabric_configfs_template { }; struct target_fabric_configfs { - char tf_name[TARGET_FABRIC_NAME_SIZE]; atomic_t tf_access_cnt; struct list_head tf_list; struct config_group tf_group; struct config_group tf_disc_group; struct config_group *tf_default_groups[2]; - /* Pointer to fabric's config_item */ - struct config_item *tf_fabric; - /* Passed from fabric modules */ - struct config_item_type *tf_fabric_cit; - /* Pointer to fabric's struct module */ - struct module *tf_module; const struct target_core_fabric_ops *tf_ops; struct target_fabric_configfs_template tf_cit_tmpl; }; -- cgit v1.2.3 From 968ebe752035d14a4c2bb69f8ed0ddf7292dd2f9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:50:55 +0200 Subject: target: remove struct target_fabric_configfs_template It's only embedded into struct target_fabric_configfs these days, so we might as well remove this layer of abstraction. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 7 ++-- drivers/target/target_core_fabric_configfs.c | 46 ++++++++++++-------------- include/target/target_core_configfs.h | 48 +++++++++++++--------------- 3 files changed, 46 insertions(+), 55 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index f63e4dda8a90..798386a1b6e7 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -199,16 +199,15 @@ static struct config_group *target_core_register_fabric( * struct target_fabric_configfs *tf will contain a usage reference. */ pr_debug("Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n", - &tf->tf_cit_tmpl.tfc_wwn_cit); + &tf->tf_wwn_cit); tf->tf_group.default_groups = tf->tf_default_groups; tf->tf_group.default_groups[0] = &tf->tf_disc_group; tf->tf_group.default_groups[1] = NULL; - config_group_init_type_name(&tf->tf_group, name, - &tf->tf_cit_tmpl.tfc_wwn_cit); + config_group_init_type_name(&tf->tf_group, name, &tf->tf_wwn_cit); config_group_init_type_name(&tf->tf_disc_group, "discovery_auth", - &tf->tf_cit_tmpl.tfc_discovery_cit); + &tf->tf_discovery_cit); pr_debug("Target_Core_ConfigFS: REGISTER -> Allocated Fabric:" " %s\n", tf->tf_group.cg_item.ci_name); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index d2ce61a07afd..6cb4828308e9 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -46,8 +46,7 @@ #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ { \ - struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ - struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + struct config_item_type *cit = &tf->tf_##_name##_cit; \ \ cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ @@ -59,8 +58,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) #define TF_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ { \ - struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \ - struct config_item_type *cit = &tfc->tfc_##_name##_cit; \ + struct config_item_type *cit = &tf->tf_##_name##_cit; \ struct configfs_attribute **attrs = tf->tf_ops->tfc_##_name##_attrs; \ \ cit->ct_item_ops = _item_ops; \ @@ -399,9 +397,9 @@ static struct config_group *target_fabric_make_mappedlun( } config_group_init_type_name(&lacl->se_lun_group, name, - &tf->tf_cit_tmpl.tfc_tpg_mappedlun_cit); + &tf->tf_tpg_mappedlun_cit); config_group_init_type_name(&lacl->ml_stat_grps.stat_group, - "statistics", &tf->tf_cit_tmpl.tfc_tpg_mappedlun_stat_cit); + "statistics", &tf->tf_tpg_mappedlun_stat_cit); lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; lacl_cg->default_groups[1] = NULL; @@ -523,16 +521,15 @@ static struct config_group *target_fabric_make_nodeacl( nacl_cg->default_groups[4] = NULL; config_group_init_type_name(&se_nacl->acl_group, name, - &tf->tf_cit_tmpl.tfc_tpg_nacl_base_cit); + &tf->tf_tpg_nacl_base_cit); config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib", - &tf->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit); + &tf->tf_tpg_nacl_attrib_cit); config_group_init_type_name(&se_nacl->acl_auth_group, "auth", - &tf->tf_cit_tmpl.tfc_tpg_nacl_auth_cit); + &tf->tf_tpg_nacl_auth_cit); config_group_init_type_name(&se_nacl->acl_param_group, "param", - &tf->tf_cit_tmpl.tfc_tpg_nacl_param_cit); + &tf->tf_tpg_nacl_param_cit); config_group_init_type_name(&se_nacl->acl_fabric_stat_group, - "fabric_statistics", - &tf->tf_cit_tmpl.tfc_tpg_nacl_stat_cit); + "fabric_statistics", &tf->tf_tpg_nacl_stat_cit); return &se_nacl->acl_group; } @@ -614,7 +611,7 @@ static struct config_group *target_fabric_make_np( se_tpg_np->tpg_np_parent = se_tpg; config_group_init_type_name(&se_tpg_np->tpg_np_group, name, - &tf->tf_cit_tmpl.tfc_tpg_np_base_cit); + &tf->tf_tpg_np_base_cit); return &se_tpg_np->tpg_np_group; } @@ -918,9 +915,9 @@ static struct config_group *target_fabric_make_lun( } config_group_init_type_name(&lun->lun_group, name, - &tf->tf_cit_tmpl.tfc_tpg_port_cit); + &tf->tf_tpg_port_cit); config_group_init_type_name(&lun->port_stat_grps.stat_group, - "statistics", &tf->tf_cit_tmpl.tfc_tpg_port_stat_cit); + "statistics", &tf->tf_tpg_port_stat_cit); lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; lun_cg->default_groups[1] = NULL; @@ -1071,19 +1068,19 @@ static struct config_group *target_fabric_make_tpg( se_tpg->tpg_group.default_groups[6] = NULL; config_group_init_type_name(&se_tpg->tpg_group, name, - &tf->tf_cit_tmpl.tfc_tpg_base_cit); + &tf->tf_tpg_base_cit); config_group_init_type_name(&se_tpg->tpg_lun_group, "lun", - &tf->tf_cit_tmpl.tfc_tpg_lun_cit); + &tf->tf_tpg_lun_cit); config_group_init_type_name(&se_tpg->tpg_np_group, "np", - &tf->tf_cit_tmpl.tfc_tpg_np_cit); + &tf->tf_tpg_np_cit); config_group_init_type_name(&se_tpg->tpg_acl_group, "acls", - &tf->tf_cit_tmpl.tfc_tpg_nacl_cit); + &tf->tf_tpg_nacl_cit); config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib", - &tf->tf_cit_tmpl.tfc_tpg_attrib_cit); + &tf->tf_tpg_attrib_cit); config_group_init_type_name(&se_tpg->tpg_auth_group, "auth", - &tf->tf_cit_tmpl.tfc_tpg_auth_cit); + &tf->tf_tpg_auth_cit); config_group_init_type_name(&se_tpg->tpg_param_group, "param", - &tf->tf_cit_tmpl.tfc_tpg_param_cit); + &tf->tf_tpg_param_cit); return &se_tpg->tpg_group; } @@ -1169,10 +1166,9 @@ static struct config_group *target_fabric_make_wwn( wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; wwn->wwn_group.default_groups[1] = NULL; - config_group_init_type_name(&wwn->wwn_group, name, - &tf->tf_cit_tmpl.tfc_tpg_cit); + config_group_init_type_name(&wwn->wwn_group, name, &tf->tf_tpg_cit); config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", - &tf->tf_cit_tmpl.tfc_wwn_fabric_stats_cit); + &tf->tf_wwn_fabric_stats_cit); return &wwn->wwn_group; } diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 3f11d2ead63d..abd063b8b301 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -5,30 +5,6 @@ #define TARGET_CORE_NAME_MAX_LEN 64 #define TARGET_FABRIC_NAME_SIZE 32 -struct target_fabric_configfs_template { - struct config_item_type tfc_discovery_cit; - struct config_item_type tfc_wwn_cit; - struct config_item_type tfc_wwn_fabric_stats_cit; - struct config_item_type tfc_tpg_cit; - struct config_item_type tfc_tpg_base_cit; - struct config_item_type tfc_tpg_lun_cit; - struct config_item_type tfc_tpg_port_cit; - struct config_item_type tfc_tpg_port_stat_cit; - struct config_item_type tfc_tpg_np_cit; - struct config_item_type tfc_tpg_np_base_cit; - struct config_item_type tfc_tpg_attrib_cit; - struct config_item_type tfc_tpg_auth_cit; - struct config_item_type tfc_tpg_param_cit; - struct config_item_type tfc_tpg_nacl_cit; - struct config_item_type tfc_tpg_nacl_base_cit; - struct config_item_type tfc_tpg_nacl_attrib_cit; - struct config_item_type tfc_tpg_nacl_auth_cit; - struct config_item_type tfc_tpg_nacl_param_cit; - struct config_item_type tfc_tpg_nacl_stat_cit; - struct config_item_type tfc_tpg_mappedlun_cit; - struct config_item_type tfc_tpg_mappedlun_stat_cit; -}; - struct target_fabric_configfs { atomic_t tf_access_cnt; struct list_head tf_list; @@ -36,6 +12,26 @@ struct target_fabric_configfs { struct config_group tf_disc_group; struct config_group *tf_default_groups[2]; const struct target_core_fabric_ops *tf_ops; - struct target_fabric_configfs_template tf_cit_tmpl; -}; + struct config_item_type tf_discovery_cit; + struct config_item_type tf_wwn_cit; + struct config_item_type tf_wwn_fabric_stats_cit; + struct config_item_type tf_tpg_cit; + struct config_item_type tf_tpg_base_cit; + struct config_item_type tf_tpg_lun_cit; + struct config_item_type tf_tpg_port_cit; + struct config_item_type tf_tpg_port_stat_cit; + struct config_item_type tf_tpg_np_cit; + struct config_item_type tf_tpg_np_base_cit; + struct config_item_type tf_tpg_attrib_cit; + struct config_item_type tf_tpg_auth_cit; + struct config_item_type tf_tpg_param_cit; + struct config_item_type tf_tpg_nacl_cit; + struct config_item_type tf_tpg_nacl_base_cit; + struct config_item_type tf_tpg_nacl_attrib_cit; + struct config_item_type tf_tpg_nacl_auth_cit; + struct config_item_type tf_tpg_nacl_param_cit; + struct config_item_type tf_tpg_nacl_stat_cit; + struct config_item_type tf_tpg_mappedlun_cit; + struct config_item_type tf_tpg_mappedlun_stat_cit; +}; -- cgit v1.2.3 From afe92323f9df4a2c4a093cd3f2a3f82800498596 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 3 May 2015 08:54:42 +0200 Subject: target: remove ->put_session method The only instance of ->put_session is in qla2xxx, and was added by commit aaf68b ("tcm_qla2xxx: Convert to TFO->put_session() usage") with the following description: This patch converts tcm_qla2xxx code to use an internal kref_put() for se_session->sess_kref in order to ensure that qla_hw_data->hardware_lock can be held while calling qlt_unreg_sess() for the final put. But these day we're already holding the hardware lock over qlt_unreg_sess in the ->close_session callback, so we're fine without this method. (Re-add missing tcm_qla2xxx_release_session + drop put_session usage - nab) Signed-off-by: Christoph Hellwig Acked-by: Himanshu Madhani Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 13 ------------- drivers/target/target_core_transport.c | 6 ------ drivers/xen/xen-scsiback.c | 1 - include/target/target_core_fabric.h | 1 - 4 files changed, 21 deletions(-) (limited to 'include') diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index b505e5e7c987..cb53144c72d0 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -700,17 +700,6 @@ static void tcm_qla2xxx_release_session(struct kref *kref) qlt_unreg_sess(se_sess->fabric_sess_ptr); } -static void tcm_qla2xxx_put_session(struct se_session *se_sess) -{ - struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; - struct qla_hw_data *ha = sess->vha->hw; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - kref_put(&se_sess->sess_kref, tcm_qla2xxx_release_session); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) { if (!sess) @@ -1843,7 +1832,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, - .put_session = tcm_qla2xxx_put_session, .shutdown_session = tcm_qla2xxx_shutdown_session, .close_session = tcm_qla2xxx_close_session, .sess_get_index = tcm_qla2xxx_sess_get_index, @@ -1887,7 +1875,6 @@ static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, .check_stop_free = tcm_qla2xxx_check_stop_free, .release_cmd = tcm_qla2xxx_release_cmd, - .put_session = tcm_qla2xxx_put_session, .shutdown_session = tcm_qla2xxx_shutdown_session, .close_session = tcm_qla2xxx_close_session, .sess_get_index = tcm_qla2xxx_sess_get_index, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index fc460f1b0b75..3c2809cd8b5b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -409,12 +409,6 @@ EXPORT_SYMBOL(target_get_session); void target_put_session(struct se_session *se_sess) { - struct se_portal_group *tpg = se_sess->se_tpg; - - if (tpg->se_tpg_tfo->put_session != NULL) { - tpg->se_tpg_tfo->put_session(se_sess); - return; - } kref_put(&se_sess->sess_kref, target_release_session); } EXPORT_SYMBOL(target_put_session); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index edd0379c06b9..8b7dd47abd8d 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -1817,7 +1817,6 @@ static const struct target_core_fabric_ops scsiback_ops = { .tpg_get_inst_index = scsiback_tpg_get_inst_index, .check_stop_free = scsiback_check_stop_free, .release_cmd = scsiback_release_cmd, - .put_session = NULL, .shutdown_session = scsiback_shutdown_session, .close_session = scsiback_close_session, .sess_get_index = scsiback_sess_get_index, diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index f64d493f888b..55654c90350d 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -37,7 +37,6 @@ struct target_core_fabric_ops { */ int (*check_stop_free)(struct se_cmd *); void (*release_cmd)(struct se_cmd *); - void (*put_session)(struct se_session *); /* * Called with spin_lock_bh(struct se_portal_group->session_lock held. */ -- cgit v1.2.3 From 29a05deebf6c2e3010934fb78ee65cab3d329470 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 22 Mar 2015 20:42:19 -0700 Subject: target: Convert se_node_acl->device_list[] to RCU hlist This patch converts se_node_acl->device_list[] table for mappedluns to modern RCU hlist_head usage in order to support an arbitrary number of node_acl lun mappings. It converts transport_lookup_*_lun() fast-path code to use RCU read path primitives when looking up se_dev_entry. It adds a new hlist_head at se_node_acl->lun_entry_hlist for this purpose. For transport_lookup_cmd_lun() code, it works with existing per-cpu se_lun->lun_ref when associating se_cmd with se_lun + se_device. Also, go ahead and update core_create_device_list_for_node() + core_free_device_list_for_node() to use ->lun_entry_hlist. It also converts se_dev_entry->pr_ref_count access to use modern struct kref counting, and updates core_disable_device_list_for_node() to kref_put() and block on se_deve->pr_comp waiting for outstanding PR special-case PR references to drop, then invoke kfree_rcu() to wait for the RCU grace period to complete before releasing memory. So now that se_node_acl->lun_entry_hlist fast path access uses RCU protected pointers, go ahead and convert remaining non-fast path RCU updater code using ->lun_entry_lock to struct mutex to allow callers to block while walking se_node_acl->lun_entry_hlist. Finally drop the left-over core_clear_initiator_node_from_tpg() that originally cleared lun_access during se_node_acl shutdown, as post RCU conversion it now becomes duplicated logic. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Paul E. McKenney Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 3 +- drivers/target/target_core_device.c | 356 ++++++++++++++------------- drivers/target/target_core_fabric_configfs.c | 43 ++-- drivers/target/target_core_internal.h | 8 +- drivers/target/target_core_pr.c | 72 +++--- drivers/target/target_core_pscsi.c | 7 +- drivers/target/target_core_spc.c | 18 +- drivers/target/target_core_stat.c | 197 +++++++-------- drivers/target/target_core_tpg.c | 75 +----- drivers/target/target_core_ua.c | 51 ++-- include/target/target_core_backend.h | 2 +- include/target/target_core_base.h | 27 +- 12 files changed, 415 insertions(+), 444 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index b590f153a7b6..53cdfabac861 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1001,7 +1001,8 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) spin_lock_bh(&port->sep_alua_lock); list_for_each_entry(se_deve, &port->sep_alua_list, alua_port_list) { - lacl = se_deve->se_lun_acl; + lacl = rcu_dereference_check(se_deve->se_lun_acl, + lockdep_is_held(&port->sep_alua_lock)); /* * se_deve->se_lun_acl pointer may be NULL for a * entry created without explicit Node+MappedLUN ACLs diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 371a9770f563..e44e6bd66659 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -60,18 +60,17 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) { struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; struct se_device *dev; - unsigned long flags; + struct se_dev_entry *deve; if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) return TCM_NON_EXISTENT_LUN; - spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags); - se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; - if (se_cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - struct se_dev_entry *deve = se_cmd->se_deve; - - deve->total_cmds++; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (deve) { + atomic_long_inc(&deve->total_cmds); if ((se_cmd->data_direction == DMA_TO_DEVICE) && (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { @@ -79,17 +78,19 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) " Access for 0x%08x\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); - spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); + rcu_read_unlock(); return TCM_WRITE_PROTECTED; } if (se_cmd->data_direction == DMA_TO_DEVICE) - deve->write_bytes += se_cmd->data_length; + atomic_long_add(se_cmd->data_length, + &deve->write_bytes); else if (se_cmd->data_direction == DMA_FROM_DEVICE) - deve->read_bytes += se_cmd->data_length; + atomic_long_add(se_cmd->data_length, + &deve->read_bytes); - se_lun = deve->se_lun; - se_cmd->se_lun = deve->se_lun; + se_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = rcu_dereference(deve->se_lun); se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; @@ -97,7 +98,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) percpu_ref_get(&se_lun->lun_ref); se_cmd->lun_ref_active = true; } - spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); + rcu_read_unlock(); if (!se_lun) { /* @@ -147,24 +148,23 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) struct se_dev_entry *deve; struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; unsigned long flags; if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) return -ENODEV; - spin_lock_irqsave(&se_sess->se_node_acl->device_list_lock, flags); - se_cmd->se_deve = se_sess->se_node_acl->device_list[unpacked_lun]; - deve = se_cmd->se_deve; - - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - se_tmr->tmr_lun = deve->se_lun; - se_cmd->se_lun = deve->se_lun; - se_lun = deve->se_lun; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (deve) { + se_tmr->tmr_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = rcu_dereference(deve->se_lun); + se_lun = rcu_dereference(deve->se_lun); se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; } - spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); + rcu_read_unlock(); if (!se_lun) { pr_debug("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" @@ -186,9 +186,27 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) } EXPORT_SYMBOL(transport_lookup_tmr_lun); +bool target_lun_is_rdonly(struct se_cmd *cmd) +{ + struct se_session *se_sess = cmd->se_sess; + struct se_dev_entry *deve; + bool ret; + + if (cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) + return true; + + rcu_read_lock(); + deve = target_nacl_find_deve(se_sess->se_node_acl, cmd->orig_fe_lun); + ret = (deve && deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(target_lun_is_rdonly); + /* * This function is called from core_scsi3_emulate_pro_register_and_move() - * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_ref_count + * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_kref * when a matching rtpi is found. */ struct se_dev_entry *core_get_se_deve_from_rtpi( @@ -197,81 +215,43 @@ struct se_dev_entry *core_get_se_deve_from_rtpi( { struct se_dev_entry *deve; struct se_lun *lun; - struct se_port *port; struct se_portal_group *tpg = nacl->se_tpg; - u32 i; - - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - lun = deve->se_lun; + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + lun = rcu_dereference(deve->se_lun); if (!lun) { pr_err("%s device entries device pointer is" " NULL, but Initiator has access.\n", tpg->se_tpg_tfo->get_fabric_name()); continue; } - port = lun->lun_sep; - if (!port) { - pr_err("%s device entries device pointer is" - " NULL, but Initiator has access.\n", - tpg->se_tpg_tfo->get_fabric_name()); - continue; - } - if (port->sep_rtpi != rtpi) + if (lun->lun_rtpi != rtpi) continue; - atomic_inc_mb(&deve->pr_ref_count); - spin_unlock_irq(&nacl->device_list_lock); + kref_get(&deve->pr_kref); + rcu_read_unlock(); return deve; } - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return NULL; } -int core_free_device_list_for_node( +void core_free_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { struct se_dev_entry *deve; - struct se_lun *lun; - u32 i; - - if (!nacl->device_list) - return 0; - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - - if (!deve->se_lun) { - pr_err("%s device entries device pointer is" - " NULL, but Initiator has access.\n", - tpg->se_tpg_tfo->get_fabric_name()); - continue; - } - lun = deve->se_lun; - - spin_unlock_irq(&nacl->device_list_lock); - core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); - spin_lock_irq(&nacl->device_list_lock); + mutex_lock(&nacl->lun_entry_mutex); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + struct se_lun *lun = rcu_dereference_check(deve->se_lun, + lockdep_is_held(&nacl->lun_entry_mutex)); + core_disable_device_list_for_node(lun, deve, nacl, tpg); } - spin_unlock_irq(&nacl->device_list_lock); - - array_free(nacl->device_list, TRANSPORT_MAX_LUNS_PER_TPG); - nacl->device_list = NULL; - - return 0; + mutex_unlock(&nacl->lun_entry_mutex); } void core_update_device_list_access( @@ -281,16 +261,40 @@ void core_update_device_list_access( { struct se_dev_entry *deve; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[mapped_lun]; - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + mutex_lock(&nacl->lun_entry_mutex); + deve = target_nacl_find_deve(nacl, mapped_lun); + if (deve) { + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + } else { + deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; + deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + } } - spin_unlock_irq(&nacl->device_list_lock); + mutex_unlock(&nacl->lun_entry_mutex); +} + +/* + * Called with rcu_read_lock or nacl->device_list_lock held. + */ +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *nacl, u32 mapped_lun) +{ + struct se_dev_entry *deve; + + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) + if (deve->mapped_lun == mapped_lun) + return deve; + + return NULL; +} +EXPORT_SYMBOL(target_nacl_find_deve); + +void target_pr_kref_release(struct kref *kref) +{ + struct se_dev_entry *deve = container_of(kref, struct se_dev_entry, + pr_kref); + complete(&deve->pr_comp); } /* core_enable_device_list_for_node(): @@ -306,85 +310,87 @@ int core_enable_device_list_for_node( struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve; - - spin_lock_irq(&nacl->device_list_lock); - - deve = nacl->device_list[mapped_lun]; - - /* - * Check if the call is handling demo mode -> explicit LUN ACL - * transition. This transition must be for the same struct se_lun - * + mapped_lun that was setup in demo mode.. - */ - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) { - if (deve->se_lun_acl != NULL) { - pr_err("struct se_dev_entry->se_lun_acl" - " already set for demo mode -> explicit" - " LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); + struct se_dev_entry *orig, *new; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) { + pr_err("Unable to allocate se_dev_entry memory\n"); + return -ENOMEM; + } + + atomic_set(&new->ua_count, 0); + spin_lock_init(&new->ua_lock); + INIT_LIST_HEAD(&new->alua_port_list); + INIT_LIST_HEAD(&new->ua_list); + + new->mapped_lun = mapped_lun; + kref_init(&new->pr_kref); + init_completion(&new->pr_comp); + + if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) + new->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; + else + new->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + + new->creation_time = get_jiffies_64(); + new->attach_count++; + + mutex_lock(&nacl->lun_entry_mutex); + orig = target_nacl_find_deve(nacl, mapped_lun); + if (orig && orig->se_lun) { + struct se_lun *orig_lun = rcu_dereference_check(orig->se_lun, + lockdep_is_held(&nacl->lun_entry_mutex)); + + if (orig_lun != lun) { + pr_err("Existing orig->se_lun doesn't match new lun" + " for dynamic -> explicit NodeACL conversion:" + " %s\n", nacl->initiatorname); + mutex_unlock(&nacl->lun_entry_mutex); + kfree(new); return -EINVAL; } - if (deve->se_lun != lun) { - pr_err("struct se_dev_entry->se_lun does" - " match passed struct se_lun for demo mode" - " -> explicit LUN ACL transition\n"); - spin_unlock_irq(&nacl->device_list_lock); - return -EINVAL; - } - deve->se_lun_acl = lun_acl; + BUG_ON(orig->se_lun_acl != NULL); - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; - } + rcu_assign_pointer(new->se_lun, lun); + rcu_assign_pointer(new->se_lun_acl, lun_acl); + hlist_del_rcu(&orig->link); + hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); + mutex_unlock(&nacl->lun_entry_mutex); - spin_unlock_irq(&nacl->device_list_lock); - return 0; - } + spin_lock_bh(&port->sep_alua_lock); + list_del(&orig->alua_port_list); + list_add_tail(&new->alua_port_list, &port->sep_alua_list); + spin_unlock_bh(&port->sep_alua_lock); - deve->se_lun = lun; - deve->se_lun_acl = lun_acl; - deve->mapped_lun = mapped_lun; - deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS; + kref_put(&orig->pr_kref, target_pr_kref_release); + wait_for_completion(&orig->pr_comp); - if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE; - } else { - deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE; - deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY; + kfree_rcu(orig, rcu_head); + return 0; } - deve->creation_time = get_jiffies_64(); - deve->attach_count++; - spin_unlock_irq(&nacl->device_list_lock); + rcu_assign_pointer(new->se_lun, lun); + rcu_assign_pointer(new->se_lun_acl, lun_acl); + hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); + mutex_unlock(&nacl->lun_entry_mutex); spin_lock_bh(&port->sep_alua_lock); - list_add_tail(&deve->alua_port_list, &port->sep_alua_list); + list_add_tail(&new->alua_port_list, &port->sep_alua_list); spin_unlock_bh(&port->sep_alua_lock); return 0; } -/* core_disable_device_list_for_node(): - * - * +/* + * Called with se_node_acl->lun_entry_mutex held. */ -int core_disable_device_list_for_node( +void core_disable_device_list_for_node( struct se_lun *lun, - struct se_lun_acl *lun_acl, - u32 mapped_lun, - u32 lun_access, + struct se_dev_entry *orig, struct se_node_acl *nacl, struct se_portal_group *tpg) { struct se_port *port = lun->lun_sep; - struct se_dev_entry *deve = nacl->device_list[mapped_lun]; - /* * If the MappedLUN entry is being disabled, the entry in * port->sep_alua_list must be removed now before clearing the @@ -399,29 +405,29 @@ int core_disable_device_list_for_node( * MappedLUN *deve will be released below.. */ spin_lock_bh(&port->sep_alua_lock); - list_del(&deve->alua_port_list); + list_del(&orig->alua_port_list); spin_unlock_bh(&port->sep_alua_lock); /* - * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE - * PR operation to complete. + * Disable struct se_dev_entry LUN ACL mapping */ - while (atomic_read(&deve->pr_ref_count) != 0) - cpu_relax(); - - spin_lock_irq(&nacl->device_list_lock); + core_scsi3_ua_release_all(orig); + + hlist_del_rcu(&orig->link); + rcu_assign_pointer(orig->se_lun, NULL); + rcu_assign_pointer(orig->se_lun_acl, NULL); + orig->lun_flags = 0; + orig->creation_time = 0; + orig->attach_count--; /* - * Disable struct se_dev_entry LUN ACL mapping + * Before firing off RCU callback, wait for any in process SPEC_I_PT=1 + * or REGISTER_AND_MOVE PR operation to complete. */ - core_scsi3_ua_release_all(deve); - deve->se_lun = NULL; - deve->se_lun_acl = NULL; - deve->lun_flags = 0; - deve->creation_time = 0; - deve->attach_count--; - spin_unlock_irq(&nacl->device_list_lock); + kref_put(&orig->pr_kref, target_pr_kref_release); + wait_for_completion(&orig->pr_comp); + + kfree_rcu(orig, rcu_head); core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl); - return 0; } /* core_clear_lun_from_tpg(): @@ -432,26 +438,22 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) { struct se_node_acl *nacl; struct se_dev_entry *deve; - u32 i; spin_lock_irq(&tpg->acl_node_lock); list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) { spin_unlock_irq(&tpg->acl_node_lock); - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - if (lun != deve->se_lun) - continue; - spin_unlock_irq(&nacl->device_list_lock); + mutex_lock(&nacl->lun_entry_mutex); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { + struct se_lun *tmp_lun = rcu_dereference_check(deve->se_lun, + lockdep_is_held(&nacl->lun_entry_mutex)); - core_disable_device_list_for_node(lun, NULL, - deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS, - nacl, tpg); + if (lun != tmp_lun) + continue; - spin_lock_irq(&nacl->device_list_lock); + core_disable_device_list_for_node(lun, deve, nacl, tpg); } - spin_unlock_irq(&nacl->device_list_lock); + mutex_unlock(&nacl->lun_entry_mutex); spin_lock_irq(&tpg->acl_node_lock); } @@ -583,7 +585,9 @@ int core_dev_export( if (IS_ERR(port)) return PTR_ERR(port); + lun->lun_index = dev->dev_index; lun->lun_se_dev = dev; + lun->lun_rtpi = port->sep_rtpi; spin_lock(&hba->device_lock); dev->export_count++; @@ -1369,16 +1373,13 @@ int core_dev_add_initiator_node_lun_acl( return 0; } -/* core_dev_del_initiator_node_lun_acl(): - * - * - */ int core_dev_del_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_lun *lun, struct se_lun_acl *lacl) { struct se_node_acl *nacl; + struct se_dev_entry *deve; nacl = lacl->se_lun_nacl; if (!nacl) @@ -1389,8 +1390,11 @@ int core_dev_del_initiator_node_lun_acl( atomic_dec_mb(&lun->lun_acl_count); spin_unlock(&lun->lun_acl_lock); - core_disable_device_list_for_node(lun, NULL, lacl->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); + mutex_lock(&nacl->lun_entry_mutex); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (deve) + core_disable_device_list_for_node(lun, deve, nacl, tpg); + mutex_unlock(&nacl->lun_entry_mutex); lacl->se_lun = NULL; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 6cb4828308e9..0939a5492c16 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -123,16 +123,16 @@ static int target_fabric_mappedlun_link( * which be will write protected (READ-ONLY) when * tpg_1/attrib/demo_mode_write_protect=1 */ - spin_lock_irq(&lacl->se_lun_nacl->device_list_lock); - deve = lacl->se_lun_nacl->device_list[lacl->mapped_lun]; - if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) + rcu_read_lock(); + deve = target_nacl_find_deve(lacl->se_lun_nacl, lacl->mapped_lun); + if (deve) lun_access = deve->lun_flags; else lun_access = (se_tpg->se_tpg_tfo->tpg_check_prod_mode_write_protect( se_tpg)) ? TRANSPORT_LUNFLAGS_READ_ONLY : TRANSPORT_LUNFLAGS_READ_WRITE; - spin_unlock_irq(&lacl->se_lun_nacl->device_list_lock); + rcu_read_unlock(); /* * Determine the actual mapped LUN value user wants.. * @@ -149,23 +149,13 @@ static int target_fabric_mappedlun_unlink( struct config_item *lun_acl_ci, struct config_item *lun_ci) { - struct se_lun *lun; struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci), struct se_lun_acl, se_lun_group); - struct se_node_acl *nacl = lacl->se_lun_nacl; - struct se_dev_entry *deve = nacl->device_list[lacl->mapped_lun]; - struct se_portal_group *se_tpg; - /* - * Determine if the underlying MappedLUN has already been released.. - */ - if (!deve->se_lun) - return 0; - - lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - se_tpg = lun->lun_sep->sep_tpg; + struct se_lun *lun = container_of(to_config_group(lun_ci), + struct se_lun, lun_group); + struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; - core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); - return 0; + return core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); } CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl); @@ -181,14 +171,15 @@ static ssize_t target_fabric_mappedlun_show_write_protect( { struct se_node_acl *se_nacl = lacl->se_lun_nacl; struct se_dev_entry *deve; - ssize_t len; - - spin_lock_irq(&se_nacl->device_list_lock); - deve = se_nacl->device_list[lacl->mapped_lun]; - len = sprintf(page, "%d\n", - (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ? - 1 : 0); - spin_unlock_irq(&se_nacl->device_list_lock); + ssize_t len = 0; + + rcu_read_lock(); + deve = target_nacl_find_deve(se_nacl, lacl->mapped_lun); + if (deve) { + len = sprintf(page, "%d\n", + (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ? 1 : 0); + } + rcu_read_unlock(); return len; } diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index d0344ad9b0d8..a04a6e396ae3 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -9,13 +9,15 @@ extern struct mutex g_device_mutex; extern struct list_head g_device_list; struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); -int core_free_device_list_for_node(struct se_node_acl *, +void target_pr_kref_release(struct kref *); +void core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); void core_update_device_list_access(u32, u32, struct se_node_acl *); +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u32); int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, u32, u32, struct se_node_acl *, struct se_portal_group *); -int core_disable_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u32, u32, struct se_node_acl *, struct se_portal_group *); +void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, + struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index a4b9a0dd50cd..909573a682d5 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -48,7 +48,7 @@ struct pr_transport_id_holder { struct t10_pr_registration *dest_pr_reg; struct se_portal_group *dest_tpg; struct se_node_acl *dest_node_acl; - struct se_dev_entry *dest_se_deve; + struct se_dev_entry __rcu *dest_se_deve; struct list_head dest_list; }; @@ -232,7 +232,7 @@ target_scsi2_reservation_release(struct se_cmd *cmd) tpg = sess->se_tpg; pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); out_unlock: @@ -281,7 +281,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) dev->dev_reserved_node_acl->initiatorname); pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" " from %s \n", cmd->se_lun->unpacked_lun, - cmd->se_deve->mapped_lun, + cmd->orig_fe_lun, sess->se_node_acl->initiatorname); ret = TCM_RESERVATION_CONFLICT; goto out_unlock; @@ -295,7 +295,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) } pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), - cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, + cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); out_unlock: @@ -320,6 +320,7 @@ static int core_scsi3_pr_seq_non_holder( unsigned char *cdb = cmd->t_task_cdb; struct se_dev_entry *se_deve; struct se_session *se_sess = cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; int other_cdb = 0, ignore_reg; int registered_nexus = 0, ret = 1; /* Conflict by default */ int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */ @@ -327,7 +328,8 @@ static int core_scsi3_pr_seq_non_holder( int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ - se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + rcu_read_lock(); + se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); /* * Determine if the registration should be ignored due to * non-matching ISIDs in target_scsi3_pr_reservation_check(). @@ -368,8 +370,10 @@ static int core_scsi3_pr_seq_non_holder( registered_nexus = 1; break; default: + rcu_read_unlock(); return -EINVAL; } + rcu_read_unlock(); /* * Referenced from spc4r17 table 45 for *NON* PR holder access */ @@ -735,7 +739,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname)) continue; - atomic_inc_mb(&deve_tmp->pr_ref_count); + kref_get(&deve_tmp->pr_kref); spin_unlock_bh(&port->sep_alua_lock); /* * Grab a configfs group dependency that is released @@ -748,7 +752,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); atomic_dec_mb(&port->sep_tg_pt_ref_cnt); - atomic_dec_mb(&deve_tmp->pr_ref_count); + kref_put(&deve_tmp->pr_kref, target_pr_kref_release); goto out; } /* @@ -763,7 +767,6 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { atomic_dec_mb(&port->sep_tg_pt_ref_cnt); - atomic_dec_mb(&deve_tmp->pr_ref_count); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } @@ -896,7 +899,7 @@ static int __core_scsi3_check_aptpl_registration( struct se_lun *lun, u32 target_lun, struct se_node_acl *nacl, - struct se_dev_entry *deve) + u32 mapped_lun) { struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct t10_reservation *pr_tmpl = &dev->t10_pr; @@ -924,13 +927,12 @@ static int __core_scsi3_check_aptpl_registration( pr_reg_aptpl_list) { if (!strcmp(pr_reg->pr_iport, i_port) && - (pr_reg->pr_res_mapped_lun == deve->mapped_lun) && + (pr_reg->pr_res_mapped_lun == mapped_lun) && !(strcmp(pr_reg->pr_tport, t_port)) && (pr_reg->pr_reg_tpgt == tpgt) && (pr_reg->pr_aptpl_target_lun == target_lun)) { pr_reg->pr_reg_nacl = nacl; - pr_reg->pr_reg_deve = deve; pr_reg->pr_reg_tg_pt_lun = lun; list_del(&pr_reg->pr_reg_aptpl_list); @@ -968,13 +970,12 @@ int core_scsi3_check_aptpl_registration( struct se_node_acl *nacl, u32 mapped_lun) { - struct se_dev_entry *deve = nacl->device_list[mapped_lun]; - if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; return __core_scsi3_check_aptpl_registration(dev, tpg, lun, - lun->unpacked_lun, nacl, deve); + lun->unpacked_lun, nacl, + mapped_lun); } static void __core_scsi3_dump_registration( @@ -1408,27 +1409,29 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) { - struct se_lun_acl *lun_acl = se_deve->se_lun_acl; + struct se_lun_acl *lun_acl; struct se_node_acl *nacl; struct se_portal_group *tpg; /* * For nacl->dynamic_node_acl=1 */ + lun_acl = se_deve->se_lun_acl; if (!lun_acl) { - atomic_dec_mb(&se_deve->pr_ref_count); + kref_put(&se_deve->pr_kref, target_pr_kref_release); return; } nacl = lun_acl->se_lun_nacl; tpg = nacl->se_tpg; target_undepend_item(&lun_acl->se_lun_group.cg_item); - atomic_dec_mb(&se_deve->pr_ref_count); + kref_put(&se_deve->pr_kref, target_pr_kref_release); } static sense_reason_t core_scsi3_decode_spec_i_port( struct se_cmd *cmd, struct se_portal_group *tpg, + struct se_dev_entry *local_se_deve, unsigned char *l_isid, u64 sa_res_key, int all_tg_pt, @@ -1439,7 +1442,7 @@ core_scsi3_decode_spec_i_port( struct se_portal_group *dest_tpg = NULL, *tmp_tpg; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *dest_node_acl = NULL; - struct se_dev_entry *dest_se_deve = NULL, *local_se_deve; + struct se_dev_entry __rcu *dest_se_deve = NULL; struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); @@ -1452,7 +1455,6 @@ core_scsi3_decode_spec_i_port( int dest_local_nexus; u32 dest_rtpi = 0; - local_se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; /* * Allocate a struct pr_transport_id_holder and setup the * local_node_acl and local_se_deve pointers and add to @@ -1467,7 +1469,6 @@ core_scsi3_decode_spec_i_port( INIT_LIST_HEAD(&tidh_new->dest_list); tidh_new->dest_tpg = tpg; tidh_new->dest_node_acl = se_sess->se_node_acl; - tidh_new->dest_se_deve = local_se_deve; local_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, se_sess->se_node_acl, local_se_deve, l_isid, @@ -1476,6 +1477,7 @@ core_scsi3_decode_spec_i_port( kfree(tidh_new); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } + rcu_assign_pointer(tidh_new->dest_se_deve, local_se_deve); tidh_new->dest_pr_reg = local_pr_reg; /* * The local I_T nexus does not hold any configfs dependances, @@ -1635,7 +1637,7 @@ core_scsi3_decode_spec_i_port( if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item()" " failed\n"); - atomic_dec_mb(&dest_se_deve->pr_ref_count); + kref_put(&dest_se_deve->pr_kref, target_pr_kref_release); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -1990,6 +1992,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type) { struct se_session *se_sess = cmd->se_sess; + struct se_node_acl *nacl = se_sess->se_node_acl; struct se_device *dev = cmd->se_dev; struct se_dev_entry *se_deve; struct se_lun *se_lun = cmd->se_lun; @@ -2005,7 +2008,14 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } se_tpg = se_sess->se_tpg; - se_deve = se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; + + rcu_read_lock(); + se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!se_deve) { + pr_err("Unable to locate se_deve for PRO-REGISTER\n"); + rcu_read_unlock(); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) { memset(&isid_buf[0], 0, PR_REG_ISID_LEN); @@ -2021,14 +2031,16 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, if (res_key) { pr_warn("SPC-3 PR: Reservation Key non-zero" " for SA REGISTER, returning CONFLICT\n"); + rcu_read_unlock(); return TCM_RESERVATION_CONFLICT; } /* * Do nothing but return GOOD status. */ - if (!sa_res_key) + if (!sa_res_key) { + rcu_read_unlock(); return 0; - + } if (!spec_i_pt) { /* * Perform the Service Action REGISTER on the Initiator @@ -2041,6 +2053,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, register_type, 0)) { pr_err("Unable to allocate" " struct t10_pr_registration\n"); + rcu_read_unlock(); return TCM_INVALID_PARAMETER_LIST; } } else { @@ -2052,14 +2065,17 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * logic from of core_scsi3_alloc_registration() for * each TransportID provided SCSI Initiator Port/Device */ - ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, + ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, se_deve, isid_ptr, sa_res_key, all_tg_pt, aptpl); - if (ret != 0) + if (ret != 0) { + rcu_read_unlock(); return ret; + } } - + rcu_read_unlock(); return core_scsi3_update_and_write_aptpl(dev, aptpl); } + rcu_read_unlock(); /* ok, existing registration */ @@ -3321,7 +3337,7 @@ after_iport_check: if (core_scsi3_lunacl_depend_item(dest_se_deve)) { pr_err("core_scsi3_lunacl_depend_item() failed\n"); - atomic_dec_mb(&dest_se_deve->pr_ref_count); + kref_put(&dest_se_deve->pr_kref, target_pr_kref_release); dest_se_deve = NULL; ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; goto out; diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index ecc5eaef13d6..21db991b4465 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -47,6 +47,7 @@ #include #include "target_core_alua.h" +#include "target_core_internal.h" #include "target_core_pscsi.h" #define ISPRINT(a) ((a >= ' ') && (a <= '~')) @@ -637,12 +638,14 @@ static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, * Hack to make sure that Write-Protect modepage is set if R/O mode is * forced. */ - if (!cmd->se_deve || !cmd->data_length) + if (!cmd->data_length) goto after_mode_sense; if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) && (status_byte(result) << 1) == SAM_STAT_GOOD) { - if (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) { + bool read_only = target_lun_is_rdonly(cmd); + + if (read_only) { unsigned char *buf; buf = transport_kmap_data_sg(cmd); diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 78c0b40fa5c0..9f995b87b8d1 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -981,6 +981,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) int length = 0; int ret; int i; + bool read_only = target_lun_is_rdonly(cmd);; memset(buf, 0, SE_MODE_PAGE_BUF); @@ -991,9 +992,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd) length = ten ? 3 : 2; /* DEVICE-SPECIFIC PARAMETER */ - if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || - (cmd->se_deve && - (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY))) + if ((cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) || read_only) spc_modesense_write_protect(&buf[length], type); /* @@ -1211,8 +1210,9 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) { struct se_dev_entry *deve; struct se_session *sess = cmd->se_sess; + struct se_node_acl *nacl; unsigned char *buf; - u32 lun_count = 0, offset = 8, i; + u32 lun_count = 0, offset = 8; if (cmd->data_length < 16) { pr_warn("REPORT LUNS allocation length %u too small\n", @@ -1234,12 +1234,10 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) lun_count = 1; goto done; } + nacl = sess->se_node_acl; - spin_lock_irq(&sess->se_node_acl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = sess->se_node_acl->device_list[i]; - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { /* * We determine the correct LUN LIST LENGTH even once we * have reached the initial allocation length. @@ -1252,7 +1250,7 @@ sense_reason_t spc_emulate_report_luns(struct se_cmd *cmd) int_to_scsilun(deve->mapped_lun, (struct scsi_lun *)&buf[offset]); offset += 8; } - spin_unlock_irq(&sess->se_node_acl->device_list_lock); + rcu_read_unlock(); /* * See SPC3 r07, page 159. diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 64efee2fba52..ea1287940a7c 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -1084,17 +1084,17 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_inst( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiInstIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); @@ -1109,16 +1109,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev( struct se_lun *lun; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } - lun = deve->se_lun; + lun = rcu_dereference(deve->se_lun); /* scsiDeviceIndex */ - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); @@ -1133,16 +1133,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_port( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiAuthIntrTgtPortIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); @@ -1156,15 +1156,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_indx( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); @@ -1178,15 +1178,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrDevOrPort */ ret = snprintf(page, PAGE_SIZE, "%u\n", 1); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); @@ -1200,15 +1200,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrName */ ret = snprintf(page, PAGE_SIZE, "%s\n", nacl->initiatorname); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); @@ -1222,15 +1222,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* FIXME: scsiAuthIntrLunMapIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); @@ -1244,15 +1244,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrAttachedTimes */ ret = snprintf(page, PAGE_SIZE, "%u\n", deve->attach_count); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); @@ -1266,15 +1266,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrOutCommands */ - ret = snprintf(page, PAGE_SIZE, "%u\n", deve->total_cmds); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%lu\n", + atomic_long_read(&deve->total_cmds)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); @@ -1288,15 +1289,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrReadMegaBytes */ - ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->read_bytes >> 20)); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(atomic_long_read(&deve->read_bytes) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); @@ -1310,15 +1312,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrWrittenMegaBytes */ - ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->write_bytes >> 20)); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(atomic_long_read(&deve->write_bytes) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); @@ -1332,15 +1335,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* FIXME: scsiAuthIntrHSOutCommands */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); @@ -1354,16 +1357,16 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAuthIntrLastCreation */ ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)deve->creation_time - INITIAL_JIFFIES) * 100 / HZ)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); @@ -1377,15 +1380,15 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* FIXME: scsiAuthIntrRowStatus */ ret = snprintf(page, PAGE_SIZE, "Ready\n"); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); @@ -1450,17 +1453,17 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiInstIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); @@ -1475,16 +1478,16 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( struct se_lun *lun; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } - lun = deve->se_lun; + lun = rcu_dereference(deve->se_lun); /* scsiDeviceIndex */ - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); - spin_unlock_irq(&nacl->device_list_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); @@ -1499,16 +1502,16 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port( struct se_portal_group *tpg; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } tpg = nacl->se_tpg; /* scsiPortIndex */ ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); @@ -1548,15 +1551,15 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( struct se_dev_entry *deve; ssize_t ret; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[lacl->mapped_lun]; - if (!deve->se_lun || !deve->se_lun_acl) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, lacl->mapped_lun); + if (!deve) { + rcu_read_unlock(); return -ENODEV; } /* scsiAttIntrPortAuthIntrIdx */ ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index c0c1f67facb5..0519923ef930 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -47,42 +47,6 @@ extern struct se_device *g_lun0_dev; static DEFINE_SPINLOCK(tpg_lock); static LIST_HEAD(tpg_list); -/* core_clear_initiator_node_from_tpg(): - * - * - */ -static void core_clear_initiator_node_from_tpg( - struct se_node_acl *nacl, - struct se_portal_group *tpg) -{ - int i; - struct se_dev_entry *deve; - struct se_lun *lun; - - spin_lock_irq(&nacl->device_list_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)) - continue; - - if (!deve->se_lun) { - pr_err("%s device entries device pointer is" - " NULL, but Initiator has access.\n", - tpg->se_tpg_tfo->get_fabric_name()); - continue; - } - - lun = deve->se_lun; - spin_unlock_irq(&nacl->device_list_lock); - core_disable_device_list_for_node(lun, NULL, deve->mapped_lun, - TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg); - - spin_lock_irq(&nacl->device_list_lock); - } - spin_unlock_irq(&nacl->device_list_lock); -} - /* __core_tpg_get_initiator_node_acl(): * * spin_lock_bh(&tpg->acl_node_lock); must be held when calling @@ -225,35 +189,6 @@ static void *array_zalloc(int n, size_t size, gfp_t flags) return a; } -/* core_create_device_list_for_node(): - * - * - */ -static int core_create_device_list_for_node(struct se_node_acl *nacl) -{ - struct se_dev_entry *deve; - int i; - - nacl->device_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG, - sizeof(struct se_dev_entry), GFP_KERNEL); - if (!nacl->device_list) { - pr_err("Unable to allocate memory for" - " struct se_node_acl->device_list\n"); - return -ENOMEM; - } - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - deve = nacl->device_list[i]; - - atomic_set(&deve->ua_count, 0); - atomic_set(&deve->pr_ref_count, 0); - spin_lock_init(&deve->ua_lock); - INIT_LIST_HEAD(&deve->alua_port_list); - INIT_LIST_HEAD(&deve->ua_list); - } - - return 0; -} - static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, const unsigned char *initiatorname) { @@ -266,10 +201,11 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, INIT_LIST_HEAD(&acl->acl_list); INIT_LIST_HEAD(&acl->acl_sess_list); + INIT_HLIST_HEAD(&acl->lun_entry_hlist); kref_init(&acl->acl_kref); init_completion(&acl->acl_free_comp); - spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); + mutex_init(&acl->lun_entry_mutex); atomic_set(&acl->acl_pr_ref_count, 0); if (tpg->se_tpg_tfo->tpg_get_default_depth) acl->queue_depth = tpg->se_tpg_tfo->tpg_get_default_depth(tpg); @@ -281,15 +217,11 @@ static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, tpg->se_tpg_tfo->set_default_node_attributes(acl); - if (core_create_device_list_for_node(acl) < 0) - goto out_free_acl; if (core_set_queue_depth_for_node(tpg, acl) < 0) - goto out_free_device_list; + goto out_free_acl; return acl; -out_free_device_list: - core_free_device_list_for_node(acl, tpg); out_free_acl: kfree(acl); return NULL; @@ -454,7 +386,6 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) wait_for_completion(&acl->acl_free_comp); core_tpg_wait_for_nacl_pr_ref(acl); - core_clear_initiator_node_from_tpg(acl, tpg); core_free_device_list_for_node(acl, tpg); pr_debug("%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s" diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index a0bf0d1a3df7..6c9616d212b1 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -50,9 +50,17 @@ target_scsi3_ua_check(struct se_cmd *cmd) if (!nacl) return 0; - deve = nacl->device_list[cmd->orig_fe_lun]; - if (!atomic_read(&deve->ua_count)) + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!deve) { + rcu_read_unlock(); return 0; + } + if (!atomic_read(&deve->ua_count)) { + rcu_read_unlock(); + return 0; + } + rcu_read_unlock(); /* * From sam4r14, section 5.14 Unit attention condition: * @@ -103,9 +111,12 @@ int core_scsi3_ua_allocate( ua->ua_asc = asc; ua->ua_ascq = ascq; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[unpacked_lun]; - + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, unpacked_lun); + if (!deve) { + rcu_read_unlock(); + return -EINVAL; + } spin_lock(&deve->ua_lock); list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) { /* @@ -113,7 +124,7 @@ int core_scsi3_ua_allocate( */ if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) { spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); kmem_cache_free(se_ua_cache, ua); return 0; } @@ -158,14 +169,13 @@ int core_scsi3_ua_allocate( list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); atomic_inc_mb(&deve->ua_count); + rcu_read_unlock(); return 0; } list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:" " 0x%02x, ASCQ: 0x%02x\n", @@ -173,6 +183,7 @@ int core_scsi3_ua_allocate( asc, ascq); atomic_inc_mb(&deve->ua_count); + rcu_read_unlock(); return 0; } @@ -210,10 +221,14 @@ void core_scsi3_ua_for_check_condition( if (!nacl) return; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[cmd->orig_fe_lun]; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!deve) { + rcu_read_unlock(); + return; + } if (!atomic_read(&deve->ua_count)) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return; } /* @@ -249,7 +264,7 @@ void core_scsi3_ua_for_check_condition( atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); pr_debug("[%s]: %s UNIT ATTENTION condition with" " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x" @@ -278,10 +293,14 @@ int core_scsi3_ua_clear_for_request_sense( if (!nacl) return -EINVAL; - spin_lock_irq(&nacl->device_list_lock); - deve = nacl->device_list[cmd->orig_fe_lun]; + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (!deve) { + rcu_read_unlock(); + return -EINVAL; + } if (!atomic_read(&deve->ua_count)) { - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); return -EPERM; } /* @@ -307,7 +326,7 @@ int core_scsi3_ua_clear_for_request_sense( atomic_dec_mb(&deve->ua_count); } spin_unlock(&deve->ua_lock); - spin_unlock_irq(&nacl->device_list_lock); + rcu_read_unlock(); pr_debug("[%s]: Released UNIT ATTENTION condition, mapped" " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x," diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 47fafec556f8..80d9e486e33e 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -101,7 +101,7 @@ int target_alloc_sgl(struct scatterlist **, unsigned int *, u32, bool); sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, struct scatterlist *, u32, struct scatterlist *, u32); -void array_free(void *array, int n); +bool target_lun_is_rdonly(struct se_cmd *); /* From target_core_configfs.c to setup default backend config_item_types */ void target_core_setup_sub_cits(struct se_subsystem_api *); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 042a73464966..b518523cba7b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -160,10 +160,8 @@ enum se_cmd_flags_table { /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ enum transport_lunflags_table { - TRANSPORT_LUNFLAGS_NO_ACCESS = 0x00, - TRANSPORT_LUNFLAGS_INITIATOR_ACCESS = 0x01, - TRANSPORT_LUNFLAGS_READ_ONLY = 0x02, - TRANSPORT_LUNFLAGS_READ_WRITE = 0x04, + TRANSPORT_LUNFLAGS_READ_ONLY = 0x01, + TRANSPORT_LUNFLAGS_READ_WRITE = 0x02, }; /* @@ -584,10 +582,10 @@ struct se_node_acl { char acl_tag[MAX_ACL_TAG_SIZE]; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t acl_pr_ref_count; - struct se_dev_entry **device_list; + struct hlist_head lun_entry_hlist; struct se_session *nacl_sess; struct se_portal_group *se_tpg; - spinlock_t device_list_lock; + struct mutex lun_entry_mutex; spinlock_t nacl_sess_lock; struct config_group acl_group; struct config_group acl_attrib_group; @@ -644,20 +642,23 @@ struct se_dev_entry { /* See transport_lunflags_table */ u32 lun_flags; u32 mapped_lun; - u32 total_cmds; u64 pr_res_key; u64 creation_time; u32 attach_count; - u64 read_bytes; - u64 write_bytes; + atomic_long_t total_cmds; + atomic_long_t read_bytes; + atomic_long_t write_bytes; atomic_t ua_count; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ - atomic_t pr_ref_count; - struct se_lun_acl *se_lun_acl; + struct kref pr_kref; + struct completion pr_comp; + struct se_lun_acl __rcu *se_lun_acl; spinlock_t ua_lock; - struct se_lun *se_lun; + struct se_lun __rcu *se_lun; struct list_head alua_port_list; struct list_head ua_list; + struct hlist_node link; + struct rcu_head rcu_head; }; struct se_dev_attrib { @@ -703,6 +704,7 @@ struct se_port_stat_grps { }; struct se_lun { + u16 lun_rtpi; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; /* See transport_lun_status_table */ @@ -710,6 +712,7 @@ struct se_lun { u32 lun_access; u32 lun_flags; u32 unpacked_lun; + u32 lun_index; atomic_t lun_acl_count; spinlock_t lun_acl_lock; spinlock_t lun_sep_lock; -- cgit v1.2.3 From 80bfdfa92481d431b199eff72788588d13a3988f Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 25 Mar 2015 01:02:57 -0700 Subject: target/pr: Use atomic bitop for se_dev_entry->deve_flags reservation check This patch converts the core_scsi3_pr_seq_non_holder() check for non reservation holding registrations to use an atomic bitop in ->deve_flags to determine if a registration is currently active. It also includes associated a set_bit() in __core_scsi3_add_registration() and clear_bit() in __core_scsi3_free_registration(), if se_dev_entry still exists, and has not already been released via se_dev_entry shutdown path in core_disable_device_list_for_node(). Also, clear_bit in core_disable_device_list_for_node as well to ensure the read-critical path in core_scsi3_pr_seq_non_holder() picks up the new state, preceeding the final kfree_rcu() call. Reported-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 + drivers/target/target_core_pr.c | 58 +++++++++++++++++++++++++------------ include/target/target_core_base.h | 3 +- 3 files changed, 42 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e44e6bd66659..97792cc81fe4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -413,6 +413,7 @@ void core_disable_device_list_for_node( core_scsi3_ua_release_all(orig); hlist_del_rcu(&orig->link); + clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags); rcu_assign_pointer(orig->se_lun, NULL); rcu_assign_pointer(orig->se_lun_acl, NULL); orig->lun_flags = 0; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 909573a682d5..66e686bdf894 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -327,9 +327,13 @@ static int core_scsi3_pr_seq_non_holder( int we = 0; /* Write Exclusive */ int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ + bool registered = false; rcu_read_lock(); se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); + if (se_deve) + registered = test_bit(DEF_PR_REG_ACTIVE, &se_deve->deve_flags); + rcu_read_unlock(); /* * Determine if the registration should be ignored due to * non-matching ISIDs in target_scsi3_pr_reservation_check(). @@ -346,7 +350,7 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for the persistent reservation * holder. */ - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: @@ -356,7 +360,7 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for registered I_T Nexuses. */ reg_only = 1; - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: @@ -366,14 +370,12 @@ static int core_scsi3_pr_seq_non_holder( * Each registered I_T Nexus is a reservation holder. */ all_reg = 1; - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; default: - rcu_read_unlock(); return -EINVAL; } - rcu_read_unlock(); /* * Referenced from spc4r17 table 45 for *NON* PR holder access */ @@ -1009,10 +1011,6 @@ static void __core_scsi3_dump_registration( pr_reg->pr_reg_aptpl); } -/* - * this function can be called with struct se_device->dev_reservation_lock - * when register_move = 1 - */ static void __core_scsi3_add_registration( struct se_device *dev, struct se_node_acl *nacl, @@ -1023,6 +1021,7 @@ static void __core_scsi3_add_registration( const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; struct t10_reservation *pr_tmpl = &dev->t10_pr; + struct se_dev_entry *deve; /* * Increment PRgeneration counter for struct se_device upon a successful @@ -1039,10 +1038,16 @@ static void __core_scsi3_add_registration( spin_lock(&pr_tmpl->registration_lock); list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); - pr_reg->pr_reg_deve->def_pr_registered = 1; __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); spin_unlock(&pr_tmpl->registration_lock); + + rcu_read_lock(); + deve = pr_reg->pr_reg_deve; + if (deve) + set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); + rcu_read_unlock(); + /* * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. */ @@ -1054,6 +1059,8 @@ static void __core_scsi3_add_registration( */ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { + struct se_node_acl *nacl_tmp = pr_reg_tmp->pr_reg_nacl; + list_del(&pr_reg_tmp->pr_reg_atp_mem_list); pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); @@ -1061,12 +1068,17 @@ static void __core_scsi3_add_registration( spin_lock(&pr_tmpl->registration_lock); list_add_tail(&pr_reg_tmp->pr_reg_list, &pr_tmpl->registration_list); - pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; - __core_scsi3_dump_registration(tfo, dev, - pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, - register_type); + __core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp, + register_type); spin_unlock(&pr_tmpl->registration_lock); + + rcu_read_lock(); + deve = pr_reg_tmp->pr_reg_deve; + if (deve) + set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); + rcu_read_unlock(); + /* * Drop configfs group dependency reference from * __core_scsi3_alloc_registration() @@ -1242,13 +1254,13 @@ static void __core_scsi3_free_registration( const struct target_core_fabric_ops *tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; struct t10_reservation *pr_tmpl = &dev->t10_pr; + struct se_node_acl *nacl = pr_reg->pr_reg_nacl; + struct se_dev_entry *deve; char i_buf[PR_REG_ISID_ID_LEN]; memset(i_buf, 0, PR_REG_ISID_ID_LEN); core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); - pr_reg->pr_reg_deve->def_pr_registered = 0; - pr_reg->pr_reg_deve->pr_res_key = 0; if (!list_empty(&pr_reg->pr_reg_list)) list_del(&pr_reg->pr_reg_list); /* @@ -1257,6 +1269,8 @@ static void __core_scsi3_free_registration( */ if (dec_holders) core_scsi3_put_pr_reg(pr_reg); + + spin_unlock(&pr_tmpl->registration_lock); /* * Wait until all reference from any other I_T nexuses for this * *pr_reg have been released. Because list_del() is called above, @@ -1264,13 +1278,18 @@ static void __core_scsi3_free_registration( * count back to zero, and we release *pr_reg. */ while (atomic_read(&pr_reg->pr_res_holders) != 0) { - spin_unlock(&pr_tmpl->registration_lock); pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", tfo->get_fabric_name()); cpu_relax(); - spin_lock(&pr_tmpl->registration_lock); } + rcu_read_lock(); + deve = target_nacl_find_deve(nacl, pr_reg->pr_res_mapped_lun); + if (deve) + clear_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); + rcu_read_unlock(); + + spin_lock(&pr_tmpl->registration_lock); pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" " Node: %s%s\n", tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, @@ -3421,13 +3440,14 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { + spin_unlock(&dev->dev_reservation_lock); if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, dest_se_deve, iport_ptr, sa_res_key, 0, aptpl, 2, 1)) { - spin_unlock(&dev->dev_reservation_lock); ret = TCM_INVALID_PARAMETER_LIST; goto out; } + spin_lock(&dev->dev_reservation_lock); dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); new_reg = 1; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index b518523cba7b..508528a5e927 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -638,7 +638,6 @@ struct se_lun_acl { }; struct se_dev_entry { - bool def_pr_registered; /* See transport_lunflags_table */ u32 lun_flags; u32 mapped_lun; @@ -655,6 +654,8 @@ struct se_dev_entry { struct se_lun_acl __rcu *se_lun_acl; spinlock_t ua_lock; struct se_lun __rcu *se_lun; +#define DEF_PR_REG_ACTIVE 1 + unsigned long deve_flags; struct list_head alua_port_list; struct list_head ua_list; struct hlist_node link; -- cgit v1.2.3 From 79dc9c9e865a7f8c14737453f112ced25deafdef Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 27 Mar 2015 04:51:03 +0000 Subject: target/pr: Change alloc_registration to avoid pr_reg_tg_pt_lun This patch changes __core_scsi3_do_alloc_registration() code to drop pr_reg->pr_reg_tg_pt_lun pointer usage in favor of a new pr_reg RPTI + existing pr_reg->pr_aptpl_target_lun used by APTPL metadata logic. It also includes changes to REGISTER, REGISTER_AND_MOVE and APTPL feature bit codepaths to use rcu_dereference_check() with the expected non-zero se_dev_entry->pr_kref reference held. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 6 +- drivers/target/target_core_pr.c | 131 ++++++++++++++++++---------------- include/target/target_core_base.h | 4 +- 3 files changed, 72 insertions(+), 69 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 798386a1b6e7..4a31d4765390 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -817,7 +817,6 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( struct se_device *dev, char *page) { struct se_node_acl *se_nacl; - struct se_lun *lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg; const struct target_core_fabric_ops *tfo; @@ -832,7 +831,6 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( se_nacl = pr_reg->pr_reg_nacl; se_tpg = se_nacl->se_tpg; - lun = pr_reg->pr_reg_tg_pt_lun; tfo = se_tpg->se_tpg_tfo; len += sprintf(page+len, "SPC-3 Reservation: %s" @@ -840,9 +838,9 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( tfo->tpg_get_wwn(se_tpg)); len += sprintf(page+len, "SPC-3 Reservation: Relative Port" " Identifier Tag: %hu %s Portal Group Tag: %hu" - " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi, + " %s Logical Unit: %u\n", pr_reg->tg_pt_sep_rtpi, tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), - tfo->get_fabric_name(), lun->unpacked_lun); + tfo->get_fabric_name(), pr_reg->pr_aptpl_target_lun); out_unlock: spin_unlock(&dev->dev_reservation_lock); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 66e686bdf894..48ed5d2bf5fe 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -44,11 +44,10 @@ * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT) */ struct pr_transport_id_holder { - int dest_local_nexus; struct t10_pr_registration *dest_pr_reg; struct se_portal_group *dest_tpg; struct se_node_acl *dest_node_acl; - struct se_dev_entry __rcu *dest_se_deve; + struct se_dev_entry *dest_se_deve; struct list_head dest_list; }; @@ -625,7 +624,9 @@ static u32 core_scsi3_pr_generation(struct se_device *dev) static struct t10_pr_registration *__core_scsi3_do_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, + struct se_lun *lun, struct se_dev_entry *deve, + u32 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -647,12 +648,12 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( atomic_set(&pr_reg->pr_res_holders, 0); pr_reg->pr_reg_nacl = nacl; pr_reg->pr_reg_deve = deve; - pr_reg->pr_res_mapped_lun = deve->mapped_lun; - pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun; + pr_reg->pr_res_mapped_lun = mapped_lun; + pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; + pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = aptpl; - pr_reg->pr_reg_tg_pt_lun = deve->se_lun; /* * If an ISID value for this SCSI Initiator Port exists, * save it to the registration now. @@ -676,7 +677,9 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *); static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, + struct se_lun *lun, struct se_dev_entry *deve, + u32 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -684,6 +687,8 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( { struct se_dev_entry *deve_tmp; struct se_node_acl *nacl_tmp; + struct se_lun_acl *lacl_tmp; + struct se_lun *lun_tmp; struct se_port *port, *port_tmp; const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; @@ -692,8 +697,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * Create a registration for the I_T Nexus upon which the * PROUT REGISTER was received. */ - pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid, - sa_res_key, all_tg_pt, aptpl); + pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, lun, deve, mapped_lun, + isid, sa_res_key, all_tg_pt, + aptpl); if (!pr_reg) return NULL; /* @@ -721,7 +727,9 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (!deve_tmp->se_lun_acl) continue; - nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl; + lacl_tmp = rcu_dereference_check(deve_tmp->se_lun_acl, + lockdep_is_held(&port->sep_alua_lock)); + nacl_tmp = lacl_tmp->se_lun_nacl; /* * Skip the matching struct se_node_acl that is allocated * above.. @@ -764,8 +772,12 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * the original *pr_reg is processed in * __core_scsi3_add_registration() */ + lun_tmp = rcu_dereference_check(deve_tmp->se_lun, + atomic_read(&deve_tmp->pr_kref.refcount) != 0); + pr_reg_atp = __core_scsi3_do_alloc_registration(dev, - nacl_tmp, deve_tmp, NULL, + nacl_tmp, lun_tmp, deve_tmp, + deve_tmp->mapped_lun, NULL, sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { atomic_dec_mb(&port->sep_tg_pt_ref_cnt); @@ -835,7 +847,6 @@ int core_scsi3_alloc_aptpl_registration( pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = 1; - pr_reg->pr_reg_tg_pt_lun = NULL; pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */ pr_reg->pr_res_type = type; /* @@ -935,7 +946,7 @@ static int __core_scsi3_check_aptpl_registration( (pr_reg->pr_aptpl_target_lun == target_lun)) { pr_reg->pr_reg_nacl = nacl; - pr_reg->pr_reg_tg_pt_lun = lun; + pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; list_del(&pr_reg->pr_reg_aptpl_list); spin_unlock(&pr_tmpl->aptpl_reg_lock); @@ -1090,7 +1101,9 @@ static void __core_scsi3_add_registration( static int core_scsi3_alloc_registration( struct se_device *dev, struct se_node_acl *nacl, + struct se_lun *lun, struct se_dev_entry *deve, + u32 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -1100,8 +1113,9 @@ static int core_scsi3_alloc_registration( { struct t10_pr_registration *pr_reg; - pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid, - sa_res_key, all_tg_pt, aptpl); + pr_reg = __core_scsi3_alloc_registration(dev, nacl, lun, deve, mapped_lun, + isid, sa_res_key, all_tg_pt, + aptpl); if (!pr_reg) return -EPERM; @@ -1411,12 +1425,14 @@ static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl) static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) { - struct se_lun_acl *lun_acl = se_deve->se_lun_acl; + struct se_lun_acl *lun_acl; struct se_node_acl *nacl; struct se_portal_group *tpg; /* * For nacl->dynamic_node_acl=1 */ + lun_acl = rcu_dereference_check(se_deve->se_lun_acl, + atomic_read(&se_deve->pr_kref.refcount) != 0); if (!lun_acl) return 0; @@ -1434,7 +1450,8 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) /* * For nacl->dynamic_node_acl=1 */ - lun_acl = se_deve->se_lun_acl; + lun_acl = rcu_dereference_check(se_deve->se_lun_acl, + atomic_read(&se_deve->pr_kref.refcount) != 0); if (!lun_acl) { kref_put(&se_deve->pr_kref, target_pr_kref_release); return; @@ -1450,7 +1467,6 @@ static sense_reason_t core_scsi3_decode_spec_i_port( struct se_cmd *cmd, struct se_portal_group *tpg, - struct se_dev_entry *local_se_deve, unsigned char *l_isid, u64 sa_res_key, int all_tg_pt, @@ -1461,7 +1477,7 @@ core_scsi3_decode_spec_i_port( struct se_portal_group *dest_tpg = NULL, *tmp_tpg; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *dest_node_acl = NULL; - struct se_dev_entry __rcu *dest_se_deve = NULL; + struct se_dev_entry *dest_se_deve = NULL; struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; LIST_HEAD(tid_dest_list); @@ -1471,14 +1487,12 @@ core_scsi3_decode_spec_i_port( char *iport_ptr = NULL, i_buf[PR_REG_ISID_ID_LEN]; sense_reason_t ret; u32 tpdl, tid_len = 0; - int dest_local_nexus; u32 dest_rtpi = 0; /* * Allocate a struct pr_transport_id_holder and setup the - * local_node_acl and local_se_deve pointers and add to - * struct list_head tid_dest_list for add registration - * processing in the loop of tid_dest_list below. + * local_node_acl pointer and add to struct list_head tid_dest_list + * for add registration processing in the loop of tid_dest_list below. */ tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); if (!tidh_new) { @@ -1490,20 +1504,20 @@ core_scsi3_decode_spec_i_port( tidh_new->dest_node_acl = se_sess->se_node_acl; local_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, - se_sess->se_node_acl, local_se_deve, l_isid, + se_sess->se_node_acl, cmd->se_lun, + NULL, cmd->orig_fe_lun, l_isid, sa_res_key, all_tg_pt, aptpl); if (!local_pr_reg) { kfree(tidh_new); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - rcu_assign_pointer(tidh_new->dest_se_deve, local_se_deve); tidh_new->dest_pr_reg = local_pr_reg; /* * The local I_T nexus does not hold any configfs dependances, - * so we set tid_h->dest_local_nexus=1 to prevent the + * so we set tidh_new->dest_se_deve to NULL to prevent the * configfs_undepend_item() calls in the tid_dest_list loops below. */ - tidh_new->dest_local_nexus = 1; + tidh_new->dest_se_deve = NULL; list_add_tail(&tidh_new->dest_list, &tid_dest_list); if (cmd->data_length < 28) { @@ -1544,6 +1558,8 @@ core_scsi3_decode_spec_i_port( ptr = &buf[28]; while (tpdl > 0) { + struct se_lun *dest_lun; + proto_ident = (ptr[0] & 0x0f); dest_tpg = NULL; @@ -1720,9 +1736,13 @@ core_scsi3_decode_spec_i_port( * and then call __core_scsi3_add_registration() in the * 2nd loop which will never fail. */ + dest_lun = rcu_dereference_check(dest_se_deve->se_lun, + atomic_read(&dest_se_deve->pr_kref.refcount) != 0); + dest_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, - dest_node_acl, dest_se_deve, iport_ptr, - sa_res_key, all_tg_pt, aptpl); + dest_node_acl, dest_lun, dest_se_deve, + dest_se_deve->mapped_lun, iport_ptr, + sa_res_key, all_tg_pt, aptpl); if (!dest_pr_reg) { core_scsi3_lunacl_undepend_item(dest_se_deve); core_scsi3_nodeacl_undepend_item(dest_node_acl); @@ -1760,7 +1780,6 @@ core_scsi3_decode_spec_i_port( dest_node_acl = tidh->dest_node_acl; dest_se_deve = tidh->dest_se_deve; dest_pr_reg = tidh->dest_pr_reg; - dest_local_nexus = tidh->dest_local_nexus; list_del(&tidh->dest_list); kfree(tidh); @@ -1774,9 +1793,10 @@ core_scsi3_decode_spec_i_port( pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully" " registered Transport ID for Node: %s%s Mapped LUN:" " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), - dest_node_acl->initiatorname, i_buf, dest_se_deve->mapped_lun); + dest_node_acl->initiatorname, i_buf, (dest_se_deve) ? + dest_se_deve->mapped_lun : 0); - if (dest_local_nexus) + if (!dest_se_deve) continue; core_scsi3_lunacl_undepend_item(dest_se_deve); @@ -1797,7 +1817,6 @@ out: dest_node_acl = tidh->dest_node_acl; dest_se_deve = tidh->dest_se_deve; dest_pr_reg = tidh->dest_pr_reg; - dest_local_nexus = tidh->dest_local_nexus; list_del(&tidh->dest_list); kfree(tidh); @@ -1815,7 +1834,7 @@ out: kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); - if (dest_local_nexus) + if (!dest_se_deve) continue; core_scsi3_lunacl_undepend_item(dest_se_deve); @@ -1830,7 +1849,6 @@ static int core_scsi3_update_aptpl_buf( unsigned char *buf, u32 pr_aptpl_buf_len) { - struct se_lun *lun; struct se_portal_group *tpg; struct t10_pr_registration *pr_reg; unsigned char tmp[512], isid_buf[32]; @@ -1849,7 +1867,6 @@ static int core_scsi3_update_aptpl_buf( tmp[0] = '\0'; isid_buf[0] = '\0'; tpg = pr_reg->pr_reg_nacl->se_tpg; - lun = pr_reg->pr_reg_tg_pt_lun; /* * Write out any ISID value to APTPL metadata that was included * in the original registration. @@ -1901,7 +1918,8 @@ static int core_scsi3_update_aptpl_buf( " %d\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpg->se_tpg_tfo->tpg_get_tag(tpg), - lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count); + pr_reg->tg_pt_sep_rtpi, pr_reg->pr_aptpl_target_lun, + reg_count); if ((len + strlen(tmp) >= pr_aptpl_buf_len)) { pr_err("Unable to update renaming APTPL metadata," @@ -2011,9 +2029,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type) { struct se_session *se_sess = cmd->se_sess; - struct se_node_acl *nacl = se_sess->se_node_acl; struct se_device *dev = cmd->se_dev; - struct se_dev_entry *se_deve; struct se_lun *se_lun = cmd->se_lun; struct se_portal_group *se_tpg; struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp; @@ -2028,14 +2044,6 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, } se_tpg = se_sess->se_tpg; - rcu_read_lock(); - se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); - if (!se_deve) { - pr_err("Unable to locate se_deve for PRO-REGISTER\n"); - rcu_read_unlock(); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - if (se_tpg->se_tpg_tfo->sess_get_initiator_sid) { memset(&isid_buf[0], 0, PR_REG_ISID_LEN); se_tpg->se_tpg_tfo->sess_get_initiator_sid(se_sess, &isid_buf[0], @@ -2050,16 +2058,14 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, if (res_key) { pr_warn("SPC-3 PR: Reservation Key non-zero" " for SA REGISTER, returning CONFLICT\n"); - rcu_read_unlock(); return TCM_RESERVATION_CONFLICT; } /* * Do nothing but return GOOD status. */ - if (!sa_res_key) { - rcu_read_unlock(); + if (!sa_res_key) return 0; - } + if (!spec_i_pt) { /* * Perform the Service Action REGISTER on the Initiator @@ -2067,12 +2073,12 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * Logical Unit of the SCSI device server. */ if (core_scsi3_alloc_registration(cmd->se_dev, - se_sess->se_node_acl, se_deve, isid_ptr, + se_sess->se_node_acl, cmd->se_lun, + NULL, cmd->orig_fe_lun, isid_ptr, sa_res_key, all_tg_pt, aptpl, register_type, 0)) { pr_err("Unable to allocate" " struct t10_pr_registration\n"); - rcu_read_unlock(); return TCM_INVALID_PARAMETER_LIST; } } else { @@ -2084,17 +2090,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * logic from of core_scsi3_alloc_registration() for * each TransportID provided SCSI Initiator Port/Device */ - ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, se_deve, + ret = core_scsi3_decode_spec_i_port(cmd, se_tpg, isid_ptr, sa_res_key, all_tg_pt, aptpl); - if (ret != 0) { - rcu_read_unlock(); + if (ret != 0) return ret; - } } - rcu_read_unlock(); return core_scsi3_update_and_write_aptpl(dev, aptpl); } - rcu_read_unlock(); /* ok, existing registration */ @@ -3440,10 +3442,13 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { + struct se_lun *dest_lun = rcu_dereference_check(dest_se_deve->se_lun, + atomic_read(&dest_se_deve->pr_kref.refcount) != 0); + spin_unlock(&dev->dev_reservation_lock); - if (core_scsi3_alloc_registration(cmd->se_dev, - dest_node_acl, dest_se_deve, iport_ptr, - sa_res_key, 0, aptpl, 2, 1)) { + if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, + dest_lun, dest_se_deve, dest_se_deve->mapped_lun, + iport_ptr, sa_res_key, 0, aptpl, 2, 1)) { ret = TCM_INVALID_PARAMETER_LIST; goto out; } @@ -4011,10 +4016,10 @@ core_scsi3_pri_read_full_status(struct se_cmd *cmd) * IDENTIFIER field are not defined by this standard. */ if (!pr_reg->pr_reg_all_tg_pt) { - struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep; + u16 sep_rtpi = pr_reg->tg_pt_sep_rtpi; - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((sep_rtpi >> 8) & 0xff); + buf[off++] = (sep_rtpi & 0xff); } else off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFIER */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 508528a5e927..cf3c6addf05a 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -372,13 +372,14 @@ struct t10_pr_registration { bool isid_present_at_reg; u32 pr_res_mapped_lun; u32 pr_aptpl_target_lun; + u16 tg_pt_sep_rtpi; u32 pr_res_generation; u64 pr_reg_bin_isid; u64 pr_res_key; atomic_t pr_res_holders; struct se_node_acl *pr_reg_nacl; + /* Used by ALL_TG_PT=1 registration with deve->pr_ref taken */ struct se_dev_entry *pr_reg_deve; - struct se_lun *pr_reg_tg_pt_lun; struct list_head pr_reg_list; struct list_head pr_reg_abort_list; struct list_head pr_reg_aptpl_list; @@ -498,7 +499,6 @@ struct se_cmd { struct list_head se_delayed_node; struct list_head se_qf_node; struct se_device *se_dev; - struct se_dev_entry *se_deve; struct se_lun *se_lun; /* Only used for internal passthrough and legacy TCM fabric modules */ struct se_session *se_sess; -- cgit v1.2.3 From 6bb826121be244a5a3c8bd8b7d45c47df18810b7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 10 May 2015 19:31:10 -0700 Subject: target: Convert se_portal_group->tpg_lun_list[] to RCU hlist This patch converts the fixed size se_portal_group->tpg_lun_list[] to use modern RCU with hlist_head in order to support an arbitary number of se_lun ports per target endpoint. It includes dropping core_tpg_alloc_lun() from core_dev_add_lun(), and calling it directly from target_fabric_make_lun() to allocate a new se_lun. And add a new target_fabric_port_release() configfs item callback to invoke kfree_rcu() to release memory during se_lun->lun_group shutdown. Also now that se_node_acl->lun_entry_hlist is using RCU, convert existing tpg_lun_lock to struct mutex so core_tpg_add_node_to_devs() can perform RCU updater logic without releasing ->tpg_lun_mutex. Also, drop core_tpg_clear_object_luns() and it's single consumer in iscsi-target, which is duplicating TPG LUN shutdown logic and is current code results in a NOP. Finally, sbp-target and xen-scsiback fabric driver conversions are included, which are required due to the non-standard way they use ->tpg_lun_hlist. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Cc: Paul E. McKenney Cc: Chris Boot Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_tpg.c | 2 - drivers/target/sbp/sbp_target.c | 97 +++++++++----------- drivers/target/sbp/sbp_target.h | 2 +- drivers/target/target_core_device.c | 92 ++----------------- drivers/target/target_core_fabric_configfs.c | 34 ++++--- drivers/target/target_core_internal.h | 6 +- drivers/target/target_core_tpg.c | 132 ++++++--------------------- drivers/xen/xen-scsiback.c | 27 +++--- include/target/target_core_base.h | 6 +- include/target/target_core_fabric.h | 1 - 10 files changed, 122 insertions(+), 277 deletions(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index d4ac31fc2acd..de8829102ab4 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -278,8 +278,6 @@ int iscsit_tpg_del_portal_group( return -EPERM; } - core_tpg_clear_object_luns(&tpg->tpg_se_tpg); - if (tpg->param_list) { iscsi_release_param_list(tpg->param_list); tpg->param_list = NULL; diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 5d7755edc668..47fb12fbaf47 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -108,13 +108,13 @@ static struct sbp_session *sbp_session_find_by_guid( } static struct sbp_login_descriptor *sbp_login_find_by_lun( - struct sbp_session *session, struct se_lun *lun) + struct sbp_session *session, u32 unpacked_lun) { struct sbp_login_descriptor *login, *found = NULL; spin_lock_bh(&session->lock); list_for_each_entry(login, &session->login_list, link) { - if (login->lun == lun) + if (login->login_lun == unpacked_lun) found = login; } spin_unlock_bh(&session->lock); @@ -124,7 +124,7 @@ static struct sbp_login_descriptor *sbp_login_find_by_lun( static int sbp_login_count_all_by_lun( struct sbp_tpg *tpg, - struct se_lun *lun, + u32 unpacked_lun, int exclusive) { struct se_session *se_sess; @@ -138,7 +138,7 @@ static int sbp_login_count_all_by_lun( spin_lock_bh(&sess->lock); list_for_each_entry(login, &sess->login_list, link) { - if (login->lun != lun) + if (login->login_lun != unpacked_lun) continue; if (!exclusive || login->exclusive) @@ -174,23 +174,23 @@ static struct sbp_login_descriptor *sbp_login_find_by_id( return found; } -static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun) +static u32 sbp_get_lun_from_tpg(struct sbp_tpg *tpg, u32 login_lun, int *err) { struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_lun *se_lun; - if (lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return ERR_PTR(-EINVAL); - - spin_lock(&se_tpg->tpg_lun_lock); - se_lun = se_tpg->tpg_lun_list[lun]; - - if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) - se_lun = ERR_PTR(-ENODEV); - - spin_unlock(&se_tpg->tpg_lun_lock); + rcu_read_lock(); + hlist_for_each_entry_rcu(se_lun, &se_tpg->tpg_lun_hlist, link) { + if (se_lun->unpacked_lun == login_lun) { + rcu_read_unlock(); + *err = 0; + return login_lun; + } + } + rcu_read_unlock(); - return se_lun; + *err = -ENODEV; + return login_lun; } static struct sbp_session *sbp_session_create( @@ -294,17 +294,16 @@ static void sbp_management_request_login( { struct sbp_tport *tport = agent->tport; struct sbp_tpg *tpg = tport->tpg; - struct se_lun *se_lun; - int ret; - u64 guid; struct sbp_session *sess; struct sbp_login_descriptor *login; struct sbp_login_response_block *response; - int login_response_len; + u64 guid; + u32 unpacked_lun; + int login_response_len, ret; - se_lun = sbp_get_lun_from_tpg(tpg, - LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); - if (IS_ERR(se_lun)) { + unpacked_lun = sbp_get_lun_from_tpg(tpg, + LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)), &ret); + if (ret) { pr_notice("login to unknown LUN: %d\n", LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc))); @@ -325,11 +324,11 @@ static void sbp_management_request_login( } pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n", - se_lun->unpacked_lun, guid); + unpacked_lun, guid); sess = sbp_session_find_by_guid(tpg, guid); if (sess) { - login = sbp_login_find_by_lun(sess, se_lun); + login = sbp_login_find_by_lun(sess, unpacked_lun); if (login) { pr_notice("initiator already logged-in\n"); @@ -357,7 +356,7 @@ static void sbp_management_request_login( * reject with access_denied if any logins present */ if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) && - sbp_login_count_all_by_lun(tpg, se_lun, 0)) { + sbp_login_count_all_by_lun(tpg, unpacked_lun, 0)) { pr_warn("refusing exclusive login with other active logins\n"); req->status.status = cpu_to_be32( @@ -370,7 +369,7 @@ static void sbp_management_request_login( * check exclusive bit in any existing login descriptor * reject with access_denied if any exclusive logins present */ - if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) { + if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 1)) { pr_warn("refusing login while another exclusive login present\n"); req->status.status = cpu_to_be32( @@ -383,7 +382,7 @@ static void sbp_management_request_login( * check we haven't exceeded the number of allowed logins * reject with resources_unavailable if we have */ - if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >= + if (sbp_login_count_all_by_lun(tpg, unpacked_lun, 0) >= tport->max_logins_per_lun) { pr_warn("max number of logins reached\n"); @@ -439,7 +438,7 @@ static void sbp_management_request_login( } login->sess = sess; - login->lun = se_lun; + login->login_lun = unpacked_lun; login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo); login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)); login->login_id = atomic_inc_return(&login_id); @@ -601,7 +600,7 @@ static void sbp_management_request_logout( } pr_info("mgt_agent LOGOUT from LUN %d session %d\n", - login->lun->unpacked_lun, login->login_id); + login->login_lun, login->login_id); if (req->node_addr != login->sess->node_id) { pr_warn("logout from different node ID\n"); @@ -1227,7 +1226,7 @@ static void sbp_handle_command(struct sbp_target_request *req) goto err; } - unpacked_lun = req->login->lun->unpacked_lun; + unpacked_lun = req->login->login_lun; sbp_calc_data_length_direction(req, &data_length, &data_dir); pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n", @@ -1826,25 +1825,21 @@ static int sbp_check_stop_free(struct se_cmd *se_cmd) static int sbp_count_se_tpg_luns(struct se_portal_group *tpg) { - int i, count = 0; - - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - struct se_lun *se_lun = tpg->tpg_lun_list[i]; - - if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) - continue; + struct se_lun *lun; + int count = 0; + rcu_read_lock(); + hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) count++; - } - spin_unlock(&tpg->tpg_lun_lock); + rcu_read_unlock(); return count; } static int sbp_update_unit_directory(struct sbp_tport *tport) { - int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i; + struct se_lun *lun; + int num_luns, num_entries, idx = 0, mgt_agt_addr, ret; u32 *data; if (tport->unit_directory.data) { @@ -1906,28 +1901,20 @@ static int sbp_update_unit_directory(struct sbp_tport *tport) /* unit unique ID (leaf is just after LUNs) */ data[idx++] = 0x8d000000 | (num_luns + 1); - spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i]; + rcu_read_lock(); + hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { struct se_device *dev; int type; - if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE) - continue; - - spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); - - dev = se_lun->lun_se_dev; + dev = lun->lun_se_dev; type = dev->transport->get_device_type(dev); /* logical_unit_number */ data[idx++] = 0x14000000 | ((type << 16) & 0x1f0000) | - (se_lun->unpacked_lun & 0xffff); - - spin_lock(&tport->tpg->se_tpg.tpg_lun_lock); + (lun->unpacked_lun & 0xffff); } - spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock); + rcu_read_unlock(); /* unit unique ID leaf */ data[idx++] = 2 << 16; diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h index e1b0b84f7379..73bcb1208832 100644 --- a/drivers/target/sbp/sbp_target.h +++ b/drivers/target/sbp/sbp_target.h @@ -125,7 +125,7 @@ struct sbp_login_descriptor { struct sbp_session *sess; struct list_head link; - struct se_lun *lun; + u32 login_lun; u64 status_fifo_addr; int exclusive; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 97792cc81fe4..431e5fc8daec 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1172,22 +1172,17 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size) } EXPORT_SYMBOL(se_dev_set_block_size); -struct se_lun *core_dev_add_lun( +int core_dev_add_lun( struct se_portal_group *tpg, struct se_device *dev, - u32 unpacked_lun) + struct se_lun *lun) { - struct se_lun *lun; int rc; - lun = core_tpg_alloc_lun(tpg, unpacked_lun); - if (IS_ERR(lun)) - return lun; - rc = core_tpg_add_lun(tpg, lun, TRANSPORT_LUNFLAGS_READ_WRITE, dev); if (rc < 0) - return ERR_PTR(rc); + return rc; pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -1212,7 +1207,7 @@ struct se_lun *core_dev_add_lun( spin_unlock_irq(&tpg->acl_node_lock); } - return lun; + return 0; } /* core_dev_del_lun(): @@ -1231,68 +1226,6 @@ void core_dev_del_lun( core_tpg_remove_lun(tpg, lun); } -struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_lun) -{ - struct se_lun *lun; - - spin_lock(&tpg->tpg_lun_lock); - if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS" - "_PER_TPG-1: %u for Target Portal Group: %hu\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - TRANSPORT_MAX_LUNS_PER_TPG-1, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - lun = tpg->tpg_lun_list[unpacked_lun]; - - if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) { - pr_err("%s Logical Unit Number: %u is not free on" - " Target Portal Group: %hu, ignoring request.\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - spin_unlock(&tpg->tpg_lun_lock); - - return lun; -} - -/* core_dev_get_lun(): - * - * - */ -static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked_lun) -{ - struct se_lun *lun; - - spin_lock(&tpg->tpg_lun_lock); - if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER" - "_TPG-1: %u for Target Portal Group: %hu\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - TRANSPORT_MAX_LUNS_PER_TPG-1, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - lun = tpg->tpg_lun_list[unpacked_lun]; - - if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { - pr_err("%s Logical Unit Number: %u is not active on" - " Target Portal Group: %hu, ignoring request.\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return NULL; - } - spin_unlock(&tpg->tpg_lun_lock); - - return lun; -} - struct se_lun_acl *core_dev_init_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_node_acl *nacl, @@ -1326,22 +1259,11 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( int core_dev_add_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_lun_acl *lacl, - u32 unpacked_lun, + struct se_lun *lun, u32 lun_access) { - struct se_lun *lun; - struct se_node_acl *nacl; + struct se_node_acl *nacl = lacl->se_lun_nacl; - lun = core_dev_get_lun(tpg, unpacked_lun); - if (!lun) { - pr_err("%s Logical Unit Number: %u is not active on" - " Target Portal Group: %hu, ignoring request.\n", - tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - return -EINVAL; - } - - nacl = lacl->se_lun_nacl; if (!nacl) return -EINVAL; @@ -1362,7 +1284,7 @@ int core_dev_add_initiator_node_lun_acl( pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), - tpg->se_tpg_tfo->tpg_get_tag(tpg), unpacked_lun, lacl->mapped_lun, + tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", lacl->initiatorname); /* diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 0939a5492c16..9be8030e016f 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -81,7 +81,7 @@ static int target_fabric_mappedlun_link( struct se_lun_acl, se_lun_group); struct se_portal_group *se_tpg; struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s; - int ret = 0, lun_access; + int lun_access; if (lun->lun_link_magic != SE_LUN_LINK_MAGIC) { pr_err("Bad lun->lun_link_magic, not a valid lun_ci pointer:" @@ -137,12 +137,9 @@ static int target_fabric_mappedlun_link( * Determine the actual mapped LUN value user wants.. * * This value is what the SCSI Initiator actually sees the - * iscsi/$IQN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. + * $FABRIC/$WWPN/$TPGT/lun/lun_* as on their SCSI Initiator Ports. */ - ret = core_dev_add_initiator_node_lun_acl(se_tpg, lacl, - lun->unpacked_lun, lun_access); - - return (ret < 0) ? -EINVAL : 0; + return core_dev_add_initiator_node_lun_acl(se_tpg, lacl, lun, lun_access); } static int target_fabric_mappedlun_unlink( @@ -761,7 +758,6 @@ static int target_fabric_port_link( struct config_item *tpg_ci; struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - struct se_lun *lun_p; struct se_portal_group *se_tpg; struct se_device *dev = container_of(to_config_group(se_dev_ci), struct se_device, dev_group); @@ -789,10 +785,9 @@ static int target_fabric_port_link( return -EEXIST; } - lun_p = core_dev_add_lun(se_tpg, dev, lun->unpacked_lun); - if (IS_ERR(lun_p)) { - pr_err("core_dev_add_lun() failed\n"); - ret = PTR_ERR(lun_p); + ret = core_dev_add_lun(se_tpg, dev, lun); + if (ret) { + pr_err("core_dev_add_lun() failed: %d\n", ret); goto out; } @@ -832,9 +827,18 @@ static int target_fabric_port_unlink( return 0; } +static void target_fabric_port_release(struct config_item *item) +{ + struct se_lun *lun = container_of(to_config_group(item), + struct se_lun, lun_group); + + kfree_rcu(lun, rcu_head); +} + static struct configfs_item_operations target_fabric_port_item_ops = { .show_attribute = target_fabric_port_attr_show, .store_attribute = target_fabric_port_attr_store, + .release = target_fabric_port_release, .allow_link = target_fabric_port_link, .drop_link = target_fabric_port_unlink, }; @@ -893,15 +897,16 @@ static struct config_group *target_fabric_make_lun( if (unpacked_lun > UINT_MAX) return ERR_PTR(-EINVAL); - lun = core_get_lun_from_tpg(se_tpg, unpacked_lun); - if (!lun) - return ERR_PTR(-EINVAL); + lun = core_tpg_alloc_lun(se_tpg, unpacked_lun); + if (IS_ERR(lun)) + return ERR_CAST(lun); lun_cg = &lun->lun_group; lun_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2, GFP_KERNEL); if (!lun_cg->default_groups) { pr_err("Unable to allocate lun_cg->default_groups\n"); + kfree(lun); return ERR_PTR(-ENOMEM); } @@ -918,6 +923,7 @@ static struct config_group *target_fabric_make_lun( if (!port_stat_grp->default_groups) { pr_err("Unable to allocate port_stat_grp->default_groups\n"); kfree(lun_cg->default_groups); + kfree(lun); return ERR_PTR(-ENOMEM); } target_stat_setup_port_default_groups(lun); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index a04a6e396ae3..2c160ceaf03f 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -23,13 +23,13 @@ int core_dev_export(struct se_device *, struct se_portal_group *, struct se_lun *); void core_dev_unexport(struct se_device *, struct se_portal_group *, struct se_lun *); -struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_device *, u32); +int core_dev_add_lun(struct se_portal_group *, struct se_device *, + struct se_lun *lun); void core_dev_del_lun(struct se_portal_group *, struct se_lun *); -struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, struct se_node_acl *, u32, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun_acl *, u32, u32); + struct se_lun_acl *, struct se_lun *lun, u32); int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, struct se_lun *, struct se_lun_acl *); void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 0519923ef930..13d34e22a3c4 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -91,19 +91,15 @@ void core_tpg_add_node_to_devs( struct se_node_acl *acl, struct se_portal_group *tpg) { - int i = 0; u32 lun_access = 0; struct se_lun *lun; struct se_device *dev; - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = tpg->tpg_lun_list[i]; + mutex_lock(&tpg->tpg_lun_mutex); + hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) { if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) continue; - spin_unlock(&tpg->tpg_lun_lock); - dev = lun->lun_se_dev; /* * By default in LIO-Target $FABRIC_MOD, @@ -130,7 +126,7 @@ void core_tpg_add_node_to_devs( "READ-WRITE" : "READ-ONLY"); core_enable_device_list_for_node(lun, NULL, lun->unpacked_lun, - lun_access, acl, tpg); + lun_access, acl, tpg); /* * Check to see if there are any existing persistent reservation * APTPL pre-registrations that need to be enabled for this dynamic @@ -138,9 +134,8 @@ void core_tpg_add_node_to_devs( */ core_scsi3_check_aptpl_registration(dev, tpg, lun, acl, lun->unpacked_lun); - spin_lock(&tpg->tpg_lun_lock); } - spin_unlock(&tpg->tpg_lun_lock); + mutex_unlock(&tpg->tpg_lun_mutex); } /* core_set_queue_depth_for_node(): @@ -161,34 +156,6 @@ static int core_set_queue_depth_for_node( return 0; } -void array_free(void *array, int n) -{ - void **a = array; - int i; - - for (i = 0; i < n; i++) - kfree(a[i]); - kfree(a); -} - -static void *array_zalloc(int n, size_t size, gfp_t flags) -{ - void **a; - int i; - - a = kzalloc(n * sizeof(void*), flags); - if (!a) - return NULL; - for (i = 0; i < n; i++) { - a[i] = kzalloc(size, flags); - if (!a[i]) { - array_free(a, n); - return NULL; - } - } - return a; -} - static struct se_node_acl *target_alloc_node_acl(struct se_portal_group *tpg, const unsigned char *initiatorname) { @@ -284,27 +251,6 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl) cpu_relax(); } -void core_tpg_clear_object_luns(struct se_portal_group *tpg) -{ - int i; - struct se_lun *lun; - - spin_lock(&tpg->tpg_lun_lock); - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = tpg->tpg_lun_list[i]; - - if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) || - (lun->lun_se_dev == NULL)) - continue; - - spin_unlock(&tpg->tpg_lun_lock); - core_dev_del_lun(tpg, lun); - spin_lock(&tpg->tpg_lun_lock); - } - spin_unlock(&tpg->tpg_lun_lock); -} -EXPORT_SYMBOL(core_tpg_clear_object_luns); - struct se_node_acl *core_tpg_add_initiator_node_acl( struct se_portal_group *tpg, const char *initiatorname) @@ -567,30 +513,7 @@ int core_tpg_register( struct se_portal_group *se_tpg, int proto_id) { - struct se_lun *lun; - u32 i; - - se_tpg->tpg_lun_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG, - sizeof(struct se_lun), GFP_KERNEL); - if (!se_tpg->tpg_lun_list) { - pr_err("Unable to allocate struct se_portal_group->" - "tpg_lun_list\n"); - return -ENOMEM; - } - - for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = se_tpg->tpg_lun_list[i]; - lun->unpacked_lun = i; - lun->lun_link_magic = SE_LUN_LINK_MAGIC; - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; - atomic_set(&lun->lun_acl_count, 0); - init_completion(&lun->lun_shutdown_comp); - INIT_LIST_HEAD(&lun->lun_acl_list); - spin_lock_init(&lun->lun_acl_lock); - spin_lock_init(&lun->lun_sep_lock); - init_completion(&lun->lun_ref_comp); - } - + INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); se_tpg->proto_id = proto_id; se_tpg->se_tpg_tfo = tfo; se_tpg->se_tpg_wwn = se_wwn; @@ -600,14 +523,11 @@ int core_tpg_register( INIT_LIST_HEAD(&se_tpg->tpg_sess_list); spin_lock_init(&se_tpg->acl_node_lock); spin_lock_init(&se_tpg->session_lock); - spin_lock_init(&se_tpg->tpg_lun_lock); + mutex_init(&se_tpg->tpg_lun_mutex); if (se_tpg->proto_id >= 0) { - if (core_tpg_setup_virtual_lun0(se_tpg) < 0) { - array_free(se_tpg->tpg_lun_list, - TRANSPORT_MAX_LUNS_PER_TPG); + if (core_tpg_setup_virtual_lun0(se_tpg) < 0) return -ENOMEM; - } } spin_lock_bh(&tpg_lock); @@ -662,7 +582,6 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); - array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); return 0; } EXPORT_SYMBOL(core_tpg_deregister); @@ -682,17 +601,20 @@ struct se_lun *core_tpg_alloc_lun( return ERR_PTR(-EOVERFLOW); } - spin_lock(&tpg->tpg_lun_lock); - lun = tpg->tpg_lun_list[unpacked_lun]; - if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) { - pr_err("TPG Logical Unit Number: %u is already active" - " on %s Target Portal Group: %u, ignoring request.\n", - unpacked_lun, tpg->se_tpg_tfo->get_fabric_name(), - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&tpg->tpg_lun_lock); - return ERR_PTR(-EINVAL); + lun = kzalloc(sizeof(*lun), GFP_KERNEL); + if (!lun) { + pr_err("Unable to allocate se_lun memory\n"); + return ERR_PTR(-ENOMEM); } - spin_unlock(&tpg->tpg_lun_lock); + lun->unpacked_lun = unpacked_lun; + lun->lun_link_magic = SE_LUN_LINK_MAGIC; + lun->lun_status = TRANSPORT_LUN_STATUS_FREE; + atomic_set(&lun->lun_acl_count, 0); + init_completion(&lun->lun_shutdown_comp); + INIT_LIST_HEAD(&lun->lun_acl_list); + spin_lock_init(&lun->lun_acl_lock); + spin_lock_init(&lun->lun_sep_lock); + init_completion(&lun->lun_ref_comp); return lun; } @@ -716,10 +638,12 @@ int core_tpg_add_lun( return ret; } - spin_lock(&tpg->tpg_lun_lock); + mutex_lock(&tpg->tpg_lun_mutex); lun->lun_access = lun_access; lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; - spin_unlock(&tpg->tpg_lun_lock); + if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); + mutex_unlock(&tpg->tpg_lun_mutex); return 0; } @@ -728,14 +652,18 @@ void core_tpg_remove_lun( struct se_portal_group *tpg, struct se_lun *lun) { + struct se_device *dev = lun->lun_se_dev; + core_clear_lun_from_tpg(lun, tpg); transport_clear_lun_ref(lun); core_dev_unexport(lun->lun_se_dev, tpg, lun); - spin_lock(&tpg->tpg_lun_lock); + mutex_lock(&tpg->tpg_lun_mutex); lun->lun_status = TRANSPORT_LUN_STATUS_FREE; - spin_unlock(&tpg->tpg_lun_lock); + if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + hlist_del_rcu(&lun->link); + mutex_unlock(&tpg->tpg_lun_mutex); percpu_ref_exit(&lun->lun_ref); } diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 8b7dd47abd8d..555033bd9239 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -866,7 +866,8 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, struct list_head *head = &(info->v2p_entry_lists); unsigned long flags; char *lunp; - unsigned int lun; + unsigned int unpacked_lun; + struct se_lun *se_lun; struct scsiback_tpg *tpg_entry, *tpg = NULL; char *error = "doesn't exist"; @@ -877,7 +878,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, } *lunp = 0; lunp++; - if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { + if (kstrtouint(lunp, 10, &unpacked_lun) || unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { pr_err("lun number not valid: %s\n", lunp); return -EINVAL; } @@ -886,15 +887,17 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, list_for_each_entry(tpg_entry, &scsiback_list, tv_tpg_list) { if (!strcmp(phy, tpg_entry->tport->tport_name) || !strcmp(phy, tpg_entry->param_alias)) { - spin_lock(&tpg_entry->se_tpg.tpg_lun_lock); - if (tpg_entry->se_tpg.tpg_lun_list[lun]->lun_status == - TRANSPORT_LUN_STATUS_ACTIVE) { - if (!tpg_entry->tpg_nexus) - error = "nexus undefined"; - else - tpg = tpg_entry; + mutex_lock(&tpg_entry->se_tpg.tpg_lun_mutex); + hlist_for_each_entry(se_lun, &tpg_entry->se_tpg.tpg_lun_hlist, link) { + if (se_lun->unpacked_lun == unpacked_lun) { + if (!tpg_entry->tpg_nexus) + error = "nexus undefined"; + else + tpg = tpg_entry; + break; + } } - spin_unlock(&tpg_entry->se_tpg.tpg_lun_lock); + mutex_unlock(&tpg_entry->se_tpg.tpg_lun_mutex); break; } } @@ -906,7 +909,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, mutex_unlock(&scsiback_mutex); if (!tpg) { - pr_err("%s:%d %s\n", phy, lun, error); + pr_err("%s:%d %s\n", phy, unpacked_lun, error); return -ENODEV; } @@ -934,7 +937,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, kref_init(&new->kref); new->v = *v; new->tpg = tpg; - new->lun = lun; + new->lun = unpacked_lun; list_add_tail(&new->l, head); out: diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index cf3c6addf05a..c15fa1a3b945 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -725,6 +725,8 @@ struct se_lun { struct se_port_stat_grps port_stat_grps; struct completion lun_ref_comp; struct percpu_ref lun_ref; + struct hlist_node link; + struct rcu_head rcu_head; }; struct se_dev_stat_grps { @@ -877,11 +879,11 @@ struct se_portal_group { spinlock_t acl_node_lock; /* Spinlock for adding/removing sessions */ spinlock_t session_lock; - spinlock_t tpg_lun_lock; + struct mutex tpg_lun_mutex; struct list_head se_tpg_node; /* linked list for initiator ACL list */ struct list_head acl_node_list; - struct se_lun **tpg_lun_list; + struct hlist_head tpg_lun_hlist; struct se_lun tpg_virt_lun0; /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 55654c90350d..b1e00a7d66de 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -157,7 +157,6 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *, unsigned char *); -void core_tpg_clear_object_luns(struct se_portal_group *); int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, -- cgit v1.2.3 From 403edd78a2851ef95b24c0bf5151a4ab640898d7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 8 Mar 2015 22:33:47 +0000 Subject: target: Convert se_tpg->acl_node_lock to ->acl_node_mutex This patch converts se_tpg->acl_node_lock to struct mutex, so that ->acl_node_acl walkers in core_clear_lun_from_tpg() can block when calling core_disable_device_list_for_node(). It also updates core_dev_add_lun() to hold ->acl_node_mutex when calling core_tpg_add_node_to_devs() to build ->lun_entry_hlist for dynamically generated se_node_acl. Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 14 ++++------ drivers/target/target_core_pr.c | 8 +++--- drivers/target/target_core_tpg.c | 51 +++++++++++++++++----------------- drivers/target/target_core_transport.c | 20 ++++++------- drivers/target/tcm_fc/tfc_conf.c | 4 +-- include/target/target_core_base.h | 2 +- 6 files changed, 48 insertions(+), 51 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 431e5fc8daec..1593d4965848 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -440,9 +440,8 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) struct se_node_acl *nacl; struct se_dev_entry *deve; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) { - spin_unlock_irq(&tpg->acl_node_lock); mutex_lock(&nacl->lun_entry_mutex); hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) { @@ -455,10 +454,8 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) core_disable_device_list_for_node(lun, deve, nacl, tpg); } mutex_unlock(&nacl->lun_entry_mutex); - - spin_lock_irq(&tpg->acl_node_lock); } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); } static struct se_port *core_alloc_port(struct se_device *dev) @@ -1194,17 +1191,16 @@ int core_dev_add_lun( */ if (tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) { struct se_node_acl *acl; - spin_lock_irq(&tpg->acl_node_lock); + + mutex_lock(&tpg->acl_node_mutex); list_for_each_entry(acl, &tpg->acl_node_list, acl_list) { if (acl->dynamic_node_acl && (!tpg->se_tpg_tfo->tpg_check_demo_mode_login_only || !tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg))) { - spin_unlock_irq(&tpg->acl_node_lock); core_tpg_add_node_to_devs(acl, tpg); - spin_lock_irq(&tpg->acl_node_lock); } } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); } return 0; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 1e89679ad606..b983f8a54766 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -1589,12 +1589,12 @@ core_scsi3_decode_spec_i_port( * from the decoded fabric module specific TransportID * at *i_str. */ - spin_lock_irq(&tmp_tpg->acl_node_lock); + mutex_lock(&tmp_tpg->acl_node_mutex); dest_node_acl = __core_tpg_get_initiator_node_acl( tmp_tpg, i_str); if (dest_node_acl) atomic_inc_mb(&dest_node_acl->acl_pr_ref_count); - spin_unlock_irq(&tmp_tpg->acl_node_lock); + mutex_unlock(&tmp_tpg->acl_node_mutex); if (!dest_node_acl) { core_scsi3_tpg_undepend_item(tmp_tpg); @@ -3308,12 +3308,12 @@ after_iport_check: /* * Locate the destination struct se_node_acl from the received Transport ID */ - spin_lock_irq(&dest_se_tpg->acl_node_lock); + mutex_lock(&dest_se_tpg->acl_node_mutex); dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg, initiator_str); if (dest_node_acl) atomic_inc_mb(&dest_node_acl->acl_pr_ref_count); - spin_unlock_irq(&dest_se_tpg->acl_node_lock); + mutex_unlock(&dest_se_tpg->acl_node_mutex); if (!dest_node_acl) { pr_err("Unable to locate %s dest_node_acl for" diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 13d34e22a3c4..229e8278f4fe 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -49,7 +49,7 @@ static LIST_HEAD(tpg_list); /* __core_tpg_get_initiator_node_acl(): * - * spin_lock_bh(&tpg->acl_node_lock); must be held when calling + * mutex_lock(&tpg->acl_node_mutex); must be held when calling */ struct se_node_acl *__core_tpg_get_initiator_node_acl( struct se_portal_group *tpg, @@ -75,9 +75,9 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( { struct se_node_acl *acl; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return acl; } @@ -198,10 +198,10 @@ static void target_add_node_acl(struct se_node_acl *acl) { struct se_portal_group *tpg = acl->se_tpg; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); list_add_tail(&acl->acl_list, &tpg->acl_node_list); tpg->num_node_acls++; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); pr_debug("%s_TPG[%hu] - Added %s ACL with TCQ Depth: %d for %s" " Initiator Node: %s\n", @@ -257,7 +257,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( { struct se_node_acl *acl; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); if (acl) { if (acl->dynamic_node_acl) { @@ -265,7 +265,7 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( pr_debug("%s_TPG[%u] - Replacing dynamic ACL" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return acl; } @@ -273,10 +273,10 @@ struct se_node_acl *core_tpg_add_initiator_node_acl( " Node %s already exists for TPG %u, ignoring" " request.\n", tpg->se_tpg_tfo->get_fabric_name(), initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return ERR_PTR(-EEXIST); } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); acl = target_alloc_node_acl(tpg, initiatorname); if (!acl) @@ -294,13 +294,13 @@ void core_tpg_del_initiator_node_acl(struct se_node_acl *acl) unsigned long flags; int rc; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (acl->dynamic_node_acl) { acl->dynamic_node_acl = 0; } list_del(&acl->acl_list); tpg->num_node_acls--; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); spin_lock_irqsave(&acl->nacl_sess_lock, flags); acl->acl_stop = 1; @@ -357,21 +357,21 @@ int core_tpg_set_initiator_node_queue_depth( unsigned long flags; int dynamic_acl = 0; - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname); if (!acl) { pr_err("Access Control List entry for %s Initiator" " Node %s does not exists for TPG %hu, ignoring" " request.\n", tpg->se_tpg_tfo->get_fabric_name(), initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return -ENODEV; } if (acl->dynamic_node_acl) { acl->dynamic_node_acl = 0; dynamic_acl = 1; } - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); spin_lock_irqsave(&tpg->session_lock, flags); list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) { @@ -387,10 +387,10 @@ int core_tpg_set_initiator_node_queue_depth( tpg->se_tpg_tfo->get_fabric_name(), initiatorname); spin_unlock_irqrestore(&tpg->session_lock, flags); - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (dynamic_acl) acl->dynamic_node_acl = 1; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return -EEXIST; } /* @@ -425,10 +425,10 @@ int core_tpg_set_initiator_node_queue_depth( if (init_sess) tpg->se_tpg_tfo->close_session(init_sess); - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (dynamic_acl) acl->dynamic_node_acl = 1; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return -EINVAL; } spin_unlock_irqrestore(&tpg->session_lock, flags); @@ -444,10 +444,10 @@ int core_tpg_set_initiator_node_queue_depth( initiatorname, tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_lock_irq(&tpg->acl_node_lock); + mutex_lock(&tpg->acl_node_mutex); if (dynamic_acl) acl->dynamic_node_acl = 1; - spin_unlock_irq(&tpg->acl_node_lock); + mutex_unlock(&tpg->acl_node_mutex); return 0; } @@ -521,9 +521,9 @@ int core_tpg_register( INIT_LIST_HEAD(&se_tpg->acl_node_list); INIT_LIST_HEAD(&se_tpg->se_tpg_node); INIT_LIST_HEAD(&se_tpg->tpg_sess_list); - spin_lock_init(&se_tpg->acl_node_lock); spin_lock_init(&se_tpg->session_lock); mutex_init(&se_tpg->tpg_lun_mutex); + mutex_init(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) { if (core_tpg_setup_virtual_lun0(se_tpg) < 0) @@ -559,25 +559,26 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) cpu_relax(); + /* * Release any remaining demo-mode generated se_node_acl that have * not been released because of TFO->tpg_check_demo_mode_cache() == 1 * in transport_deregister_session(). */ - spin_lock_irq(&se_tpg->acl_node_lock); + mutex_lock(&se_tpg->acl_node_mutex); list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list, acl_list) { list_del(&nacl->acl_list); se_tpg->num_node_acls--; - spin_unlock_irq(&se_tpg->acl_node_lock); + mutex_unlock(&se_tpg->acl_node_mutex); core_tpg_wait_for_nacl_pr_ref(nacl); core_free_device_list_for_node(nacl, se_tpg); kfree(nacl); - spin_lock_irq(&se_tpg->acl_node_lock); + mutex_lock(&se_tpg->acl_node_mutex); } - spin_unlock_irq(&se_tpg->acl_node_lock); + mutex_unlock(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3c2809cd8b5b..965a308e10a5 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -498,7 +498,7 @@ void transport_deregister_session(struct se_session *se_sess) const struct target_core_fabric_ops *se_tfo; struct se_node_acl *se_nacl; unsigned long flags; - bool comp_nacl = true; + bool comp_nacl = true, drop_nacl = false; if (!se_tpg) { transport_free_session(se_sess); @@ -518,22 +518,22 @@ void transport_deregister_session(struct se_session *se_sess) */ se_nacl = se_sess->se_node_acl; - spin_lock_irqsave(&se_tpg->acl_node_lock, flags); + mutex_lock(&se_tpg->acl_node_mutex); if (se_nacl && se_nacl->dynamic_node_acl) { if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) { list_del(&se_nacl->acl_list); se_tpg->num_node_acls--; - spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); - core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_free_device_list_for_node(se_nacl, se_tpg); - kfree(se_nacl); - - comp_nacl = false; - spin_lock_irqsave(&se_tpg->acl_node_lock, flags); + drop_nacl = true; } } - spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags); + mutex_unlock(&se_tpg->acl_node_mutex); + if (drop_nacl) { + core_tpg_wait_for_nacl_pr_ref(se_nacl); + core_free_device_list_for_node(se_nacl, se_tpg); + kfree(se_nacl); + comp_nacl = false; + } pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->get_fabric_name()); /* diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index ee5653139417..8e1a54f2642c 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -217,7 +217,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) struct se_portal_group *se_tpg = &tpg->se_tpg; struct se_node_acl *se_acl; - spin_lock_irq(&se_tpg->acl_node_lock); + mutex_lock(&se_tpg->acl_node_mutex); list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) { acl = container_of(se_acl, struct ft_node_acl, se_node_acl); pr_debug("acl %p port_name %llx\n", @@ -231,7 +231,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata) break; } } - spin_unlock_irq(&se_tpg->acl_node_lock); + mutex_unlock(&se_tpg->acl_node_mutex); return found; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c15fa1a3b945..2b6adace28b4 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -876,7 +876,7 @@ struct se_portal_group { /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t tpg_pr_ref_count; /* Spinlock for adding/removing ACLed Nodes */ - spinlock_t acl_node_lock; + struct mutex acl_node_mutex; /* Spinlock for adding/removing sessions */ spinlock_t session_lock; struct mutex tpg_lun_mutex; -- cgit v1.2.3 From 84786546b6ff8d50c3e4c1ea877a872cf55d485a Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 8 Mar 2015 08:04:44 +0000 Subject: target: Drop unused se_lun->lun_acl_list Reviewed-by: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 15 --------------- drivers/target/target_core_tpg.c | 4 ---- include/target/target_core_base.h | 3 --- 3 files changed, 22 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1593d4965848..ba8c65a670d8 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1243,7 +1243,6 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( return NULL; } - INIT_LIST_HEAD(&lacl->lacl_list); lacl->mapped_lun = mapped_lun; lacl->se_lun_nacl = nacl; snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", @@ -1273,11 +1272,6 @@ int core_dev_add_initiator_node_lun_acl( lun_access, nacl, tpg) < 0) return -EINVAL; - spin_lock(&lun->lun_acl_lock); - list_add_tail(&lacl->lacl_list, &lun->lun_acl_list); - atomic_inc_mb(&lun->lun_acl_count); - spin_unlock(&lun->lun_acl_lock); - pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, @@ -1304,19 +1298,12 @@ int core_dev_del_initiator_node_lun_acl( if (!nacl) return -EINVAL; - spin_lock(&lun->lun_acl_lock); - list_del(&lacl->lacl_list); - atomic_dec_mb(&lun->lun_acl_count); - spin_unlock(&lun->lun_acl_lock); - mutex_lock(&nacl->lun_entry_mutex); deve = target_nacl_find_deve(nacl, lacl->mapped_lun); if (deve) core_disable_device_list_for_node(lun, deve, nacl, tpg); mutex_unlock(&nacl->lun_entry_mutex); - lacl->se_lun = NULL; - pr_debug("%s_TPG[%hu]_LUN[%u] - Removed ACL for" " InitiatorNode: %s Mapped LUN: %u\n", tpg->se_tpg_tfo->get_fabric_name(), @@ -1446,8 +1433,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun = &dev->xcopy_lun; xcopy_lun->lun_se_dev = dev; init_completion(&xcopy_lun->lun_shutdown_comp); - INIT_LIST_HEAD(&xcopy_lun->lun_acl_list); - spin_lock_init(&xcopy_lun->lun_acl_lock); spin_lock_init(&xcopy_lun->lun_sep_lock); init_completion(&xcopy_lun->lun_ref_comp); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index e7745d21075b..73c25bda5a25 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -495,8 +495,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); - INIT_LIST_HEAD(&lun->lun_acl_list); - spin_lock_init(&lun->lun_acl_lock); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); @@ -610,8 +608,6 @@ struct se_lun *core_tpg_alloc_lun( lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); - INIT_LIST_HEAD(&lun->lun_acl_list); - spin_lock_init(&lun->lun_acl_lock); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 2b6adace28b4..7908d6d04f91 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -632,7 +632,6 @@ struct se_lun_acl { u32 mapped_lun; struct se_node_acl *se_lun_nacl; struct se_lun *se_lun; - struct list_head lacl_list; struct config_group se_lun_group; struct se_ml_stat_grps ml_stat_grps; }; @@ -715,10 +714,8 @@ struct se_lun { u32 unpacked_lun; u32 lun_index; atomic_t lun_acl_count; - spinlock_t lun_acl_lock; spinlock_t lun_sep_lock; struct completion lun_shutdown_comp; - struct list_head lun_acl_list; struct se_device *lun_se_dev; struct se_port *lun_sep; struct config_group lun_group; -- cgit v1.2.3 From 4624773765699ac3f4e0b918306b638cba385713 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Sun, 24 May 2015 00:48:54 -0700 Subject: target: Drop left-over se_lun->lun_status Now that se_portal_group->tpg_lun_hlist is a RCU protected hlist, go ahead and drop the left-over lun->lun_status usage. Reported-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_tpg.c | 6 ------ include/target/target_core_base.h | 8 -------- 2 files changed, 14 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index f66c208386f8..91f8ddb6d783 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -98,8 +98,6 @@ void core_tpg_add_node_to_devs( mutex_lock(&tpg->tpg_lun_mutex); hlist_for_each_entry_rcu(lun, &tpg->tpg_lun_hlist, link) { - if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) - continue; if (lun_orig && lun != lun_orig) continue; @@ -495,7 +493,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) int ret; lun->unpacked_lun = 0; - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); @@ -608,7 +605,6 @@ struct se_lun *core_tpg_alloc_lun( } lun->unpacked_lun = unpacked_lun; lun->lun_link_magic = SE_LUN_LINK_MAGIC; - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); @@ -638,7 +634,6 @@ int core_tpg_add_lun( mutex_lock(&tpg->tpg_lun_mutex); lun->lun_access = lun_access; - lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); mutex_unlock(&tpg->tpg_lun_mutex); @@ -658,7 +653,6 @@ void core_tpg_remove_lun( core_dev_unexport(lun->lun_se_dev, tpg, lun); mutex_lock(&tpg->tpg_lun_mutex); - lun->lun_status = TRANSPORT_LUN_STATUS_FREE; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_del_rcu(&lun->link); mutex_unlock(&tpg->tpg_lun_mutex); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7908d6d04f91..78ed2a83838c 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -119,12 +119,6 @@ enum hba_flags_table { HBA_FLAGS_PSCSI_MODE = 0x02, }; -/* struct se_lun->lun_status */ -enum transport_lun_status_table { - TRANSPORT_LUN_STATUS_FREE = 0, - TRANSPORT_LUN_STATUS_ACTIVE = 1, -}; - /* Special transport agnostic struct se_cmd->t_states */ enum transport_state_table { TRANSPORT_NO_STATE = 0, @@ -707,8 +701,6 @@ struct se_lun { u16 lun_rtpi; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; - /* See transport_lun_status_table */ - enum transport_lun_status_table lun_status; u32 lun_access; u32 lun_flags; u32 unpacked_lun; -- cgit v1.2.3 From 0a06d4309dc168dfa70cec3cf0cd9eb7fc15a2fd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 10 May 2015 18:14:56 +0200 Subject: target: simplify backend driver registration Rewrite the backend driver registration based on what we did to the fabric drivers: introduce a read-only struct target_bakckend_ops that the driver registers, which is then instanciate as a struct target_backend by the core. This allows the ops vector to be smaller and allows us to mark it const. At the same time the registration function can set up the configfs attributes, avoiding the need to add additional boilerplate code for that to the drivers. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 68 +++++++++++++------------ drivers/target/target_core_device.c | 6 +-- drivers/target/target_core_file.c | 16 ++---- drivers/target/target_core_hba.c | 96 ++++++++++++++++++++--------------- drivers/target/target_core_iblock.c | 18 ++----- drivers/target/target_core_internal.h | 16 ++++++ drivers/target/target_core_pscsi.c | 14 ++--- drivers/target/target_core_rd.c | 22 ++------ drivers/target/target_core_user.c | 11 ++-- include/target/target_core_backend.h | 22 ++------ include/target/target_core_base.h | 4 +- 11 files changed, 135 insertions(+), 158 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 4a31d4765390..57c099dd9da5 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -51,15 +51,26 @@ #include "target_core_xcopy.h" #define TB_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ -static void target_core_setup_##_name##_cit(struct se_subsystem_api *sa) \ +static void target_core_setup_##_name##_cit(struct target_backend *tb) \ { \ - struct target_backend_cits *tbc = &sa->tb_cits; \ - struct config_item_type *cit = &tbc->tb_##_name##_cit; \ + struct config_item_type *cit = &tb->tb_##_name##_cit; \ \ cit->ct_item_ops = _item_ops; \ cit->ct_group_ops = _group_ops; \ cit->ct_attrs = _attrs; \ - cit->ct_owner = sa->owner; \ + cit->ct_owner = tb->ops->owner; \ + pr_debug("Setup generic %s\n", __stringify(_name)); \ +} + +#define TB_CIT_SETUP_DRV(_name, _item_ops, _group_ops) \ +static void target_core_setup_##_name##_cit(struct target_backend *tb) \ +{ \ + struct config_item_type *cit = &tb->tb_##_name##_cit; \ + \ + cit->ct_item_ops = _item_ops; \ + cit->ct_group_ops = _group_ops; \ + cit->ct_attrs = tb->ops->tb_##_name##_attrs; \ + cit->ct_owner = tb->ops->owner; \ pr_debug("Setup generic %s\n", __stringify(_name)); \ } @@ -469,7 +480,7 @@ static struct configfs_item_operations target_core_dev_attrib_ops = { .store_attribute = target_core_dev_attrib_attr_store, }; -TB_CIT_SETUP(dev_attrib, &target_core_dev_attrib_ops, NULL, NULL); +TB_CIT_SETUP_DRV(dev_attrib, &target_core_dev_attrib_ops, NULL); /* End functions for struct config_item_type tb_dev_attrib_cit */ @@ -1174,13 +1185,13 @@ TB_CIT_SETUP(dev_pr, &target_core_dev_pr_ops, NULL, target_core_dev_pr_attrs); static ssize_t target_core_show_dev_info(void *p, char *page) { struct se_device *dev = p; - struct se_subsystem_api *t = dev->transport; int bl = 0; ssize_t read_bytes = 0; transport_dump_dev_state(dev, page, &bl); read_bytes += bl; - read_bytes += t->show_configfs_dev_params(dev, page+read_bytes); + read_bytes += dev->transport->show_configfs_dev_params(dev, + page+read_bytes); return read_bytes; } @@ -1198,9 +1209,8 @@ static ssize_t target_core_store_dev_control( size_t count) { struct se_device *dev = p; - struct se_subsystem_api *t = dev->transport; - return t->set_configfs_dev_params(dev, page, count); + return dev->transport->set_configfs_dev_params(dev, page, count); } static struct target_core_configfs_attribute target_core_attr_dev_control = { @@ -2477,9 +2487,9 @@ static struct config_group *target_core_make_subdev( const char *name) { struct t10_alua_tg_pt_gp *tg_pt_gp; - struct se_subsystem_api *t; struct config_item *hba_ci = &group->cg_item; struct se_hba *hba = item_to_hba(hba_ci); + struct target_backend *tb = hba->backend; struct se_device *dev; struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; struct config_group *dev_stat_grp = NULL; @@ -2488,10 +2498,6 @@ static struct config_group *target_core_make_subdev( ret = mutex_lock_interruptible(&hba->hba_access_mutex); if (ret) return ERR_PTR(ret); - /* - * Locate the struct se_subsystem_api from parent's struct se_hba. - */ - t = hba->transport; dev = target_alloc_device(hba, name); if (!dev) @@ -2504,17 +2510,17 @@ static struct config_group *target_core_make_subdev( if (!dev_cg->default_groups) goto out_free_device; - config_group_init_type_name(dev_cg, name, &t->tb_cits.tb_dev_cit); + config_group_init_type_name(dev_cg, name, &tb->tb_dev_cit); config_group_init_type_name(&dev->dev_attrib.da_group, "attrib", - &t->tb_cits.tb_dev_attrib_cit); + &tb->tb_dev_attrib_cit); config_group_init_type_name(&dev->dev_pr_group, "pr", - &t->tb_cits.tb_dev_pr_cit); + &tb->tb_dev_pr_cit); config_group_init_type_name(&dev->t10_wwn.t10_wwn_group, "wwn", - &t->tb_cits.tb_dev_wwn_cit); + &tb->tb_dev_wwn_cit); config_group_init_type_name(&dev->t10_alua.alua_tg_pt_gps_group, - "alua", &t->tb_cits.tb_dev_alua_tg_pt_gps_cit); + "alua", &tb->tb_dev_alua_tg_pt_gps_cit); config_group_init_type_name(&dev->dev_stat_grps.stat_group, - "statistics", &t->tb_cits.tb_dev_stat_cit); + "statistics", &tb->tb_dev_stat_cit); dev_cg->default_groups[0] = &dev->dev_attrib.da_group; dev_cg->default_groups[1] = &dev->dev_pr_group; @@ -2644,7 +2650,7 @@ static ssize_t target_core_hba_show_attr_hba_info( char *page) { return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", - hba->hba_id, hba->transport->name, + hba->hba_id, hba->backend->ops->name, TARGET_CORE_CONFIGFS_VERSION); } @@ -2664,11 +2670,10 @@ static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba, static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, const char *page, size_t count) { - struct se_subsystem_api *transport = hba->transport; unsigned long mode_flag; int ret; - if (transport->pmode_enable_hba == NULL) + if (hba->backend->ops->pmode_enable_hba == NULL) return -EINVAL; ret = kstrtoul(page, 0, &mode_flag); @@ -2682,7 +2687,7 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, return -EINVAL; } - ret = transport->pmode_enable_hba(hba, mode_flag); + ret = hba->backend->ops->pmode_enable_hba(hba, mode_flag); if (ret < 0) return -EINVAL; if (ret > 0) @@ -2808,16 +2813,15 @@ static struct config_item_type target_core_cit = { /* Stop functions for struct config_item_type target_core_hba_cit */ -void target_core_setup_sub_cits(struct se_subsystem_api *sa) +void target_setup_backend_cits(struct target_backend *tb) { - target_core_setup_dev_cit(sa); - target_core_setup_dev_attrib_cit(sa); - target_core_setup_dev_pr_cit(sa); - target_core_setup_dev_wwn_cit(sa); - target_core_setup_dev_alua_tg_pt_gps_cit(sa); - target_core_setup_dev_stat_cit(sa); + target_core_setup_dev_cit(tb); + target_core_setup_dev_attrib_cit(tb); + target_core_setup_dev_pr_cit(tb); + target_core_setup_dev_wwn_cit(tb); + target_core_setup_dev_alua_tg_pt_gps_cit(tb); + target_core_setup_dev_stat_cit(tb); } -EXPORT_SYMBOL(target_core_setup_sub_cits); static int __init target_core_init_configfs(void) { diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 47a73609e277..af906f1caaa7 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1367,13 +1367,13 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) struct se_device *dev; struct se_lun *xcopy_lun; - dev = hba->transport->alloc_device(hba, name); + dev = hba->backend->ops->alloc_device(hba, name); if (!dev) return NULL; dev->dev_link_magic = SE_DEV_LINK_MAGIC; dev->se_hba = hba; - dev->transport = hba->transport; + dev->transport = hba->backend->ops; dev->prot_length = sizeof(struct se_dif_v1_tuple); INIT_LIST_HEAD(&dev->dev_list); @@ -1571,7 +1571,7 @@ int core_dev_setup_virtual_lun0(void) goto out_free_hba; } - hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf)); + hba->backend->ops->set_configfs_dev_params(dev, buf, sizeof(buf)); ret = target_configure_device(dev); if (ret) diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index e865885352da..7c5b1ef57d34 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -46,10 +46,6 @@ static inline struct fd_dev *FD_DEV(struct se_device *dev) return container_of(dev, struct fd_dev, dev); } -/* fd_attach_hba(): (Part of se_subsystem_api_t template) - * - * - */ static int fd_attach_hba(struct se_hba *hba, u32 host_id) { struct fd_host *fd_host; @@ -881,7 +877,7 @@ static struct configfs_attribute *fileio_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api fileio_template = { +static const struct target_backend_ops fileio_ops = { .name = "fileio", .inquiry_prod = "FILEIO", .inquiry_rev = FD_VERSION, @@ -899,21 +895,17 @@ static struct se_subsystem_api fileio_template = { .init_prot = fd_init_prot, .format_prot = fd_format_prot, .free_prot = fd_free_prot, + .tb_dev_attrib_attrs = fileio_backend_dev_attrs, }; static int __init fileio_module_init(void) { - struct target_backend_cits *tbc = &fileio_template.tb_cits; - - target_core_setup_sub_cits(&fileio_template); - tbc->tb_dev_attrib_cit.ct_attrs = fileio_backend_dev_attrs; - - return transport_subsystem_register(&fileio_template); + return transport_backend_register(&fileio_ops); } static void __exit fileio_module_exit(void) { - transport_subsystem_release(&fileio_template); + target_backend_unregister(&fileio_ops); } MODULE_DESCRIPTION("TCM FILEIO subsystem plugin"); diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index e6e496ff9546..62ea4e8e70a8 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -39,63 +39,75 @@ #include "target_core_internal.h" -static LIST_HEAD(subsystem_list); -static DEFINE_MUTEX(subsystem_mutex); +static LIST_HEAD(backend_list); +static DEFINE_MUTEX(backend_mutex); static u32 hba_id_counter; static DEFINE_SPINLOCK(hba_lock); static LIST_HEAD(hba_list); -int transport_subsystem_register(struct se_subsystem_api *sub_api) -{ - struct se_subsystem_api *s; - - INIT_LIST_HEAD(&sub_api->sub_api_list); - mutex_lock(&subsystem_mutex); - list_for_each_entry(s, &subsystem_list, sub_api_list) { - if (!strcmp(s->name, sub_api->name)) { - pr_err("%p is already registered with" - " duplicate name %s, unable to process" - " request\n", s, s->name); - mutex_unlock(&subsystem_mutex); +int transport_backend_register(const struct target_backend_ops *ops) +{ + struct target_backend *tb, *old; + + tb = kzalloc(sizeof(*tb), GFP_KERNEL); + if (!tb) + return -ENOMEM; + tb->ops = ops; + + mutex_lock(&backend_mutex); + list_for_each_entry(old, &backend_list, list) { + if (!strcmp(old->ops->name, ops->name)) { + pr_err("backend %s already registered.\n", ops->name); + mutex_unlock(&backend_mutex); + kfree(tb); return -EEXIST; } } - list_add_tail(&sub_api->sub_api_list, &subsystem_list); - mutex_unlock(&subsystem_mutex); + target_setup_backend_cits(tb); + list_add_tail(&tb->list, &backend_list); + mutex_unlock(&backend_mutex); - pr_debug("TCM: Registered subsystem plugin: %s struct module:" - " %p\n", sub_api->name, sub_api->owner); + pr_debug("TCM: Registered subsystem plugin: %s struct module: %p\n", + ops->name, ops->owner); return 0; } -EXPORT_SYMBOL(transport_subsystem_register); +EXPORT_SYMBOL(transport_backend_register); -void transport_subsystem_release(struct se_subsystem_api *sub_api) +void target_backend_unregister(const struct target_backend_ops *ops) { - mutex_lock(&subsystem_mutex); - list_del(&sub_api->sub_api_list); - mutex_unlock(&subsystem_mutex); + struct target_backend *tb; + + mutex_lock(&backend_mutex); + list_for_each_entry(tb, &backend_list, list) { + if (tb->ops == ops) { + list_del(&tb->list); + kfree(tb); + break; + } + } + mutex_unlock(&backend_mutex); } -EXPORT_SYMBOL(transport_subsystem_release); +EXPORT_SYMBOL(target_backend_unregister); -static struct se_subsystem_api *core_get_backend(const char *sub_name) +static struct target_backend *core_get_backend(const char *name) { - struct se_subsystem_api *s; + struct target_backend *tb; - mutex_lock(&subsystem_mutex); - list_for_each_entry(s, &subsystem_list, sub_api_list) { - if (!strcmp(s->name, sub_name)) + mutex_lock(&backend_mutex); + list_for_each_entry(tb, &backend_list, list) { + if (!strcmp(tb->ops->name, name)) goto found; } - mutex_unlock(&subsystem_mutex); + mutex_unlock(&backend_mutex); return NULL; found: - if (s->owner && !try_module_get(s->owner)) - s = NULL; - mutex_unlock(&subsystem_mutex); - return s; + if (tb->ops->owner && !try_module_get(tb->ops->owner)) + tb = NULL; + mutex_unlock(&backend_mutex); + return tb; } struct se_hba * @@ -116,13 +128,13 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags) hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX); hba->hba_flags |= hba_flags; - hba->transport = core_get_backend(plugin_name); - if (!hba->transport) { + hba->backend = core_get_backend(plugin_name); + if (!hba->backend) { ret = -EINVAL; goto out_free_hba; } - ret = hba->transport->attach_hba(hba, plugin_dep_id); + ret = hba->backend->ops->attach_hba(hba, plugin_dep_id); if (ret < 0) goto out_module_put; @@ -137,8 +149,8 @@ core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags) return hba; out_module_put: - module_put(hba->transport->owner); - hba->transport = NULL; + module_put(hba->backend->ops->owner); + hba->backend = NULL; out_free_hba: kfree(hba); return ERR_PTR(ret); @@ -149,7 +161,7 @@ core_delete_hba(struct se_hba *hba) { WARN_ON(hba->dev_count); - hba->transport->detach_hba(hba); + hba->backend->ops->detach_hba(hba); spin_lock(&hba_lock); list_del(&hba->hba_node); @@ -158,9 +170,9 @@ core_delete_hba(struct se_hba *hba) pr_debug("CORE_HBA[%d] - Detached HBA from Generic Target" " Core\n", hba->hba_id); - module_put(hba->transport->owner); + module_put(hba->backend->ops->owner); - hba->transport = NULL; + hba->backend = NULL; kfree(hba); return 0; } diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 8c965683789f..79f651fb98fb 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -54,12 +54,6 @@ static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev) } -static struct se_subsystem_api iblock_template; - -/* iblock_attach_hba(): (Part of se_subsystem_api_t template) - * - * - */ static int iblock_attach_hba(struct se_hba *hba, u32 host_id) { pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on" @@ -899,7 +893,7 @@ static struct configfs_attribute *iblock_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api iblock_template = { +static const struct target_backend_ops iblock_ops = { .name = "iblock", .inquiry_prod = "IBLOCK", .inquiry_rev = IBLOCK_VERSION, @@ -919,21 +913,17 @@ static struct se_subsystem_api iblock_template = { .get_io_min = iblock_get_io_min, .get_io_opt = iblock_get_io_opt, .get_write_cache = iblock_get_write_cache, + .tb_dev_attrib_attrs = iblock_backend_dev_attrs, }; static int __init iblock_module_init(void) { - struct target_backend_cits *tbc = &iblock_template.tb_cits; - - target_core_setup_sub_cits(&iblock_template); - tbc->tb_dev_attrib_cit.ct_attrs = iblock_backend_dev_attrs; - - return transport_subsystem_register(&iblock_template); + return transport_backend_register(&iblock_ops); } static void __exit iblock_module_exit(void) { - transport_subsystem_release(&iblock_template); + target_backend_unregister(&iblock_ops); } MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin"); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index ce80ca76f68b..01181aed67dc 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -1,6 +1,19 @@ #ifndef TARGET_CORE_INTERNAL_H #define TARGET_CORE_INTERNAL_H +struct target_backend { + struct list_head list; + + const struct target_backend_ops *ops; + + struct config_item_type tb_dev_cit; + struct config_item_type tb_dev_attrib_cit; + struct config_item_type tb_dev_pr_cit; + struct config_item_type tb_dev_wwn_cit; + struct config_item_type tb_dev_alua_tg_pt_gps_cit; + struct config_item_type tb_dev_stat_cit; +}; + /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; @@ -40,6 +53,9 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name); int target_configure_device(struct se_device *dev); void target_free_device(struct se_device *); +/* target_core_configfs.c */ +void target_setup_backend_cits(struct target_backend *); + /* target_core_fabric_lib.c */ int target_get_pr_transport_id_len(struct se_node_acl *nacl, struct t10_pr_registration *pr_reg, int *format_code); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 21db991b4465..2e3a0b004f9a 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -57,8 +57,6 @@ static inline struct pscsi_dev_virt *PSCSI_DEV(struct se_device *dev) return container_of(dev, struct pscsi_dev_virt, dev); } -static struct se_subsystem_api pscsi_template; - static sense_reason_t pscsi_execute_cmd(struct se_cmd *cmd); static void pscsi_req_done(struct request *, int); @@ -1141,7 +1139,7 @@ static struct configfs_attribute *pscsi_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api pscsi_template = { +static const struct target_backend_ops pscsi_ops = { .name = "pscsi", .owner = THIS_MODULE, .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, @@ -1157,21 +1155,17 @@ static struct se_subsystem_api pscsi_template = { .show_configfs_dev_params = pscsi_show_configfs_dev_params, .get_device_type = pscsi_get_device_type, .get_blocks = pscsi_get_blocks, + .tb_dev_attrib_attrs = pscsi_backend_dev_attrs, }; static int __init pscsi_module_init(void) { - struct target_backend_cits *tbc = &pscsi_template.tb_cits; - - target_core_setup_sub_cits(&pscsi_template); - tbc->tb_dev_attrib_cit.ct_attrs = pscsi_backend_dev_attrs; - - return transport_subsystem_register(&pscsi_template); + return transport_backend_register(&pscsi_ops); } static void __exit pscsi_module_exit(void) { - transport_subsystem_release(&pscsi_template); + target_backend_unregister(&pscsi_ops); } MODULE_DESCRIPTION("TCM PSCSI subsystem plugin"); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 55315fd0f5d3..cf443a8a3cbe 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -43,10 +43,6 @@ static inline struct rd_dev *RD_DEV(struct se_device *dev) return container_of(dev, struct rd_dev, dev); } -/* rd_attach_hba(): (Part of se_subsystem_api_t template) - * - * - */ static int rd_attach_hba(struct se_hba *hba, u32 host_id) { struct rd_host *rd_host; @@ -735,7 +731,7 @@ static struct configfs_attribute *rd_mcp_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api rd_mcp_template = { +static const struct target_backend_ops rd_mcp_ops = { .name = "rd_mcp", .inquiry_prod = "RAMDISK-MCP", .inquiry_rev = RD_MCP_VERSION, @@ -751,25 +747,15 @@ static struct se_subsystem_api rd_mcp_template = { .get_blocks = rd_get_blocks, .init_prot = rd_init_prot, .free_prot = rd_free_prot, + .tb_dev_attrib_attrs = rd_mcp_backend_dev_attrs, }; int __init rd_module_init(void) { - struct target_backend_cits *tbc = &rd_mcp_template.tb_cits; - int ret; - - target_core_setup_sub_cits(&rd_mcp_template); - tbc->tb_dev_attrib_cit.ct_attrs = rd_mcp_backend_dev_attrs; - - ret = transport_subsystem_register(&rd_mcp_template); - if (ret < 0) { - return ret; - } - - return 0; + return transport_backend_register(&rd_mcp_ops); } void rd_module_exit(void) { - transport_subsystem_release(&rd_mcp_template); + target_backend_unregister(&rd_mcp_ops); } diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 60330e00f59d..fb67e313dc4f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1115,7 +1115,7 @@ static struct configfs_attribute *tcmu_backend_dev_attrs[] = { NULL, }; -static struct se_subsystem_api tcmu_template = { +static const struct target_backend_ops tcmu_ops = { .name = "user", .inquiry_prod = "USER", .inquiry_rev = TCMU_VERSION, @@ -1131,11 +1131,11 @@ static struct se_subsystem_api tcmu_template = { .show_configfs_dev_params = tcmu_show_configfs_dev_params, .get_device_type = sbc_get_device_type, .get_blocks = tcmu_get_blocks, + .tb_dev_attrib_attrs = tcmu_backend_dev_attrs, }; static int __init tcmu_module_init(void) { - struct target_backend_cits *tbc = &tcmu_template.tb_cits; int ret; BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0); @@ -1158,10 +1158,7 @@ static int __init tcmu_module_init(void) goto out_unreg_device; } - target_core_setup_sub_cits(&tcmu_template); - tbc->tb_dev_attrib_cit.ct_attrs = tcmu_backend_dev_attrs; - - ret = transport_subsystem_register(&tcmu_template); + ret = transport_backend_register(&tcmu_ops); if (ret) goto out_unreg_genl; @@ -1179,7 +1176,7 @@ out_free_cache: static void __exit tcmu_module_exit(void) { - transport_subsystem_release(&tcmu_template); + target_backend_unregister(&tcmu_ops); genl_unregister_family(&tcmu_genl_family); root_device_unregister(tcmu_root_device); kmem_cache_destroy(tcmu_cmd_cache); diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 80d9e486e33e..514b52019380 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -3,18 +3,7 @@ #define TRANSPORT_FLAG_PASSTHROUGH 1 -struct target_backend_cits { - struct config_item_type tb_dev_cit; - struct config_item_type tb_dev_attrib_cit; - struct config_item_type tb_dev_pr_cit; - struct config_item_type tb_dev_wwn_cit; - struct config_item_type tb_dev_alua_tg_pt_gps_cit; - struct config_item_type tb_dev_stat_cit; -}; - -struct se_subsystem_api { - struct list_head sub_api_list; - +struct target_backend_ops { char name[16]; char inquiry_prod[16]; char inquiry_rev[4]; @@ -52,7 +41,7 @@ struct se_subsystem_api { int (*format_prot)(struct se_device *); void (*free_prot)(struct se_device *); - struct target_backend_cits tb_cits; + struct configfs_attribute **tb_dev_attrib_attrs; }; struct sbc_ops { @@ -64,8 +53,8 @@ struct sbc_ops { sense_reason_t (*execute_unmap)(struct se_cmd *cmd); }; -int transport_subsystem_register(struct se_subsystem_api *); -void transport_subsystem_release(struct se_subsystem_api *); +int transport_backend_register(const struct target_backend_ops *); +void target_backend_unregister(const struct target_backend_ops *); void target_complete_cmd(struct se_cmd *, u8); void target_complete_cmd_with_length(struct se_cmd *, u8, int); @@ -103,9 +92,6 @@ sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, bool target_lun_is_rdonly(struct se_cmd *); -/* From target_core_configfs.c to setup default backend config_item_types */ -void target_core_setup_sub_cits(struct se_subsystem_api *); - /* attribute helpers from target_core_device.c for backend drivers */ bool se_dev_check_wce(struct se_device *); int se_dev_set_max_unmap_lba_count(struct se_device *, u32); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 78ed2a83838c..03e2ee8f8337 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -797,7 +797,7 @@ struct se_device { #define SE_UDEV_PATH_LEN 512 /* must be less than PAGE_SIZE */ unsigned char udev_path[SE_UDEV_PATH_LEN]; /* Pointer to template of function pointers for transport */ - struct se_subsystem_api *transport; + const struct target_backend_ops *transport; /* Linked list for struct se_hba struct se_device list */ struct list_head dev_list; struct se_lun xcopy_lun; @@ -819,7 +819,7 @@ struct se_hba { spinlock_t device_lock; struct config_group hba_group; struct mutex hba_access_mutex; - struct se_subsystem_api *transport; + struct target_backend *backend; }; struct scsi_port_stats { -- cgit v1.2.3 From 5873c4d157400ade4052e9d7b6259fa592e1ddbf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 10 May 2015 18:14:57 +0200 Subject: target: consolidate backend attribute implementations Provide a common sets of dev_attrib attributes for all devices using the generic SPC/SBC parsers, and a second one with the minimal required read-only attributes for passthrough devices. The later is only used by pscsi for now, but will be wired up for the full-passthrough TCMU use case as well. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 169 ++++++++++++++++++++++++++ drivers/target/target_core_file.c | 38 +----- drivers/target/target_core_iblock.c | 38 +----- drivers/target/target_core_pscsi.c | 23 +--- drivers/target/target_core_rd.c | 38 +----- drivers/target/target_core_user.c | 23 +--- include/target/target_core_backend.h | 3 + include/target/target_core_backend_configfs.h | 118 ------------------ 8 files changed, 177 insertions(+), 273 deletions(-) delete mode 100644 include/target/target_core_backend_configfs.h (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 57c099dd9da5..dbf91f02ee5c 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -471,10 +471,179 @@ EXPORT_SYMBOL(target_unregister_template); //############################################################################*/ /* Start functions for struct config_item_type tb_dev_attrib_cit */ +#define DEF_TB_DEV_ATTRIB_SHOW(_backend, _name) \ +static ssize_t _backend##_dev_show_attr_##_name( \ + struct se_dev_attrib *da, \ + char *page) \ +{ \ + return snprintf(page, PAGE_SIZE, "%u\n", \ + (u32)da->da_dev->dev_attrib._name); \ +} + +#define DEF_TB_DEV_ATTRIB_STORE(_backend, _name) \ +static ssize_t _backend##_dev_store_attr_##_name( \ + struct se_dev_attrib *da, \ + const char *page, \ + size_t count) \ +{ \ + unsigned long val; \ + int ret; \ + \ + ret = kstrtoul(page, 0, &val); \ + if (ret < 0) { \ + pr_err("kstrtoul() failed with ret: %d\n", ret); \ + return -EINVAL; \ + } \ + ret = se_dev_set_##_name(da->da_dev, (u32)val); \ + \ + return (!ret) ? count : -EINVAL; \ +} + +#define DEF_TB_DEV_ATTRIB(_backend, _name) \ +DEF_TB_DEV_ATTRIB_SHOW(_backend, _name); \ +DEF_TB_DEV_ATTRIB_STORE(_backend, _name); + +#define DEF_TB_DEV_ATTRIB_RO(_backend, name) \ +DEF_TB_DEV_ATTRIB_SHOW(_backend, name); + +CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); +#define TB_DEV_ATTR(_backend, _name, _mode) \ +static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + _backend##_dev_show_attr_##_name, \ + _backend##_dev_store_attr_##_name); + +#define TB_DEV_ATTR_RO(_backend, _name) \ +static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + _backend##_dev_show_attr_##_name); + +DEF_TB_DEV_ATTRIB(target_core, emulate_model_alias); +DEF_TB_DEV_ATTRIB(target_core, emulate_dpo); +DEF_TB_DEV_ATTRIB(target_core, emulate_fua_write); +DEF_TB_DEV_ATTRIB(target_core, emulate_fua_read); +DEF_TB_DEV_ATTRIB(target_core, emulate_write_cache); +DEF_TB_DEV_ATTRIB(target_core, emulate_ua_intlck_ctrl); +DEF_TB_DEV_ATTRIB(target_core, emulate_tas); +DEF_TB_DEV_ATTRIB(target_core, emulate_tpu); +DEF_TB_DEV_ATTRIB(target_core, emulate_tpws); +DEF_TB_DEV_ATTRIB(target_core, emulate_caw); +DEF_TB_DEV_ATTRIB(target_core, emulate_3pc); +DEF_TB_DEV_ATTRIB(target_core, pi_prot_type); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_pi_prot_type); +DEF_TB_DEV_ATTRIB(target_core, pi_prot_format); +DEF_TB_DEV_ATTRIB(target_core, enforce_pr_isids); +DEF_TB_DEV_ATTRIB(target_core, is_nonrot); +DEF_TB_DEV_ATTRIB(target_core, emulate_rest_reord); +DEF_TB_DEV_ATTRIB(target_core, force_pr_aptpl); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_block_size); +DEF_TB_DEV_ATTRIB(target_core, block_size); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_max_sectors); +DEF_TB_DEV_ATTRIB(target_core, optimal_sectors); +DEF_TB_DEV_ATTRIB_RO(target_core, hw_queue_depth); +DEF_TB_DEV_ATTRIB(target_core, queue_depth); +DEF_TB_DEV_ATTRIB(target_core, max_unmap_lba_count); +DEF_TB_DEV_ATTRIB(target_core, max_unmap_block_desc_count); +DEF_TB_DEV_ATTRIB(target_core, unmap_granularity); +DEF_TB_DEV_ATTRIB(target_core, unmap_granularity_alignment); +DEF_TB_DEV_ATTRIB(target_core, max_write_same_len); + +TB_DEV_ATTR(target_core, emulate_model_alias, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_dpo, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_fua_write, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_fua_read, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_write_cache, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_tas, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_tpu, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_tpws, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_caw, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_3pc, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, pi_prot_type, S_IRUGO | S_IWUSR); +TB_DEV_ATTR_RO(target_core, hw_pi_prot_type); +TB_DEV_ATTR(target_core, pi_prot_format, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, enforce_pr_isids, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, is_nonrot, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, emulate_rest_reord, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, force_pr_aptpl, S_IRUGO | S_IWUSR) +TB_DEV_ATTR_RO(target_core, hw_block_size); +TB_DEV_ATTR(target_core, block_size, S_IRUGO | S_IWUSR) +TB_DEV_ATTR_RO(target_core, hw_max_sectors); +TB_DEV_ATTR(target_core, optimal_sectors, S_IRUGO | S_IWUSR); +TB_DEV_ATTR_RO(target_core, hw_queue_depth); +TB_DEV_ATTR(target_core, queue_depth, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, max_unmap_lba_count, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, max_unmap_block_desc_count, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, unmap_granularity, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, unmap_granularity_alignment, S_IRUGO | S_IWUSR); +TB_DEV_ATTR(target_core, max_write_same_len, S_IRUGO | S_IWUSR); CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib); CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group); +/* + * dev_attrib attributes for devices using the target core SBC/SPC + * interpreter. Any backend using spc_parse_cdb should be using + * these. + */ +struct configfs_attribute *sbc_attrib_attrs[] = { + &target_core_dev_attrib_emulate_model_alias.attr, + &target_core_dev_attrib_emulate_dpo.attr, + &target_core_dev_attrib_emulate_fua_write.attr, + &target_core_dev_attrib_emulate_fua_read.attr, + &target_core_dev_attrib_emulate_write_cache.attr, + &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr, + &target_core_dev_attrib_emulate_tas.attr, + &target_core_dev_attrib_emulate_tpu.attr, + &target_core_dev_attrib_emulate_tpws.attr, + &target_core_dev_attrib_emulate_caw.attr, + &target_core_dev_attrib_emulate_3pc.attr, + &target_core_dev_attrib_pi_prot_type.attr, + &target_core_dev_attrib_hw_pi_prot_type.attr, + &target_core_dev_attrib_pi_prot_format.attr, + &target_core_dev_attrib_enforce_pr_isids.attr, + &target_core_dev_attrib_is_nonrot.attr, + &target_core_dev_attrib_emulate_rest_reord.attr, + &target_core_dev_attrib_force_pr_aptpl.attr, + &target_core_dev_attrib_hw_block_size.attr, + &target_core_dev_attrib_block_size.attr, + &target_core_dev_attrib_hw_max_sectors.attr, + &target_core_dev_attrib_optimal_sectors.attr, + &target_core_dev_attrib_hw_queue_depth.attr, + &target_core_dev_attrib_queue_depth.attr, + &target_core_dev_attrib_max_unmap_lba_count.attr, + &target_core_dev_attrib_max_unmap_block_desc_count.attr, + &target_core_dev_attrib_unmap_granularity.attr, + &target_core_dev_attrib_unmap_granularity_alignment.attr, + &target_core_dev_attrib_max_write_same_len.attr, + NULL, +}; +EXPORT_SYMBOL(sbc_attrib_attrs); + +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_pi_prot_type); +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_block_size); +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_max_sectors); +DEF_TB_DEV_ATTRIB_RO(target_pt, hw_queue_depth); + +TB_DEV_ATTR_RO(target_pt, hw_pi_prot_type); +TB_DEV_ATTR_RO(target_pt, hw_block_size); +TB_DEV_ATTR_RO(target_pt, hw_max_sectors); +TB_DEV_ATTR_RO(target_pt, hw_queue_depth); + +/* + * Minimal dev_attrib attributes for devices passing through CDBs. + * In this case we only provide a few read-only attributes for + * backwards compatibility. + */ +struct configfs_attribute *passthrough_attrib_attrs[] = { + &target_pt_dev_attrib_hw_pi_prot_type.attr, + &target_pt_dev_attrib_hw_block_size.attr, + &target_pt_dev_attrib_hw_max_sectors.attr, + &target_pt_dev_attrib_hw_queue_depth.attr, + NULL, +}; +EXPORT_SYMBOL(passthrough_attrib_attrs); + static struct configfs_item_operations target_core_dev_attrib_ops = { .show_attribute = target_core_dev_attrib_attr_show, .store_attribute = target_core_dev_attrib_attr_store, diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 7c5b1ef57d34..948b61f59a55 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -37,7 +37,6 @@ #include #include -#include #include "target_core_file.h" @@ -842,41 +841,6 @@ fd_parse_cdb(struct se_cmd *cmd) return sbc_parse_cdb(cmd, &fd_sbc_ops); } -DEF_TB_DEFAULT_ATTRIBS(fileio); - -static struct configfs_attribute *fileio_backend_dev_attrs[] = { - &fileio_dev_attrib_emulate_model_alias.attr, - &fileio_dev_attrib_emulate_dpo.attr, - &fileio_dev_attrib_emulate_fua_write.attr, - &fileio_dev_attrib_emulate_fua_read.attr, - &fileio_dev_attrib_emulate_write_cache.attr, - &fileio_dev_attrib_emulate_ua_intlck_ctrl.attr, - &fileio_dev_attrib_emulate_tas.attr, - &fileio_dev_attrib_emulate_tpu.attr, - &fileio_dev_attrib_emulate_tpws.attr, - &fileio_dev_attrib_emulate_caw.attr, - &fileio_dev_attrib_emulate_3pc.attr, - &fileio_dev_attrib_pi_prot_type.attr, - &fileio_dev_attrib_hw_pi_prot_type.attr, - &fileio_dev_attrib_pi_prot_format.attr, - &fileio_dev_attrib_enforce_pr_isids.attr, - &fileio_dev_attrib_is_nonrot.attr, - &fileio_dev_attrib_emulate_rest_reord.attr, - &fileio_dev_attrib_force_pr_aptpl.attr, - &fileio_dev_attrib_hw_block_size.attr, - &fileio_dev_attrib_block_size.attr, - &fileio_dev_attrib_hw_max_sectors.attr, - &fileio_dev_attrib_optimal_sectors.attr, - &fileio_dev_attrib_hw_queue_depth.attr, - &fileio_dev_attrib_queue_depth.attr, - &fileio_dev_attrib_max_unmap_lba_count.attr, - &fileio_dev_attrib_max_unmap_block_desc_count.attr, - &fileio_dev_attrib_unmap_granularity.attr, - &fileio_dev_attrib_unmap_granularity_alignment.attr, - &fileio_dev_attrib_max_write_same_len.attr, - NULL, -}; - static const struct target_backend_ops fileio_ops = { .name = "fileio", .inquiry_prod = "FILEIO", @@ -895,7 +859,7 @@ static const struct target_backend_ops fileio_ops = { .init_prot = fd_init_prot, .format_prot = fd_format_prot, .free_prot = fd_free_prot, - .tb_dev_attrib_attrs = fileio_backend_dev_attrs, + .tb_dev_attrib_attrs = sbc_attrib_attrs, }; static int __init fileio_module_init(void) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 79f651fb98fb..6d4738252564 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -41,7 +41,6 @@ #include #include -#include #include "target_core_iblock.h" @@ -858,41 +857,6 @@ static bool iblock_get_write_cache(struct se_device *dev) return q->flush_flags & REQ_FLUSH; } -DEF_TB_DEFAULT_ATTRIBS(iblock); - -static struct configfs_attribute *iblock_backend_dev_attrs[] = { - &iblock_dev_attrib_emulate_model_alias.attr, - &iblock_dev_attrib_emulate_dpo.attr, - &iblock_dev_attrib_emulate_fua_write.attr, - &iblock_dev_attrib_emulate_fua_read.attr, - &iblock_dev_attrib_emulate_write_cache.attr, - &iblock_dev_attrib_emulate_ua_intlck_ctrl.attr, - &iblock_dev_attrib_emulate_tas.attr, - &iblock_dev_attrib_emulate_tpu.attr, - &iblock_dev_attrib_emulate_tpws.attr, - &iblock_dev_attrib_emulate_caw.attr, - &iblock_dev_attrib_emulate_3pc.attr, - &iblock_dev_attrib_pi_prot_type.attr, - &iblock_dev_attrib_hw_pi_prot_type.attr, - &iblock_dev_attrib_pi_prot_format.attr, - &iblock_dev_attrib_enforce_pr_isids.attr, - &iblock_dev_attrib_is_nonrot.attr, - &iblock_dev_attrib_emulate_rest_reord.attr, - &iblock_dev_attrib_force_pr_aptpl.attr, - &iblock_dev_attrib_hw_block_size.attr, - &iblock_dev_attrib_block_size.attr, - &iblock_dev_attrib_hw_max_sectors.attr, - &iblock_dev_attrib_optimal_sectors.attr, - &iblock_dev_attrib_hw_queue_depth.attr, - &iblock_dev_attrib_queue_depth.attr, - &iblock_dev_attrib_max_unmap_lba_count.attr, - &iblock_dev_attrib_max_unmap_block_desc_count.attr, - &iblock_dev_attrib_unmap_granularity.attr, - &iblock_dev_attrib_unmap_granularity_alignment.attr, - &iblock_dev_attrib_max_write_same_len.attr, - NULL, -}; - static const struct target_backend_ops iblock_ops = { .name = "iblock", .inquiry_prod = "IBLOCK", @@ -913,7 +877,7 @@ static const struct target_backend_ops iblock_ops = { .get_io_min = iblock_get_io_min, .get_io_opt = iblock_get_io_opt, .get_write_cache = iblock_get_write_cache, - .tb_dev_attrib_attrs = iblock_backend_dev_attrs, + .tb_dev_attrib_attrs = sbc_attrib_attrs, }; static int __init iblock_module_init(void) diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 2e3a0b004f9a..afb87a8d5668 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -44,7 +44,6 @@ #include #include -#include #include "target_core_alua.h" #include "target_core_internal.h" @@ -1119,26 +1118,6 @@ static void pscsi_req_done(struct request *req, int uptodate) kfree(pt); } -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_pi_prot_type); -TB_DEV_ATTR_RO(pscsi, hw_pi_prot_type); - -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_block_size); -TB_DEV_ATTR_RO(pscsi, hw_block_size); - -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_max_sectors); -TB_DEV_ATTR_RO(pscsi, hw_max_sectors); - -DEF_TB_DEV_ATTRIB_RO(pscsi, hw_queue_depth); -TB_DEV_ATTR_RO(pscsi, hw_queue_depth); - -static struct configfs_attribute *pscsi_backend_dev_attrs[] = { - &pscsi_dev_attrib_hw_pi_prot_type.attr, - &pscsi_dev_attrib_hw_block_size.attr, - &pscsi_dev_attrib_hw_max_sectors.attr, - &pscsi_dev_attrib_hw_queue_depth.attr, - NULL, -}; - static const struct target_backend_ops pscsi_ops = { .name = "pscsi", .owner = THIS_MODULE, @@ -1155,7 +1134,7 @@ static const struct target_backend_ops pscsi_ops = { .show_configfs_dev_params = pscsi_show_configfs_dev_params, .get_device_type = pscsi_get_device_type, .get_blocks = pscsi_get_blocks, - .tb_dev_attrib_attrs = pscsi_backend_dev_attrs, + .tb_dev_attrib_attrs = passthrough_attrib_attrs, }; static int __init pscsi_module_init(void) diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index cf443a8a3cbe..55dd73e7f213 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -34,7 +34,6 @@ #include #include -#include #include "target_core_rd.h" @@ -696,41 +695,6 @@ rd_parse_cdb(struct se_cmd *cmd) return sbc_parse_cdb(cmd, &rd_sbc_ops); } -DEF_TB_DEFAULT_ATTRIBS(rd_mcp); - -static struct configfs_attribute *rd_mcp_backend_dev_attrs[] = { - &rd_mcp_dev_attrib_emulate_model_alias.attr, - &rd_mcp_dev_attrib_emulate_dpo.attr, - &rd_mcp_dev_attrib_emulate_fua_write.attr, - &rd_mcp_dev_attrib_emulate_fua_read.attr, - &rd_mcp_dev_attrib_emulate_write_cache.attr, - &rd_mcp_dev_attrib_emulate_ua_intlck_ctrl.attr, - &rd_mcp_dev_attrib_emulate_tas.attr, - &rd_mcp_dev_attrib_emulate_tpu.attr, - &rd_mcp_dev_attrib_emulate_tpws.attr, - &rd_mcp_dev_attrib_emulate_caw.attr, - &rd_mcp_dev_attrib_emulate_3pc.attr, - &rd_mcp_dev_attrib_pi_prot_type.attr, - &rd_mcp_dev_attrib_hw_pi_prot_type.attr, - &rd_mcp_dev_attrib_pi_prot_format.attr, - &rd_mcp_dev_attrib_enforce_pr_isids.attr, - &rd_mcp_dev_attrib_is_nonrot.attr, - &rd_mcp_dev_attrib_emulate_rest_reord.attr, - &rd_mcp_dev_attrib_force_pr_aptpl.attr, - &rd_mcp_dev_attrib_hw_block_size.attr, - &rd_mcp_dev_attrib_block_size.attr, - &rd_mcp_dev_attrib_hw_max_sectors.attr, - &rd_mcp_dev_attrib_optimal_sectors.attr, - &rd_mcp_dev_attrib_hw_queue_depth.attr, - &rd_mcp_dev_attrib_queue_depth.attr, - &rd_mcp_dev_attrib_max_unmap_lba_count.attr, - &rd_mcp_dev_attrib_max_unmap_block_desc_count.attr, - &rd_mcp_dev_attrib_unmap_granularity.attr, - &rd_mcp_dev_attrib_unmap_granularity_alignment.attr, - &rd_mcp_dev_attrib_max_write_same_len.attr, - NULL, -}; - static const struct target_backend_ops rd_mcp_ops = { .name = "rd_mcp", .inquiry_prod = "RAMDISK-MCP", @@ -747,7 +711,7 @@ static const struct target_backend_ops rd_mcp_ops = { .get_blocks = rd_get_blocks, .init_prot = rd_init_prot, .free_prot = rd_free_prot, - .tb_dev_attrib_attrs = rd_mcp_backend_dev_attrs, + .tb_dev_attrib_attrs = sbc_attrib_attrs, }; int __init rd_module_init(void) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index fb67e313dc4f..aebaad55e23f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -29,7 +29,6 @@ #include #include #include -#include #include @@ -1095,26 +1094,6 @@ tcmu_parse_cdb(struct se_cmd *cmd) return passthrough_parse_cdb(cmd, tcmu_pass_op); } -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type); -TB_DEV_ATTR_RO(tcmu, hw_pi_prot_type); - -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_block_size); -TB_DEV_ATTR_RO(tcmu, hw_block_size); - -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_max_sectors); -TB_DEV_ATTR_RO(tcmu, hw_max_sectors); - -DEF_TB_DEV_ATTRIB_RO(tcmu, hw_queue_depth); -TB_DEV_ATTR_RO(tcmu, hw_queue_depth); - -static struct configfs_attribute *tcmu_backend_dev_attrs[] = { - &tcmu_dev_attrib_hw_pi_prot_type.attr, - &tcmu_dev_attrib_hw_block_size.attr, - &tcmu_dev_attrib_hw_max_sectors.attr, - &tcmu_dev_attrib_hw_queue_depth.attr, - NULL, -}; - static const struct target_backend_ops tcmu_ops = { .name = "user", .inquiry_prod = "USER", @@ -1131,7 +1110,7 @@ static const struct target_backend_ops tcmu_ops = { .show_configfs_dev_params = tcmu_show_configfs_dev_params, .get_device_type = sbc_get_device_type, .get_blocks = tcmu_get_blocks, - .tb_dev_attrib_attrs = tcmu_backend_dev_attrs, + .tb_dev_attrib_attrs = passthrough_attrib_attrs, }; static int __init tcmu_module_init(void) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 514b52019380..2d5610516494 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -82,6 +82,9 @@ int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *); int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); +extern struct configfs_attribute *sbc_attrib_attrs[]; +extern struct configfs_attribute *passthrough_attrib_attrs[]; + /* core helpers also used by command snooping in pscsi */ void *transport_kmap_data_sg(struct se_cmd *); void transport_kunmap_data_sg(struct se_cmd *); diff --git a/include/target/target_core_backend_configfs.h b/include/target/target_core_backend_configfs.h deleted file mode 100644 index 186f7a923570..000000000000 --- a/include/target/target_core_backend_configfs.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef TARGET_CORE_BACKEND_CONFIGFS_H -#define TARGET_CORE_BACKEND_CONFIGFS_H - -#include - -#define DEF_TB_DEV_ATTRIB_SHOW(_backend, _name) \ -static ssize_t _backend##_dev_show_attr_##_name( \ - struct se_dev_attrib *da, \ - char *page) \ -{ \ - return snprintf(page, PAGE_SIZE, "%u\n", \ - (u32)da->da_dev->dev_attrib._name); \ -} - -#define DEF_TB_DEV_ATTRIB_STORE(_backend, _name) \ -static ssize_t _backend##_dev_store_attr_##_name( \ - struct se_dev_attrib *da, \ - const char *page, \ - size_t count) \ -{ \ - unsigned long val; \ - int ret; \ - \ - ret = kstrtoul(page, 0, &val); \ - if (ret < 0) { \ - pr_err("kstrtoul() failed with ret: %d\n", ret); \ - return -EINVAL; \ - } \ - ret = se_dev_set_##_name(da->da_dev, (u32)val); \ - \ - return (!ret) ? count : -EINVAL; \ -} - -#define DEF_TB_DEV_ATTRIB(_backend, _name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, _name); \ -DEF_TB_DEV_ATTRIB_STORE(_backend, _name); - -#define DEF_TB_DEV_ATTRIB_RO(_backend, name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, name); - -CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); -#define TB_DEV_ATTR(_backend, _name, _mode) \ -static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - _backend##_dev_show_attr_##_name, \ - _backend##_dev_store_attr_##_name); - -#define TB_DEV_ATTR_RO(_backend, _name) \ -static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - _backend##_dev_show_attr_##_name); - -/* - * Default list of target backend device attributes as defined by - * struct se_dev_attrib - */ - -#define DEF_TB_DEFAULT_ATTRIBS(_backend) \ - DEF_TB_DEV_ATTRIB(_backend, emulate_model_alias); \ - TB_DEV_ATTR(_backend, emulate_model_alias, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_dpo); \ - TB_DEV_ATTR(_backend, emulate_dpo, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_fua_write); \ - TB_DEV_ATTR(_backend, emulate_fua_write, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_fua_read); \ - TB_DEV_ATTR(_backend, emulate_fua_read, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_write_cache); \ - TB_DEV_ATTR(_backend, emulate_write_cache, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_ua_intlck_ctrl); \ - TB_DEV_ATTR(_backend, emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_tas); \ - TB_DEV_ATTR(_backend, emulate_tas, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_tpu); \ - TB_DEV_ATTR(_backend, emulate_tpu, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_tpws); \ - TB_DEV_ATTR(_backend, emulate_tpws, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_caw); \ - TB_DEV_ATTR(_backend, emulate_caw, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_3pc); \ - TB_DEV_ATTR(_backend, emulate_3pc, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, pi_prot_type); \ - TB_DEV_ATTR(_backend, pi_prot_type, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_pi_prot_type); \ - TB_DEV_ATTR_RO(_backend, hw_pi_prot_type); \ - DEF_TB_DEV_ATTRIB(_backend, pi_prot_format); \ - TB_DEV_ATTR(_backend, pi_prot_format, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, enforce_pr_isids); \ - TB_DEV_ATTR(_backend, enforce_pr_isids, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, is_nonrot); \ - TB_DEV_ATTR(_backend, is_nonrot, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, emulate_rest_reord); \ - TB_DEV_ATTR(_backend, emulate_rest_reord, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, force_pr_aptpl); \ - TB_DEV_ATTR(_backend, force_pr_aptpl, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_block_size); \ - TB_DEV_ATTR_RO(_backend, hw_block_size); \ - DEF_TB_DEV_ATTRIB(_backend, block_size); \ - TB_DEV_ATTR(_backend, block_size, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_max_sectors); \ - TB_DEV_ATTR_RO(_backend, hw_max_sectors); \ - DEF_TB_DEV_ATTRIB(_backend, optimal_sectors); \ - TB_DEV_ATTR(_backend, optimal_sectors, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB_RO(_backend, hw_queue_depth); \ - TB_DEV_ATTR_RO(_backend, hw_queue_depth); \ - DEF_TB_DEV_ATTRIB(_backend, queue_depth); \ - TB_DEV_ATTR(_backend, queue_depth, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, max_unmap_lba_count); \ - TB_DEV_ATTR(_backend, max_unmap_lba_count, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, max_unmap_block_desc_count); \ - TB_DEV_ATTR(_backend, max_unmap_block_desc_count, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, unmap_granularity); \ - TB_DEV_ATTR(_backend, unmap_granularity, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, unmap_granularity_alignment); \ - TB_DEV_ATTR(_backend, unmap_granularity_alignment, S_IRUGO | S_IWUSR); \ - DEF_TB_DEV_ATTRIB(_backend, max_write_same_len); \ - TB_DEV_ATTR(_backend, max_write_same_len, S_IRUGO | S_IWUSR); - -#endif /* TARGET_CORE_BACKEND_CONFIGFS_H */ -- cgit v1.2.3 From 3effdb9094fd06b9c61ecef08d610ae90805fd98 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 10 May 2015 18:14:58 +0200 Subject: target: simplify backend attribute implementation Consolidate the implementation of the backend attributes in a single file and single function per attribute show/store function instead of splitting it into multiple functions in multiple files. Also use the proper strto* helpers for exposed data types, add macros to implement the store methods for the most common data types and share the show methods between the two different attribute implementations. (Fix bogus store_pi_prot_format flag=0 return value - nab) Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 552 ++++++++++++++++++++++++++++++---- drivers/target/target_core_device.c | 504 ------------------------------- include/target/target_core_backend.h | 29 -- 3 files changed, 486 insertions(+), 599 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index dbf91f02ee5c..4313eea060ed 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -471,82 +471,507 @@ EXPORT_SYMBOL(target_unregister_template); //############################################################################*/ /* Start functions for struct config_item_type tb_dev_attrib_cit */ -#define DEF_TB_DEV_ATTRIB_SHOW(_backend, _name) \ -static ssize_t _backend##_dev_show_attr_##_name( \ - struct se_dev_attrib *da, \ - char *page) \ +#define DEF_TB_DEV_ATTRIB_SHOW(_name) \ +static ssize_t show_##_name(struct se_dev_attrib *da, char *page) \ { \ - return snprintf(page, PAGE_SIZE, "%u\n", \ - (u32)da->da_dev->dev_attrib._name); \ -} - -#define DEF_TB_DEV_ATTRIB_STORE(_backend, _name) \ -static ssize_t _backend##_dev_store_attr_##_name( \ - struct se_dev_attrib *da, \ - const char *page, \ - size_t count) \ + return snprintf(page, PAGE_SIZE, "%u\n", da->_name); \ +} + +DEF_TB_DEV_ATTRIB_SHOW(emulate_model_alias); +DEF_TB_DEV_ATTRIB_SHOW(emulate_dpo); +DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_write); +DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_read); +DEF_TB_DEV_ATTRIB_SHOW(emulate_write_cache); +DEF_TB_DEV_ATTRIB_SHOW(emulate_ua_intlck_ctrl); +DEF_TB_DEV_ATTRIB_SHOW(emulate_tas); +DEF_TB_DEV_ATTRIB_SHOW(emulate_tpu); +DEF_TB_DEV_ATTRIB_SHOW(emulate_tpws); +DEF_TB_DEV_ATTRIB_SHOW(emulate_caw); +DEF_TB_DEV_ATTRIB_SHOW(emulate_3pc); +DEF_TB_DEV_ATTRIB_SHOW(pi_prot_type); +DEF_TB_DEV_ATTRIB_SHOW(hw_pi_prot_type); +DEF_TB_DEV_ATTRIB_SHOW(pi_prot_format); +DEF_TB_DEV_ATTRIB_SHOW(enforce_pr_isids); +DEF_TB_DEV_ATTRIB_SHOW(is_nonrot); +DEF_TB_DEV_ATTRIB_SHOW(emulate_rest_reord); +DEF_TB_DEV_ATTRIB_SHOW(force_pr_aptpl); +DEF_TB_DEV_ATTRIB_SHOW(hw_block_size); +DEF_TB_DEV_ATTRIB_SHOW(block_size); +DEF_TB_DEV_ATTRIB_SHOW(hw_max_sectors); +DEF_TB_DEV_ATTRIB_SHOW(optimal_sectors); +DEF_TB_DEV_ATTRIB_SHOW(hw_queue_depth); +DEF_TB_DEV_ATTRIB_SHOW(queue_depth); +DEF_TB_DEV_ATTRIB_SHOW(max_unmap_lba_count); +DEF_TB_DEV_ATTRIB_SHOW(max_unmap_block_desc_count); +DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity); +DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity_alignment); +DEF_TB_DEV_ATTRIB_SHOW(max_write_same_len); + +#define DEF_TB_DEV_ATTRIB_STORE_U32(_name) \ +static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + size_t count) \ { \ - unsigned long val; \ + u32 val; \ int ret; \ \ - ret = kstrtoul(page, 0, &val); \ - if (ret < 0) { \ - pr_err("kstrtoul() failed with ret: %d\n", ret); \ - return -EINVAL; \ - } \ - ret = se_dev_set_##_name(da->da_dev, (u32)val); \ + ret = kstrtou32(page, 0, &val); \ + if (ret < 0) \ + return ret; \ + da->_name = val; \ + return count; \ +} + +DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_lba_count); +DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_block_desc_count); +DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity); +DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity_alignment); +DEF_TB_DEV_ATTRIB_STORE_U32(max_write_same_len); + +#define DEF_TB_DEV_ATTRIB_STORE_BOOL(_name) \ +static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + size_t count) \ +{ \ + bool flag; \ + int ret; \ \ - return (!ret) ? count : -EINVAL; \ + ret = strtobool(page, &flag); \ + if (ret < 0) \ + return ret; \ + da->_name = flag; \ + return count; \ +} + +DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_fua_write); +DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_caw); +DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_3pc); +DEF_TB_DEV_ATTRIB_STORE_BOOL(enforce_pr_isids); +DEF_TB_DEV_ATTRIB_STORE_BOOL(is_nonrot); + +#define DEF_TB_DEV_ATTRIB_STORE_STUB(_name) \ +static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\ + size_t count) \ +{ \ + printk_once(KERN_WARNING \ + "ignoring deprecated ##_name## attribute\n"); \ + return count; \ +} + +DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_dpo); +DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_fua_read); + +static void dev_set_t10_wwn_model_alias(struct se_device *dev) +{ + const char *configname; + + configname = config_item_name(&dev->dev_group.cg_item); + if (strlen(configname) >= 16) { + pr_warn("dev[%p]: Backstore name '%s' is too long for " + "INQUIRY_MODEL, truncating to 16 bytes\n", dev, + configname); + } + snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); +} + +static ssize_t store_emulate_model_alias(struct se_dev_attrib *da, + const char *page, size_t count) +{ + struct se_device *dev = da->da_dev; + bool flag; + int ret; + + if (dev->export_count) { + pr_err("dev[%p]: Unable to change model alias" + " while export_count is %d\n", + dev, dev->export_count); + return -EINVAL; + } + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (flag) { + dev_set_t10_wwn_model_alias(dev); + } else { + strncpy(&dev->t10_wwn.model[0], + dev->transport->inquiry_prod, 16); + } + da->emulate_model_alias = flag; + return count; +} + +static ssize_t store_emulate_write_cache(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (flag && da->da_dev->transport->get_write_cache) { + pr_err("emulate_write_cache not supported for this device\n"); + return -EINVAL; + } + + da->emulate_write_cache = flag; + pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", + da->da_dev, flag); + return count; +} + +static ssize_t store_emulate_ua_intlck_ctrl(struct se_dev_attrib *da, + const char *page, size_t count) +{ + u32 val; + int ret; + + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (val != 0 && val != 1 && val != 2) { + pr_err("Illegal value %d\n", val); + return -EINVAL; + } + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device" + " UA_INTRLCK_CTRL while export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + da->emulate_ua_intlck_ctrl = val; + pr_debug("dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", + da->da_dev, val); + return count; +} + +static ssize_t store_emulate_tas(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device TAS while" + " export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + da->emulate_tas = flag; + pr_debug("dev[%p]: SE Device TASK_ABORTED status bit: %s\n", + da->da_dev, flag ? "Enabled" : "Disabled"); + + return count; +} + +static ssize_t store_emulate_tpu(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (flag && !da->max_unmap_block_desc_count) { + pr_err("Generic Block Discard not supported\n"); + return -ENOSYS; + } + + da->emulate_tpu = flag; + pr_debug("dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", + da->da_dev, flag); + return count; +} + +static ssize_t store_emulate_tpws(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + /* + * We expect this value to be non-zero when generic Block Layer + * Discard supported is detected iblock_create_virtdevice(). + */ + if (flag && !da->max_unmap_block_desc_count) { + pr_err("Generic Block Discard not supported\n"); + return -ENOSYS; + } + + da->emulate_tpws = flag; + pr_debug("dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", + da->da_dev, flag); + return count; +} + +static ssize_t store_pi_prot_type(struct se_dev_attrib *da, + const char *page, size_t count) +{ + int old_prot = da->pi_prot_type, ret; + struct se_device *dev = da->da_dev; + u32 flag; + + ret = kstrtou32(page, 0, &flag); + if (ret < 0) + return ret; + + if (flag != 0 && flag != 1 && flag != 2 && flag != 3) { + pr_err("Illegal value %d for pi_prot_type\n", flag); + return -EINVAL; + } + if (flag == 2) { + pr_err("DIF TYPE2 protection currently not supported\n"); + return -ENOSYS; + } + if (da->hw_pi_prot_type) { + pr_warn("DIF protection enabled on underlying hardware," + " ignoring\n"); + return count; + } + if (!dev->transport->init_prot || !dev->transport->free_prot) { + /* 0 is only allowed value for non-supporting backends */ + if (flag == 0) + return 0; + + pr_err("DIF protection not supported by backend: %s\n", + dev->transport->name); + return -ENOSYS; + } + if (!(dev->dev_flags & DF_CONFIGURED)) { + pr_err("DIF protection requires device to be configured\n"); + return -ENODEV; + } + if (dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device PROT type while" + " export_count is %d\n", dev, dev->export_count); + return -EINVAL; + } + + da->pi_prot_type = flag; + + if (flag && !old_prot) { + ret = dev->transport->init_prot(dev); + if (ret) { + da->pi_prot_type = old_prot; + return ret; + } + + } else if (!flag && old_prot) { + dev->transport->free_prot(dev); + } + + pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag); + return count; +} + +static ssize_t store_pi_prot_format(struct se_dev_attrib *da, + const char *page, size_t count) +{ + struct se_device *dev = da->da_dev; + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (!flag) + return count; + + if (!dev->transport->format_prot) { + pr_err("DIF protection format not supported by backend %s\n", + dev->transport->name); + return -ENOSYS; + } + if (!(dev->dev_flags & DF_CONFIGURED)) { + pr_err("DIF protection format requires device to be configured\n"); + return -ENODEV; + } + if (dev->export_count) { + pr_err("dev[%p]: Unable to format SE Device PROT type while" + " export_count is %d\n", dev, dev->export_count); + return -EINVAL; + } + + ret = dev->transport->format_prot(dev); + if (ret) + return ret; + + pr_debug("dev[%p]: SE Device Protection Format complete\n", dev); + return count; +} + +static ssize_t store_force_pr_aptpl(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to set force_pr_aptpl while" + " export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + + da->force_pr_aptpl = flag; + pr_debug("dev[%p]: SE Device force_pr_aptpl: %d\n", da->da_dev, flag); + return count; +} + +static ssize_t store_emulate_rest_reord(struct se_dev_attrib *da, + const char *page, size_t count) +{ + bool flag; + int ret; + + ret = strtobool(page, &flag); + if (ret < 0) + return ret; + + if (flag != 0) { + printk(KERN_ERR "dev[%p]: SE Device emulation of restricted" + " reordering not implemented\n", da->da_dev); + return -ENOSYS; + } + da->emulate_rest_reord = flag; + pr_debug("dev[%p]: SE Device emulate_rest_reord: %d\n", + da->da_dev, flag); + return count; } -#define DEF_TB_DEV_ATTRIB(_backend, _name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, _name); \ -DEF_TB_DEV_ATTRIB_STORE(_backend, _name); +/* + * Note, this can only be called on unexported SE Device Object. + */ +static ssize_t store_queue_depth(struct se_dev_attrib *da, + const char *page, size_t count) +{ + struct se_device *dev = da->da_dev; + u32 val; + int ret; -#define DEF_TB_DEV_ATTRIB_RO(_backend, name) \ -DEF_TB_DEV_ATTRIB_SHOW(_backend, name); + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device TCQ while" + " export_count is %d\n", + dev, dev->export_count); + return -EINVAL; + } + if (!val) { + pr_err("dev[%p]: Illegal ZERO value for queue_depth\n", dev); + return -EINVAL; + } + + if (val > dev->dev_attrib.queue_depth) { + if (val > dev->dev_attrib.hw_queue_depth) { + pr_err("dev[%p]: Passed queue_depth:" + " %u exceeds TCM/SE_Device MAX" + " TCQ: %u\n", dev, val, + dev->dev_attrib.hw_queue_depth); + return -EINVAL; + } + } + da->queue_depth = dev->queue_depth = val; + pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n", dev, val); + return count; +} + +static ssize_t store_optimal_sectors(struct se_dev_attrib *da, + const char *page, size_t count) +{ + u32 val; + int ret; + + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device" + " optimal_sectors while export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + if (val > da->hw_max_sectors) { + pr_err("dev[%p]: Passed optimal_sectors %u cannot be" + " greater than hw_max_sectors: %u\n", + da->da_dev, val, da->hw_max_sectors); + return -EINVAL; + } + + da->optimal_sectors = val; + pr_debug("dev[%p]: SE Device optimal_sectors changed to %u\n", + da->da_dev, val); + return count; +} + +static ssize_t store_block_size(struct se_dev_attrib *da, + const char *page, size_t count) +{ + u32 val; + int ret; + + ret = kstrtou32(page, 0, &val); + if (ret < 0) + return ret; + + if (da->da_dev->export_count) { + pr_err("dev[%p]: Unable to change SE Device block_size" + " while export_count is %d\n", + da->da_dev, da->da_dev->export_count); + return -EINVAL; + } + + if (val != 512 && val != 1024 && val != 2048 && val != 4096) { + pr_err("dev[%p]: Illegal value for block_device: %u" + " for SE device, must be 512, 1024, 2048 or 4096\n", + da->da_dev, val); + return -EINVAL; + } + + da->block_size = val; + if (da->max_bytes_per_io) + da->hw_max_sectors = da->max_bytes_per_io / val; + + pr_debug("dev[%p]: SE Device block_size changed to %u\n", + da->da_dev, val); + return count; +} CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib); #define TB_DEV_ATTR(_backend, _name, _mode) \ static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - _backend##_dev_show_attr_##_name, \ - _backend##_dev_store_attr_##_name); + __CONFIGFS_EATTR(_name, _mode, \ + show_##_name, \ + store_##_name); -#define TB_DEV_ATTR_RO(_backend, _name) \ +#define TB_DEV_ATTR_RO(_backend, _name) \ static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \ __CONFIGFS_EATTR_RO(_name, \ - _backend##_dev_show_attr_##_name); - -DEF_TB_DEV_ATTRIB(target_core, emulate_model_alias); -DEF_TB_DEV_ATTRIB(target_core, emulate_dpo); -DEF_TB_DEV_ATTRIB(target_core, emulate_fua_write); -DEF_TB_DEV_ATTRIB(target_core, emulate_fua_read); -DEF_TB_DEV_ATTRIB(target_core, emulate_write_cache); -DEF_TB_DEV_ATTRIB(target_core, emulate_ua_intlck_ctrl); -DEF_TB_DEV_ATTRIB(target_core, emulate_tas); -DEF_TB_DEV_ATTRIB(target_core, emulate_tpu); -DEF_TB_DEV_ATTRIB(target_core, emulate_tpws); -DEF_TB_DEV_ATTRIB(target_core, emulate_caw); -DEF_TB_DEV_ATTRIB(target_core, emulate_3pc); -DEF_TB_DEV_ATTRIB(target_core, pi_prot_type); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_pi_prot_type); -DEF_TB_DEV_ATTRIB(target_core, pi_prot_format); -DEF_TB_DEV_ATTRIB(target_core, enforce_pr_isids); -DEF_TB_DEV_ATTRIB(target_core, is_nonrot); -DEF_TB_DEV_ATTRIB(target_core, emulate_rest_reord); -DEF_TB_DEV_ATTRIB(target_core, force_pr_aptpl); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_block_size); -DEF_TB_DEV_ATTRIB(target_core, block_size); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_max_sectors); -DEF_TB_DEV_ATTRIB(target_core, optimal_sectors); -DEF_TB_DEV_ATTRIB_RO(target_core, hw_queue_depth); -DEF_TB_DEV_ATTRIB(target_core, queue_depth); -DEF_TB_DEV_ATTRIB(target_core, max_unmap_lba_count); -DEF_TB_DEV_ATTRIB(target_core, max_unmap_block_desc_count); -DEF_TB_DEV_ATTRIB(target_core, unmap_granularity); -DEF_TB_DEV_ATTRIB(target_core, unmap_granularity_alignment); -DEF_TB_DEV_ATTRIB(target_core, max_write_same_len); + show_##_name); TB_DEV_ATTR(target_core, emulate_model_alias, S_IRUGO | S_IWUSR); TB_DEV_ATTR(target_core, emulate_dpo, S_IRUGO | S_IWUSR); @@ -620,11 +1045,6 @@ struct configfs_attribute *sbc_attrib_attrs[] = { }; EXPORT_SYMBOL(sbc_attrib_attrs); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_pi_prot_type); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_block_size); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_max_sectors); -DEF_TB_DEV_ATTRIB_RO(target_pt, hw_queue_depth); - TB_DEV_ATTR_RO(target_pt, hw_pi_prot_type); TB_DEV_ATTR_RO(target_pt, hw_block_size); TB_DEV_ATTR_RO(target_pt, hw_max_sectors); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index af906f1caaa7..22f1e180d8ee 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -665,510 +665,6 @@ bool se_dev_check_wce(struct se_device *dev) return wce; } -int se_dev_set_max_unmap_lba_count( - struct se_device *dev, - u32 max_unmap_lba_count) -{ - dev->dev_attrib.max_unmap_lba_count = max_unmap_lba_count; - pr_debug("dev[%p]: Set max_unmap_lba_count: %u\n", - dev, dev->dev_attrib.max_unmap_lba_count); - return 0; -} -EXPORT_SYMBOL(se_dev_set_max_unmap_lba_count); - -int se_dev_set_max_unmap_block_desc_count( - struct se_device *dev, - u32 max_unmap_block_desc_count) -{ - dev->dev_attrib.max_unmap_block_desc_count = - max_unmap_block_desc_count; - pr_debug("dev[%p]: Set max_unmap_block_desc_count: %u\n", - dev, dev->dev_attrib.max_unmap_block_desc_count); - return 0; -} -EXPORT_SYMBOL(se_dev_set_max_unmap_block_desc_count); - -int se_dev_set_unmap_granularity( - struct se_device *dev, - u32 unmap_granularity) -{ - dev->dev_attrib.unmap_granularity = unmap_granularity; - pr_debug("dev[%p]: Set unmap_granularity: %u\n", - dev, dev->dev_attrib.unmap_granularity); - return 0; -} -EXPORT_SYMBOL(se_dev_set_unmap_granularity); - -int se_dev_set_unmap_granularity_alignment( - struct se_device *dev, - u32 unmap_granularity_alignment) -{ - dev->dev_attrib.unmap_granularity_alignment = unmap_granularity_alignment; - pr_debug("dev[%p]: Set unmap_granularity_alignment: %u\n", - dev, dev->dev_attrib.unmap_granularity_alignment); - return 0; -} -EXPORT_SYMBOL(se_dev_set_unmap_granularity_alignment); - -int se_dev_set_max_write_same_len( - struct se_device *dev, - u32 max_write_same_len) -{ - dev->dev_attrib.max_write_same_len = max_write_same_len; - pr_debug("dev[%p]: Set max_write_same_len: %u\n", - dev, dev->dev_attrib.max_write_same_len); - return 0; -} -EXPORT_SYMBOL(se_dev_set_max_write_same_len); - -static void dev_set_t10_wwn_model_alias(struct se_device *dev) -{ - const char *configname; - - configname = config_item_name(&dev->dev_group.cg_item); - if (strlen(configname) >= 16) { - pr_warn("dev[%p]: Backstore name '%s' is too long for " - "INQUIRY_MODEL, truncating to 16 bytes\n", dev, - configname); - } - snprintf(&dev->t10_wwn.model[0], 16, "%s", configname); -} - -int se_dev_set_emulate_model_alias(struct se_device *dev, int flag) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change model alias" - " while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (flag) { - dev_set_t10_wwn_model_alias(dev); - } else { - strncpy(&dev->t10_wwn.model[0], - dev->transport->inquiry_prod, 16); - } - dev->dev_attrib.emulate_model_alias = flag; - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_model_alias); - -int se_dev_set_emulate_dpo(struct se_device *dev, int flag) -{ - printk_once(KERN_WARNING - "ignoring deprecated emulate_dpo attribute\n"); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_dpo); - -int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - if (flag && - dev->transport->get_write_cache) { - pr_warn("emulate_fua_write not supported for this device, ignoring\n"); - return 0; - } - if (dev->export_count) { - pr_err("emulate_fua_write cannot be changed with active" - " exports: %d\n", dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_fua_write = flag; - pr_debug("dev[%p]: SE Device Forced Unit Access WRITEs: %d\n", - dev, dev->dev_attrib.emulate_fua_write); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_fua_write); - -int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) -{ - printk_once(KERN_WARNING - "ignoring deprecated emulate_fua_read attribute\n"); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_fua_read); - -int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - if (flag && - dev->transport->get_write_cache) { - pr_err("emulate_write_cache not supported for this device\n"); - return -EINVAL; - } - if (dev->export_count) { - pr_err("emulate_write_cache cannot be changed with active" - " exports: %d\n", dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_write_cache = flag; - pr_debug("dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n", - dev, dev->dev_attrib.emulate_write_cache); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_write_cache); - -int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1) && (flag != 2)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device" - " UA_INTRLCK_CTRL while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_ua_intlck_ctrl = flag; - pr_debug("dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n", - dev, dev->dev_attrib.emulate_ua_intlck_ctrl); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_ua_intlck_ctrl); - -int se_dev_set_emulate_tas(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device TAS while" - " export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - dev->dev_attrib.emulate_tas = flag; - pr_debug("dev[%p]: SE Device TASK_ABORTED status bit: %s\n", - dev, (dev->dev_attrib.emulate_tas) ? "Enabled" : "Disabled"); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_tas); - -int se_dev_set_emulate_tpu(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - /* - * We expect this value to be non-zero when generic Block Layer - * Discard supported is detected iblock_create_virtdevice(). - */ - if (flag && !dev->dev_attrib.max_unmap_block_desc_count) { - pr_err("Generic Block Discard not supported\n"); - return -ENOSYS; - } - - dev->dev_attrib.emulate_tpu = flag; - pr_debug("dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n", - dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_tpu); - -int se_dev_set_emulate_tpws(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - /* - * We expect this value to be non-zero when generic Block Layer - * Discard supported is detected iblock_create_virtdevice(). - */ - if (flag && !dev->dev_attrib.max_unmap_block_desc_count) { - pr_err("Generic Block Discard not supported\n"); - return -ENOSYS; - } - - dev->dev_attrib.emulate_tpws = flag; - pr_debug("dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n", - dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_tpws); - -int se_dev_set_emulate_caw(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.emulate_caw = flag; - pr_debug("dev[%p]: SE Device CompareAndWrite (AtomicTestandSet): %d\n", - dev, flag); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_caw); - -int se_dev_set_emulate_3pc(struct se_device *dev, int flag) -{ - if (flag != 0 && flag != 1) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.emulate_3pc = flag; - pr_debug("dev[%p]: SE Device 3rd Party Copy (EXTENDED_COPY): %d\n", - dev, flag); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_3pc); - -int se_dev_set_pi_prot_type(struct se_device *dev, int flag) -{ - int rc, old_prot = dev->dev_attrib.pi_prot_type; - - if (flag != 0 && flag != 1 && flag != 2 && flag != 3) { - pr_err("Illegal value %d for pi_prot_type\n", flag); - return -EINVAL; - } - if (flag == 2) { - pr_err("DIF TYPE2 protection currently not supported\n"); - return -ENOSYS; - } - if (dev->dev_attrib.hw_pi_prot_type) { - pr_warn("DIF protection enabled on underlying hardware," - " ignoring\n"); - return 0; - } - if (!dev->transport->init_prot || !dev->transport->free_prot) { - /* 0 is only allowed value for non-supporting backends */ - if (flag == 0) - return 0; - - pr_err("DIF protection not supported by backend: %s\n", - dev->transport->name); - return -ENOSYS; - } - if (!(dev->dev_flags & DF_CONFIGURED)) { - pr_err("DIF protection requires device to be configured\n"); - return -ENODEV; - } - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device PROT type while" - " export_count is %d\n", dev, dev->export_count); - return -EINVAL; - } - - dev->dev_attrib.pi_prot_type = flag; - - if (flag && !old_prot) { - rc = dev->transport->init_prot(dev); - if (rc) { - dev->dev_attrib.pi_prot_type = old_prot; - return rc; - } - - } else if (!flag && old_prot) { - dev->transport->free_prot(dev); - } - pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_pi_prot_type); - -int se_dev_set_pi_prot_format(struct se_device *dev, int flag) -{ - int rc; - - if (!flag) - return 0; - - if (flag != 1) { - pr_err("Illegal value %d for pi_prot_format\n", flag); - return -EINVAL; - } - if (!dev->transport->format_prot) { - pr_err("DIF protection format not supported by backend %s\n", - dev->transport->name); - return -ENOSYS; - } - if (!(dev->dev_flags & DF_CONFIGURED)) { - pr_err("DIF protection format requires device to be configured\n"); - return -ENODEV; - } - if (dev->export_count) { - pr_err("dev[%p]: Unable to format SE Device PROT type while" - " export_count is %d\n", dev, dev->export_count); - return -EINVAL; - } - - rc = dev->transport->format_prot(dev); - if (rc) - return rc; - - pr_debug("dev[%p]: SE Device Protection Format complete\n", dev); - - return 0; -} -EXPORT_SYMBOL(se_dev_set_pi_prot_format); - -int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.enforce_pr_isids = flag; - pr_debug("dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev, - (dev->dev_attrib.enforce_pr_isids) ? "Enabled" : "Disabled"); - return 0; -} -EXPORT_SYMBOL(se_dev_set_enforce_pr_isids); - -int se_dev_set_force_pr_aptpl(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - printk(KERN_ERR "Illegal value %d\n", flag); - return -EINVAL; - } - if (dev->export_count) { - pr_err("dev[%p]: Unable to set force_pr_aptpl while" - " export_count is %d\n", dev, dev->export_count); - return -EINVAL; - } - - dev->dev_attrib.force_pr_aptpl = flag; - pr_debug("dev[%p]: SE Device force_pr_aptpl: %d\n", dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_force_pr_aptpl); - -int se_dev_set_is_nonrot(struct se_device *dev, int flag) -{ - if ((flag != 0) && (flag != 1)) { - printk(KERN_ERR "Illegal value %d\n", flag); - return -EINVAL; - } - dev->dev_attrib.is_nonrot = flag; - pr_debug("dev[%p]: SE Device is_nonrot bit: %d\n", - dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_is_nonrot); - -int se_dev_set_emulate_rest_reord(struct se_device *dev, int flag) -{ - if (flag != 0) { - printk(KERN_ERR "dev[%p]: SE Device emulation of restricted" - " reordering not implemented\n", dev); - return -ENOSYS; - } - dev->dev_attrib.emulate_rest_reord = flag; - pr_debug("dev[%p]: SE Device emulate_rest_reord: %d\n", dev, flag); - return 0; -} -EXPORT_SYMBOL(se_dev_set_emulate_rest_reord); - -/* - * Note, this can only be called on unexported SE Device Object. - */ -int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device TCQ while" - " export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - if (!queue_depth) { - pr_err("dev[%p]: Illegal ZERO value for queue" - "_depth\n", dev); - return -EINVAL; - } - - if (queue_depth > dev->dev_attrib.queue_depth) { - if (queue_depth > dev->dev_attrib.hw_queue_depth) { - pr_err("dev[%p]: Passed queue_depth:" - " %u exceeds TCM/SE_Device MAX" - " TCQ: %u\n", dev, queue_depth, - dev->dev_attrib.hw_queue_depth); - return -EINVAL; - } - } - dev->dev_attrib.queue_depth = dev->queue_depth = queue_depth; - pr_debug("dev[%p]: SE Device TCQ Depth changed to: %u\n", - dev, queue_depth); - return 0; -} -EXPORT_SYMBOL(se_dev_set_queue_depth); - -int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device" - " optimal_sectors while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - if (optimal_sectors > dev->dev_attrib.hw_max_sectors) { - pr_err("dev[%p]: Passed optimal_sectors %u cannot be" - " greater than hw_max_sectors: %u\n", dev, - optimal_sectors, dev->dev_attrib.hw_max_sectors); - return -EINVAL; - } - - dev->dev_attrib.optimal_sectors = optimal_sectors; - pr_debug("dev[%p]: SE Device optimal_sectors changed to %u\n", - dev, optimal_sectors); - return 0; -} -EXPORT_SYMBOL(se_dev_set_optimal_sectors); - -int se_dev_set_block_size(struct se_device *dev, u32 block_size) -{ - if (dev->export_count) { - pr_err("dev[%p]: Unable to change SE Device block_size" - " while export_count is %d\n", - dev, dev->export_count); - return -EINVAL; - } - - if ((block_size != 512) && - (block_size != 1024) && - (block_size != 2048) && - (block_size != 4096)) { - pr_err("dev[%p]: Illegal value for block_device: %u" - " for SE device, must be 512, 1024, 2048 or 4096\n", - dev, block_size); - return -EINVAL; - } - - dev->dev_attrib.block_size = block_size; - pr_debug("dev[%p]: SE Device block_size changed to %u\n", - dev, block_size); - - if (dev->dev_attrib.max_bytes_per_io) - dev->dev_attrib.hw_max_sectors = - dev->dev_attrib.max_bytes_per_io / block_size; - - return 0; -} -EXPORT_SYMBOL(se_dev_set_block_size); - int core_dev_add_lun( struct se_portal_group *tpg, struct se_device *dev, diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 2d5610516494..566c7d27f6d0 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -94,35 +94,6 @@ sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *, struct scatterlist *, u32, struct scatterlist *, u32); bool target_lun_is_rdonly(struct se_cmd *); - -/* attribute helpers from target_core_device.c for backend drivers */ -bool se_dev_check_wce(struct se_device *); -int se_dev_set_max_unmap_lba_count(struct se_device *, u32); -int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32); -int se_dev_set_unmap_granularity(struct se_device *, u32); -int se_dev_set_unmap_granularity_alignment(struct se_device *, u32); -int se_dev_set_max_write_same_len(struct se_device *, u32); -int se_dev_set_emulate_model_alias(struct se_device *, int); -int se_dev_set_emulate_dpo(struct se_device *, int); -int se_dev_set_emulate_fua_write(struct se_device *, int); -int se_dev_set_emulate_fua_read(struct se_device *, int); -int se_dev_set_emulate_write_cache(struct se_device *, int); -int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int); -int se_dev_set_emulate_tas(struct se_device *, int); -int se_dev_set_emulate_tpu(struct se_device *, int); -int se_dev_set_emulate_tpws(struct se_device *, int); -int se_dev_set_emulate_caw(struct se_device *, int); -int se_dev_set_emulate_3pc(struct se_device *, int); -int se_dev_set_pi_prot_type(struct se_device *, int); -int se_dev_set_pi_prot_format(struct se_device *, int); -int se_dev_set_enforce_pr_isids(struct se_device *, int); -int se_dev_set_force_pr_aptpl(struct se_device *, int); -int se_dev_set_is_nonrot(struct se_device *, int); -int se_dev_set_emulate_rest_reord(struct se_device *dev, int); -int se_dev_set_queue_depth(struct se_device *, u32); -int se_dev_set_max_sectors(struct se_device *, u32); -int se_dev_set_optimal_sectors(struct se_device *, u32); -int se_dev_set_block_size(struct se_device *, u32); sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); -- cgit v1.2.3 From b3eeea6619a0ed4f37138661c49339b21361d397 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 19 May 2015 16:16:01 +0200 Subject: target: Simplify LUN shutdown code Instead of starting a thread from transport_clear_lun_ref() that waits for LUN shutdown, wait in that function for LUN shutdown to finish. Additionally, change the return type of transport_clear_lun_ref() from int to void. Signed-off-by: Bart Van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 - drivers/target/target_core_internal.h | 2 +- drivers/target/target_core_tpg.c | 2 -- drivers/target/target_core_transport.c | 23 +---------------------- include/target/target_core_base.h | 1 - 5 files changed, 2 insertions(+), 27 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 22f1e180d8ee..1e4485b1849d 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -928,7 +928,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun = &dev->xcopy_lun; xcopy_lun->lun_se_dev = dev; - init_completion(&xcopy_lun->lun_shutdown_comp); spin_lock_init(&xcopy_lun->lun_sep_lock); init_completion(&xcopy_lun->lun_ref_comp); diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 01181aed67dc..23f992ed7cae 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -108,7 +108,7 @@ int transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); -int transport_clear_lun_ref(struct se_lun *); +void transport_clear_lun_ref(struct se_lun *); void transport_send_task_abort(struct se_cmd *); sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); void target_qf_do_work(struct work_struct *work); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 91f8ddb6d783..fd531fcf3191 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -494,7 +494,6 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) lun->unpacked_lun = 0; atomic_set(&lun->lun_acl_count, 0); - init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); @@ -606,7 +605,6 @@ struct se_lun *core_tpg_alloc_lun( lun->unpacked_lun = unpacked_lun; lun->lun_link_magic = SE_LUN_LINK_MAGIC; atomic_set(&lun->lun_acl_count, 0); - init_completion(&lun->lun_shutdown_comp); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 965a308e10a5..7c0518a28186 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2596,31 +2596,10 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) } EXPORT_SYMBOL(target_wait_for_sess_cmds); -static int transport_clear_lun_ref_thread(void *p) +void transport_clear_lun_ref(struct se_lun *lun) { - struct se_lun *lun = p; - percpu_ref_kill(&lun->lun_ref); - wait_for_completion(&lun->lun_ref_comp); - complete(&lun->lun_shutdown_comp); - - return 0; -} - -int transport_clear_lun_ref(struct se_lun *lun) -{ - struct task_struct *kt; - - kt = kthread_run(transport_clear_lun_ref_thread, lun, - "tcm_cl_%u", lun->unpacked_lun); - if (IS_ERR(kt)) { - pr_err("Unable to start clear_lun thread\n"); - return PTR_ERR(kt); - } - wait_for_completion(&lun->lun_shutdown_comp); - - return 0; } /** diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 03e2ee8f8337..ee7abdd6b7a2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -707,7 +707,6 @@ struct se_lun { u32 lun_index; atomic_t lun_acl_count; spinlock_t lun_sep_lock; - struct completion lun_shutdown_comp; struct se_device *lun_se_dev; struct se_port *lun_sep; struct config_group lun_group; -- cgit v1.2.3 From adf653f92f38e80a78bb77e912d49bcc8055330f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 25 May 2015 21:33:08 -0700 Subject: target: Subsume se_port + t10_alua_tg_pt_gp_member into se_lun This patch eliminates all se_port + t10_alua_tg_pt_gp_member usage, and converts current users to direct se_lun pointer dereference. This includes the removal of core_export_port(), core_release_port() core_dev_export() and core_dev_unexport(). Along with conversion of special case se_lun pointer dereference within PR ALL_TG_PT=1 and ALUA access state transition UNIT_ATTENTION handling. Also, update core_enable_device_list_for_node() to reference the new per se_lun->lun_deve_list when creating a new entry, or replacing an existing one via RCU. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 394 ++++++++++----------------- drivers/target/target_core_alua.h | 14 +- drivers/target/target_core_configfs.c | 11 +- drivers/target/target_core_device.c | 179 ++---------- drivers/target/target_core_fabric_configfs.c | 32 +-- drivers/target/target_core_internal.h | 12 +- drivers/target/target_core_pr.c | 56 ++-- drivers/target/target_core_spc.c | 48 ++-- drivers/target/target_core_stat.c | 299 ++++++++------------ drivers/target/target_core_tpg.c | 95 ++++--- drivers/target/target_core_transport.c | 34 +-- drivers/target/target_core_xcopy.c | 17 +- include/target/target_core_base.h | 74 +++-- 13 files changed, 458 insertions(+), 807 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 53cdfabac861..1109c2833fe6 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -43,11 +43,13 @@ static sense_reason_t core_alua_check_transition(int state, int valid, int *primary); static int core_alua_set_tg_pt_secondary_state( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, int explicit, int offline); + struct se_lun *lun, int explicit, int offline); static char *core_alua_dump_state(int state); +static void __target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp); + static u16 alua_lu_gps_counter; static u32 alua_lu_gps_count; @@ -145,9 +147,8 @@ sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_port *port; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + struct se_lun *lun; unsigned char *buf; u32 rd_len = 0, off; int ext_hdr = (cmd->t_task_cdb[1] & 0x20); @@ -222,9 +223,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) rd_len += 8; spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = tg_pt_gp_mem->tg_pt; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { /* * Start Target Port descriptor format * @@ -234,8 +234,8 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) /* * Set RELATIVE TARGET PORT IDENTIFIER */ - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); + buf[off++] = (lun->lun_rtpi & 0xff); rd_len += 4; } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); @@ -259,15 +259,11 @@ target_emulate_report_target_port_groups(struct se_cmd *cmd) * this CDB was received upon to determine this value individually * for ALUA target port group. */ - port = cmd->se_lun->lun_sep; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (tg_pt_gp_mem) { - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) - buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - } + spin_lock(&cmd->se_lun->lun_tg_pt_gp_lock); + tg_pt_gp = cmd->se_lun->lun_tg_pt_gp; + if (tg_pt_gp) + buf[5] = tg_pt_gp->tg_pt_gp_implicit_trans_secs; + spin_unlock(&cmd->se_lun->lun_tg_pt_gp_lock); } transport_kunmap_data_sg(cmd); @@ -284,10 +280,9 @@ sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_port *port, *l_port = cmd->se_lun->lun_sep; + struct se_lun *l_lun = cmd->se_lun; struct se_node_acl *nacl = cmd->se_sess->se_node_acl; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem; unsigned char *buf; unsigned char *ptr; sense_reason_t rc = TCM_NO_SENSE; @@ -295,9 +290,6 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) int alua_access_state, primary = 0, valid_states; u16 tg_pt_id, rtpi; - if (!l_port) - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - if (cmd->data_length < 4) { pr_warn("SET TARGET PORT GROUPS parameter list length %u too" " small\n", cmd->data_length); @@ -312,29 +304,24 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * Determine if explicit ALUA via SET_TARGET_PORT_GROUPS is allowed * for the local tg_pt_gp. */ - l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; - if (!l_tg_pt_gp_mem) { - pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); - rc = TCM_UNSUPPORTED_SCSI_OPCODE; - goto out; - } - spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp; + spin_lock(&l_lun->lun_tg_pt_gp_lock); + l_tg_pt_gp = l_lun->lun_tg_pt_gp; if (!l_tg_pt_gp) { - spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); - pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); + spin_unlock(&l_lun->lun_tg_pt_gp_lock); + pr_err("Unable to access l_lun->tg_pt_gp\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } - spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); if (!(l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA)) { + spin_unlock(&l_lun->lun_tg_pt_gp_lock); pr_debug("Unable to process SET_TARGET_PORT_GROUPS" " while TPGS_EXPLICIT_ALUA is disabled\n"); rc = TCM_UNSUPPORTED_SCSI_OPCODE; goto out; } valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states; + spin_unlock(&l_lun->lun_tg_pt_gp_lock); ptr = &buf[4]; /* Skip over RESERVED area in header */ @@ -396,7 +383,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) spin_unlock(&dev->t10_alua.tg_pt_gps_lock); if (!core_alua_do_port_transition(tg_pt_gp, - dev, l_port, nacl, + dev, l_lun, nacl, alua_access_state, 1)) found = true; @@ -406,6 +393,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) } spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } else { + struct se_lun *lun; + /* * Extract the RELATIVE TARGET PORT IDENTIFIER to identify * the Target Port in question for the the incoming @@ -417,17 +406,16 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd) * for the struct se_device storage object. */ spin_lock(&dev->se_port_lock); - list_for_each_entry(port, &dev->dev_sep_list, - sep_list) { - if (port->sep_rtpi != rtpi) + list_for_each_entry(lun, &dev->dev_sep_list, + lun_dev_link) { + if (lun->lun_rtpi != rtpi) continue; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - + // XXX: racy unlock spin_unlock(&dev->se_port_lock); if (!core_alua_set_tg_pt_secondary_state( - tg_pt_gp_mem, port, 1, 1)) + lun, 1, 1)) found = true; spin_lock(&dev->se_port_lock); @@ -696,9 +684,7 @@ target_alua_state_check(struct se_cmd *cmd) struct se_device *dev = cmd->se_dev; unsigned char *cdb = cmd->t_task_cdb; struct se_lun *lun = cmd->se_lun; - struct se_port *port = lun->lun_sep; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; int out_alua_state, nonop_delay_msecs; if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE) @@ -706,33 +692,27 @@ target_alua_state_check(struct se_cmd *cmd) if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) return 0; - if (!port) - return 0; /* * First, check for a struct se_port specific secondary ALUA target port * access state: OFFLINE */ - if (atomic_read(&port->sep_tg_pt_secondary_offline)) { + if (atomic_read(&lun->lun_tg_pt_secondary_offline)) { pr_debug("ALUA: Got secondary offline status for local" " target port\n"); set_ascq(cmd, ASCQ_04H_ALUA_OFFLINE); return TCM_CHECK_CONDITION_NOT_READY; } - /* - * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the - * ALUA target port group, to obtain current ALUA access state. - * Otherwise look for the underlying struct se_device association with - * a ALUA logical unit group. - */ - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) + + if (!lun->lun_tg_pt_gp) return 0; - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + // XXX: keeps using tg_pt_gp witout reference after unlock + spin_unlock(&lun->lun_tg_pt_gp_lock); /* * Process ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED in a separate conditional * statement so the compiler knows explicitly to check this case first. @@ -764,7 +744,7 @@ target_alua_state_check(struct se_cmd *cmd) break; /* * OFFLINE is a secondary ALUA target port group access state, that is - * handled above with struct se_port->sep_tg_pt_secondary_offline=1 + * handled above with struct se_lun->lun_tg_pt_secondary_offline=1 */ case ALUA_ACCESS_STATE_OFFLINE: default: @@ -906,10 +886,6 @@ int core_alua_check_nonop_delay( } EXPORT_SYMBOL(core_alua_check_nonop_delay); -/* - * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex - * - */ static int core_alua_write_tpg_metadata( const char *path, unsigned char *md_buf, @@ -971,16 +947,14 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work); struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; struct se_dev_entry *se_deve; + struct se_lun *lun; struct se_lun_acl *lacl; - struct se_port *port; - struct t10_alua_tg_pt_gp_member *mem; bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status == ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = mem->tg_pt; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { /* * After an implicit target port asymmetric access state * change, a device server shall establish a unit attention @@ -995,14 +969,13 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) * every I_T nexus other than the I_T nexus on which the SET * TARGET PORT GROUPS command */ - atomic_inc_mb(&mem->tg_pt_gp_mem_ref_cnt); + atomic_inc_mb(&lun->lun_active); spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - spin_lock_bh(&port->sep_alua_lock); - list_for_each_entry(se_deve, &port->sep_alua_list, - alua_port_list) { + spin_lock_bh(&lun->lun_deve_lock); + list_for_each_entry(se_deve, &lun->lun_deve_list, lun_link) { lacl = rcu_dereference_check(se_deve->se_lun_acl, - lockdep_is_held(&port->sep_alua_lock)); + lockdep_is_held(&lun->lun_deve_lock)); /* * se_deve->se_lun_acl pointer may be NULL for a * entry created without explicit Node+MappedLUN ACLs @@ -1014,18 +987,18 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) && (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) && (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) && - (tg_pt_gp->tg_pt_gp_alua_port != NULL) && - (tg_pt_gp->tg_pt_gp_alua_port == port)) + (tg_pt_gp->tg_pt_gp_alua_lun != NULL) && + (tg_pt_gp->tg_pt_gp_alua_lun == lun)) continue; core_scsi3_ua_allocate(lacl->se_lun_nacl, se_deve->mapped_lun, 0x2A, ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED); } - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock_bh(&lun->lun_deve_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - atomic_dec_mb(&mem->tg_pt_gp_mem_ref_cnt); + atomic_dec_mb(&lun->lun_active); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* @@ -1143,7 +1116,7 @@ static int core_alua_do_transition_tg_pt( int core_alua_do_port_transition( struct t10_alua_tg_pt_gp *l_tg_pt_gp, struct se_device *l_dev, - struct se_port *l_port, + struct se_lun *l_lun, struct se_node_acl *l_nacl, int new_state, int explicit) @@ -1173,7 +1146,7 @@ int core_alua_do_port_transition( * core_alua_do_transition_tg_pt() will always return * success. */ - l_tg_pt_gp->tg_pt_gp_alua_port = l_port; + l_tg_pt_gp->tg_pt_gp_alua_lun = l_lun; l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; rc = core_alua_do_transition_tg_pt(l_tg_pt_gp, new_state, explicit); @@ -1212,10 +1185,10 @@ int core_alua_do_port_transition( continue; if (l_tg_pt_gp == tg_pt_gp) { - tg_pt_gp->tg_pt_gp_alua_port = l_port; + tg_pt_gp->tg_pt_gp_alua_lun = l_lun; tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl; } else { - tg_pt_gp->tg_pt_gp_alua_port = NULL; + tg_pt_gp->tg_pt_gp_alua_lun = NULL; tg_pt_gp->tg_pt_gp_alua_nacl = NULL; } atomic_inc_mb(&tg_pt_gp->tg_pt_gp_ref_cnt); @@ -1252,22 +1225,20 @@ int core_alua_do_port_transition( return rc; } -/* - * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held - */ -static int core_alua_update_tpg_secondary_metadata( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port) +static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun) { + struct se_portal_group *se_tpg = lun->lun_tpg; unsigned char *md_buf; - struct se_portal_group *se_tpg = port->sep_tpg; char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN]; int len, rc; + mutex_lock(&lun->lun_tg_pt_md_mutex); + md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL); if (!md_buf) { pr_err("Unable to allocate buf for ALUA metadata\n"); - return -ENOMEM; + rc = -ENOMEM; + goto out_unlock; } memset(path, 0, ALUA_METADATA_PATH_LEN); @@ -1282,32 +1253,33 @@ static int core_alua_update_tpg_secondary_metadata( len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n" "alua_tg_pt_status=0x%02x\n", - atomic_read(&port->sep_tg_pt_secondary_offline), - port->sep_tg_pt_secondary_stat); + atomic_read(&lun->lun_tg_pt_secondary_offline), + lun->lun_tg_pt_secondary_stat); snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u", se_tpg->se_tpg_tfo->get_fabric_name(), wwn, - port->sep_lun->unpacked_lun); + lun->unpacked_lun); rc = core_alua_write_tpg_metadata(path, md_buf, len); kfree(md_buf); +out_unlock: + mutex_unlock(&lun->lun_tg_pt_md_mutex); return rc; } static int core_alua_set_tg_pt_secondary_state( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct se_port *port, + struct se_lun *lun, int explicit, int offline) { struct t10_alua_tg_pt_gp *tg_pt_gp; int trans_delay_msecs; - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (!tg_pt_gp) { - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); pr_err("Unable to complete secondary state" " transition\n"); return -EINVAL; @@ -1315,14 +1287,14 @@ static int core_alua_set_tg_pt_secondary_state( trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs; /* * Set the secondary ALUA target port access state to OFFLINE - * or release the previously secondary state for struct se_port + * or release the previously secondary state for struct se_lun */ if (offline) - atomic_set(&port->sep_tg_pt_secondary_offline, 1); + atomic_set(&lun->lun_tg_pt_secondary_offline, 1); else - atomic_set(&port->sep_tg_pt_secondary_offline, 0); + atomic_set(&lun->lun_tg_pt_secondary_offline, 0); - port->sep_tg_pt_secondary_stat = (explicit) ? + lun->lun_tg_pt_secondary_stat = (explicit) ? ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG : ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA; @@ -1331,7 +1303,7 @@ static int core_alua_set_tg_pt_secondary_state( "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item), tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE"); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); /* * Do the optional transition delay after we set the secondary * ALUA access state. @@ -1342,11 +1314,8 @@ static int core_alua_set_tg_pt_secondary_state( * See if we need to update the ALUA fabric port metadata for * secondary state and status */ - if (port->sep_tg_pt_secondary_write_md) { - mutex_lock(&port->sep_tg_pt_md_mutex); - core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port); - mutex_unlock(&port->sep_tg_pt_md_mutex); - } + if (lun->lun_tg_pt_secondary_write_md) + core_alua_update_tpg_secondary_metadata(lun); return 0; } @@ -1700,7 +1669,7 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev, return NULL; } INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list); - INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list); + INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_lun_list); mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex); spin_lock_init(&tg_pt_gp->tg_pt_gp_lock); atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0); @@ -1794,32 +1763,11 @@ again: return 0; } -struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( - struct se_port *port) -{ - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache, - GFP_KERNEL); - if (!tg_pt_gp_mem) { - pr_err("Unable to allocate struct t10_alua_tg_pt_gp_member\n"); - return ERR_PTR(-ENOMEM); - } - INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list); - spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0); - - tg_pt_gp_mem->tg_pt = port; - port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem; - - return tg_pt_gp_mem; -} - void core_alua_free_tg_pt_gp( struct t10_alua_tg_pt_gp *tg_pt_gp) { struct se_device *dev = tg_pt_gp->tg_pt_gp_dev; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp; + struct se_lun *lun, *next; /* * Once we have reached this point, config_item_put() has already @@ -1850,30 +1798,24 @@ void core_alua_free_tg_pt_gp( * struct se_port. */ spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp, - &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) { - if (tg_pt_gp_mem->tg_pt_gp_assoc) { - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp->tg_pt_gp_members--; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; - } + list_for_each_entry_safe(lun, next, + &tg_pt_gp->tg_pt_gp_lun_list, lun_tg_pt_gp_link) { + list_del_init(&lun->lun_tg_pt_gp_link); + tg_pt_gp->tg_pt_gp_members--; + spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* - * tg_pt_gp_mem is associated with a single - * se_port->sep_alua_tg_pt_gp_mem, and is released via - * core_alua_free_tg_pt_gp_mem(). - * * If the passed tg_pt_gp does NOT match the default_tg_pt_gp, * assume we want to re-associate a given tg_pt_gp_mem with * default_tg_pt_gp. */ - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_lock(&lun->lun_tg_pt_gp_lock); if (tg_pt_gp != dev->t10_alua.default_tg_pt_gp) { - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + __target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); } else - tg_pt_gp_mem->tg_pt_gp = NULL; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + lun->lun_tg_pt_gp = NULL; + spin_unlock(&lun->lun_tg_pt_gp_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); } @@ -1882,35 +1824,6 @@ void core_alua_free_tg_pt_gp( kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp); } -void core_alua_free_tg_pt_gp_mem(struct se_port *port) -{ - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return; - - while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt)) - cpu_relax(); - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; - if (tg_pt_gp) { - spin_lock(&tg_pt_gp->tg_pt_gp_lock); - if (tg_pt_gp_mem->tg_pt_gp_assoc) { - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp->tg_pt_gp_members--; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; - } - spin_unlock(&tg_pt_gp->tg_pt_gp_lock); - tg_pt_gp_mem->tg_pt_gp = NULL; - } - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - - kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem); -} - static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name( struct se_device *dev, const char *name) { @@ -1944,50 +1857,58 @@ static void core_alua_put_tg_pt_gp_from_name( spin_unlock(&dev->t10_alua.tg_pt_gps_lock); } -/* - * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held - */ -void __core_alua_attach_tg_pt_gp_mem( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct t10_alua_tg_pt_gp *tg_pt_gp) +static void __target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) { + assert_spin_locked(&lun->lun_tg_pt_gp_lock); + spin_lock(&tg_pt_gp->tg_pt_gp_lock); - tg_pt_gp_mem->tg_pt_gp = tg_pt_gp; - tg_pt_gp_mem->tg_pt_gp_assoc = 1; - list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list, - &tg_pt_gp->tg_pt_gp_mem_list); + lun->lun_tg_pt_gp = tg_pt_gp; + list_add_tail(&lun->lun_tg_pt_gp_link, &tg_pt_gp->tg_pt_gp_lun_list); tg_pt_gp->tg_pt_gp_members++; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); } -/* - * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held - */ -static void __core_alua_drop_tg_pt_gp_mem( - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, - struct t10_alua_tg_pt_gp *tg_pt_gp) +void target_attach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) +{ + spin_lock(&lun->lun_tg_pt_gp_lock); + __target_attach_tg_pt_gp(lun, tg_pt_gp); + spin_unlock(&lun->lun_tg_pt_gp_lock); +} + +static void __target_detach_tg_pt_gp(struct se_lun *lun, + struct t10_alua_tg_pt_gp *tg_pt_gp) { + assert_spin_locked(&lun->lun_tg_pt_gp_lock); + spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list); - tg_pt_gp_mem->tg_pt_gp = NULL; - tg_pt_gp_mem->tg_pt_gp_assoc = 0; + list_del_init(&lun->lun_tg_pt_gp_link); tg_pt_gp->tg_pt_gp_members--; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); + + lun->lun_tg_pt_gp = NULL; } -ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) +void target_detach_tg_pt_gp(struct se_lun *lun) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp; + + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; + if (tg_pt_gp) + __target_detach_tg_pt_gp(lun, tg_pt_gp); + spin_unlock(&lun->lun_tg_pt_gp_lock); +} + +ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page) { struct config_item *tg_pt_ci; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; ssize_t len = 0; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return len; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) { tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item; len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:" @@ -1999,34 +1920,29 @@ ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page) &tg_pt_gp->tg_pt_gp_alua_access_state)), core_alua_dump_status( tg_pt_gp->tg_pt_gp_alua_access_status), - (atomic_read(&port->sep_tg_pt_secondary_offline)) ? + atomic_read(&lun->lun_tg_pt_secondary_offline) ? "Offline" : "None", - core_alua_dump_status(port->sep_tg_pt_secondary_stat)); + core_alua_dump_status(lun->lun_tg_pt_secondary_stat)); } - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); return len; } ssize_t core_alua_store_tg_pt_gp_info( - struct se_port *port, + struct se_lun *lun, const char *page, size_t count) { - struct se_portal_group *tpg; - struct se_lun *lun; - struct se_device *dev = port->sep_lun->lun_se_dev; + struct se_portal_group *tpg = lun->lun_tpg; + struct se_device *dev = lun->lun_se_dev; struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char buf[TG_PT_GROUP_NAME_BUF]; int move = 0; - tpg = port->sep_tpg; - lun = port->sep_lun; - - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return 0; + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH || + (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + return -ENODEV; if (count > TG_PT_GROUP_NAME_BUF) { pr_err("ALUA Target Port Group alias too large!\n"); @@ -2050,8 +1966,8 @@ ssize_t core_alua_store_tg_pt_gp_info( return -ENODEV; } - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) { /* * Clearing an existing tg_pt_gp association, and replacing @@ -2069,24 +1985,19 @@ ssize_t core_alua_store_tg_pt_gp_info( &tg_pt_gp->tg_pt_gp_group.cg_item), tg_pt_gp->tg_pt_gp_id); - __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, + __target_detach_tg_pt_gp(lun, tg_pt_gp); + __target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); return count; } - /* - * Removing existing association of tg_pt_gp_mem with tg_pt_gp - */ - __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp); + __target_detach_tg_pt_gp(lun, tg_pt_gp); move = 1; } - /* - * Associate tg_pt_gp_mem with tg_pt_gp_new. - */ - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + + __target_attach_tg_pt_gp(lun, tg_pt_gp_new); + spin_unlock(&lun->lun_tg_pt_gp_lock); pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA" " Target Port Group: alua/%s, ID: %hu\n", (move) ? "Moving" : "Adding", tpg->se_tpg_tfo->tpg_get_wwn(tpg), @@ -2269,11 +2180,8 @@ ssize_t core_alua_store_preferred_bit( ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page) { - if (!lun->lun_sep) - return -ENODEV; - return sprintf(page, "%d\n", - atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline)); + atomic_read(&lun->lun_tg_pt_secondary_offline)); } ssize_t core_alua_store_offline_bit( @@ -2281,11 +2189,12 @@ ssize_t core_alua_store_offline_bit( const char *page, size_t count) { - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; + struct se_device *dev = lun->lun_se_dev; unsigned long tmp; int ret; - if (!lun->lun_sep) + if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH || + (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) return -ENODEV; ret = kstrtoul(page, 0, &tmp); @@ -2298,14 +2207,8 @@ ssize_t core_alua_store_offline_bit( tmp); return -EINVAL; } - tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) { - pr_err("Unable to locate *tg_pt_gp_mem\n"); - return -EINVAL; - } - ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem, - lun->lun_sep, 0, (int)tmp); + ret = core_alua_set_tg_pt_secondary_state(lun, 0, (int)tmp); if (ret < 0) return -EINVAL; @@ -2316,7 +2219,7 @@ ssize_t core_alua_show_secondary_status( struct se_lun *lun, char *page) { - return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat); + return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_stat); } ssize_t core_alua_store_secondary_status( @@ -2339,7 +2242,7 @@ ssize_t core_alua_store_secondary_status( tmp); return -EINVAL; } - lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp; + lun->lun_tg_pt_secondary_stat = (int)tmp; return count; } @@ -2348,8 +2251,7 @@ ssize_t core_alua_show_secondary_write_metadata( struct se_lun *lun, char *page) { - return sprintf(page, "%d\n", - lun->lun_sep->sep_tg_pt_secondary_write_md); + return sprintf(page, "%d\n", lun->lun_tg_pt_secondary_write_md); } ssize_t core_alua_store_secondary_write_metadata( @@ -2370,7 +2272,7 @@ ssize_t core_alua_store_secondary_write_metadata( " %lu\n", tmp); return -EINVAL; } - lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp; + lun->lun_tg_pt_secondary_write_md = (int)tmp; return count; } diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index 0a7d65e80404..9b250f9b33bf 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -85,7 +85,6 @@ extern struct kmem_cache *t10_alua_lu_gp_cache; extern struct kmem_cache *t10_alua_lu_gp_mem_cache; extern struct kmem_cache *t10_alua_tg_pt_gp_cache; -extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; extern struct kmem_cache *t10_alua_lba_map_cache; extern struct kmem_cache *t10_alua_lba_map_mem_cache; @@ -94,7 +93,7 @@ extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *); extern sense_reason_t target_emulate_report_referrals(struct se_cmd *); extern int core_alua_check_nonop_delay(struct se_cmd *); extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *, - struct se_device *, struct se_port *, + struct se_device *, struct se_lun *, struct se_node_acl *, int, int); extern char *core_alua_dump_status(int); extern struct t10_alua_lba_map *core_alua_allocate_lba_map( @@ -117,14 +116,11 @@ extern void core_alua_drop_lu_gp_dev(struct se_device *); extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp( struct se_device *, const char *, int); extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16); -extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( - struct se_port *); extern void core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp *); -extern void core_alua_free_tg_pt_gp_mem(struct se_port *); -extern void __core_alua_attach_tg_pt_gp_mem(struct t10_alua_tg_pt_gp_member *, - struct t10_alua_tg_pt_gp *); -extern ssize_t core_alua_show_tg_pt_gp_info(struct se_port *, char *); -extern ssize_t core_alua_store_tg_pt_gp_info(struct se_port *, const char *, +extern void target_detach_tg_pt_gp(struct se_lun *); +extern void target_attach_tg_pt_gp(struct se_lun *, struct t10_alua_tg_pt_gp *); +extern ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *, char *); +extern ssize_t core_alua_store_tg_pt_gp_info(struct se_lun *, const char *, size_t); extern ssize_t core_alua_show_access_type(struct t10_alua_tg_pt_gp *, char *); extern ssize_t core_alua_store_access_type(struct t10_alua_tg_pt_gp *, diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 4313eea060ed..f97b969e6714 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -2889,21 +2889,16 @@ static ssize_t target_core_alua_tg_pt_gp_show_attr_members( struct t10_alua_tg_pt_gp *tg_pt_gp, char *page) { - struct se_port *port; - struct se_portal_group *tpg; struct se_lun *lun; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; ssize_t len = 0, cur_len; unsigned char buf[TG_PT_GROUP_NAME_BUF]; memset(buf, 0, TG_PT_GROUP_NAME_BUF); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list, - tg_pt_gp_mem_list) { - port = tg_pt_gp_mem->tg_pt; - tpg = port->sep_tpg; - lun = port->sep_lun; + list_for_each_entry(lun, &tg_pt_gp->tg_pt_gp_lun_list, + lun_tg_pt_gp_link) { + struct se_portal_group *tpg = lun->lun_tpg; cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu" "/%s\n", tpg->se_tpg_tfo->get_fabric_name(), diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1e4485b1849d..8485e9a789fc 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -120,8 +120,8 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) (se_cmd->data_direction != DMA_NONE)) return TCM_WRITE_PROTECTED; - se_lun = &se_sess->se_tpg->tpg_virt_lun0; - se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; + se_lun = se_sess->se_tpg->tpg_virt_lun0; + se_cmd->se_lun = se_sess->se_tpg->tpg_virt_lun0; se_cmd->orig_fe_lun = 0; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; @@ -309,7 +309,6 @@ int core_enable_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { - struct se_port *port = lun->lun_sep; struct se_dev_entry *orig, *new; new = kzalloc(sizeof(*new), GFP_KERNEL); @@ -320,8 +319,8 @@ int core_enable_device_list_for_node( atomic_set(&new->ua_count, 0); spin_lock_init(&new->ua_lock); - INIT_LIST_HEAD(&new->alua_port_list); INIT_LIST_HEAD(&new->ua_list); + INIT_LIST_HEAD(&new->lun_link); new->mapped_lun = mapped_lun; kref_init(&new->pr_kref); @@ -357,10 +356,10 @@ int core_enable_device_list_for_node( hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); - spin_lock_bh(&port->sep_alua_lock); - list_del(&orig->alua_port_list); - list_add_tail(&new->alua_port_list, &port->sep_alua_list); - spin_unlock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun->lun_deve_lock); + list_del(&orig->lun_link); + list_add_tail(&new->lun_link, &lun->lun_deve_list); + spin_unlock_bh(&lun->lun_deve_lock); kref_put(&orig->pr_kref, target_pr_kref_release); wait_for_completion(&orig->pr_comp); @@ -374,9 +373,9 @@ int core_enable_device_list_for_node( hlist_add_head_rcu(&new->link, &nacl->lun_entry_hlist); mutex_unlock(&nacl->lun_entry_mutex); - spin_lock_bh(&port->sep_alua_lock); - list_add_tail(&new->alua_port_list, &port->sep_alua_list); - spin_unlock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun->lun_deve_lock); + list_add_tail(&new->lun_link, &lun->lun_deve_list); + spin_unlock_bh(&lun->lun_deve_lock); return 0; } @@ -390,23 +389,22 @@ void core_disable_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { - struct se_port *port = lun->lun_sep; /* * If the MappedLUN entry is being disabled, the entry in - * port->sep_alua_list must be removed now before clearing the + * lun->lun_deve_list must be removed now before clearing the * struct se_dev_entry pointers below as logic in * core_alua_do_transition_tg_pt() depends on these being present. * * deve->se_lun_acl will be NULL for demo-mode created LUNs * that have not been explicitly converted to MappedLUNs -> - * struct se_lun_acl, but we remove deve->alua_port_list from - * port->sep_alua_list. This also means that active UAs and + * struct se_lun_acl, but we remove deve->lun_link from + * lun->lun_deve_list. This also means that active UAs and * NodeACL context specific PR metadata for demo-mode * MappedLUN *deve will be released below.. */ - spin_lock_bh(&port->sep_alua_lock); - list_del(&orig->alua_port_list); - spin_unlock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun->lun_deve_lock); + list_del(&orig->lun_link); + spin_unlock_bh(&lun->lun_deve_lock); /* * Disable struct se_dev_entry LUN ACL mapping */ @@ -458,27 +456,16 @@ void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg) mutex_unlock(&tpg->acl_node_mutex); } -static struct se_port *core_alloc_port(struct se_device *dev) +int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev) { - struct se_port *port, *port_tmp; - - port = kzalloc(sizeof(struct se_port), GFP_KERNEL); - if (!port) { - pr_err("Unable to allocate struct se_port\n"); - return ERR_PTR(-ENOMEM); - } - INIT_LIST_HEAD(&port->sep_alua_list); - INIT_LIST_HEAD(&port->sep_list); - atomic_set(&port->sep_tg_pt_secondary_offline, 0); - spin_lock_init(&port->sep_alua_lock); - mutex_init(&port->sep_tg_pt_md_mutex); + struct se_lun *tmp; spin_lock(&dev->se_port_lock); - if (dev->dev_port_count == 0x0000ffff) { + if (dev->export_count == 0x0000ffff) { pr_warn("Reached dev->dev_port_count ==" " 0x0000ffff\n"); spin_unlock(&dev->se_port_lock); - return ERR_PTR(-ENOSPC); + return -ENOSPC; } again: /* @@ -493,135 +480,23 @@ again: * 2h Relative port 2, historically known as port B * 3h to FFFFh Relative port 3 through 65 535 */ - port->sep_rtpi = dev->dev_rpti_counter++; - if (!port->sep_rtpi) + lun->lun_rtpi = dev->dev_rpti_counter++; + if (!lun->lun_rtpi) goto again; - list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) { + list_for_each_entry(tmp, &dev->dev_sep_list, lun_dev_link) { /* * Make sure RELATIVE TARGET PORT IDENTIFIER is unique * for 16-bit wrap.. */ - if (port->sep_rtpi == port_tmp->sep_rtpi) + if (lun->lun_rtpi == tmp->lun_rtpi) goto again; } spin_unlock(&dev->se_port_lock); - return port; -} - -static void core_export_port( - struct se_device *dev, - struct se_portal_group *tpg, - struct se_port *port, - struct se_lun *lun) -{ - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL; - - spin_lock(&dev->se_port_lock); - spin_lock(&lun->lun_sep_lock); - port->sep_tpg = tpg; - port->sep_lun = lun; - lun->lun_sep = port; - spin_unlock(&lun->lun_sep_lock); - - list_add_tail(&port->sep_list, &dev->dev_sep_list); - spin_unlock(&dev->se_port_lock); - - if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) && - !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) { - tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port); - if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) { - pr_err("Unable to allocate t10_alua_tg_pt" - "_gp_member_t\n"); - return; - } - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, - dev->t10_alua.default_tg_pt_gp); - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - pr_debug("%s/%s: Adding to default ALUA Target Port" - " Group: alua/default_tg_pt_gp\n", - dev->transport->name, tpg->se_tpg_tfo->get_fabric_name()); - } - - dev->dev_port_count++; - port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFIER */ -} - -/* - * Called with struct se_device->se_port_lock spinlock held. - */ -static void core_release_port(struct se_device *dev, struct se_port *port) - __releases(&dev->se_port_lock) __acquires(&dev->se_port_lock) -{ - /* - * Wait for any port reference for PR ALL_TG_PT=1 operation - * to complete in __core_scsi3_alloc_registration() - */ - spin_unlock(&dev->se_port_lock); - if (atomic_read(&port->sep_tg_pt_ref_cnt)) - cpu_relax(); - spin_lock(&dev->se_port_lock); - - core_alua_free_tg_pt_gp_mem(port); - - list_del(&port->sep_list); - dev->dev_port_count--; - kfree(port); -} - -int core_dev_export( - struct se_device *dev, - struct se_portal_group *tpg, - struct se_lun *lun) -{ - struct se_hba *hba = dev->se_hba; - struct se_port *port; - - port = core_alloc_port(dev); - if (IS_ERR(port)) - return PTR_ERR(port); - - lun->lun_index = dev->dev_index; - lun->lun_se_dev = dev; - lun->lun_rtpi = port->sep_rtpi; - - spin_lock(&hba->device_lock); - dev->export_count++; - spin_unlock(&hba->device_lock); - - core_export_port(dev, tpg, port, lun); return 0; } -void core_dev_unexport( - struct se_device *dev, - struct se_portal_group *tpg, - struct se_lun *lun) -{ - struct se_hba *hba = dev->se_hba; - struct se_port *port = lun->lun_sep; - - spin_lock(&lun->lun_sep_lock); - if (lun->lun_se_dev == NULL) { - spin_unlock(&lun->lun_sep_lock); - return; - } - spin_unlock(&lun->lun_sep_lock); - - spin_lock(&dev->se_port_lock); - core_release_port(dev, port); - spin_unlock(&dev->se_port_lock); - - spin_lock(&hba->device_lock); - dev->export_count--; - spin_unlock(&hba->device_lock); - - lun->lun_sep = NULL; - lun->lun_se_dev = NULL; -} - static void se_release_vpd_for_dev(struct se_device *dev) { struct t10_vpd *vpd, *vpd_tmp; @@ -783,10 +658,10 @@ int core_dev_add_initiator_node_lun_acl( } int core_dev_del_initiator_node_lun_acl( - struct se_portal_group *tpg, struct se_lun *lun, struct se_lun_acl *lacl) { + struct se_portal_group *tpg = lun->lun_tpg; struct se_node_acl *nacl; struct se_dev_entry *deve; @@ -930,6 +805,10 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) xcopy_lun->lun_se_dev = dev; spin_lock_init(&xcopy_lun->lun_sep_lock); init_completion(&xcopy_lun->lun_ref_comp); + INIT_LIST_HEAD(&xcopy_lun->lun_deve_list); + INIT_LIST_HEAD(&xcopy_lun->lun_dev_link); + mutex_init(&xcopy_lun->lun_tg_pt_md_mutex); + xcopy_lun->lun_tpg = &xcopy_pt_tpg; return dev; } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 9be8030e016f..0ee182fce1a6 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -91,12 +91,11 @@ static int target_fabric_mappedlun_link( /* * Ensure that the source port exists */ - if (!lun->lun_sep || !lun->lun_sep->sep_tpg) { - pr_err("Source se_lun->lun_sep or lun->lun_sep->sep" - "_tpg does not exist\n"); + if (!lun->lun_se_dev) { + pr_err("Source se_lun->lun_se_dev does not exist\n"); return -EINVAL; } - se_tpg = lun->lun_sep->sep_tpg; + se_tpg = lun->lun_tpg; nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item; tpg_ci = &nacl_ci->ci_group->cg_item; @@ -150,9 +149,8 @@ static int target_fabric_mappedlun_unlink( struct se_lun_acl, se_lun_group); struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; - return core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl); + return core_dev_del_initiator_node_lun_acl(lun, lacl); } CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl); @@ -643,10 +641,10 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; - return core_alua_show_tg_pt_gp_info(lun->lun_sep, page); + return core_alua_show_tg_pt_gp_info(lun, page); } static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp( @@ -654,10 +652,10 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; - return core_alua_store_tg_pt_gp_info(lun->lun_sep, page, count); + return core_alua_store_tg_pt_gp_info(lun, page, count); } TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR); @@ -669,7 +667,7 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_offline_bit(lun, page); @@ -680,7 +678,7 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_offline_bit(lun, page, count); @@ -695,7 +693,7 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_status( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_secondary_status(lun, page); @@ -706,7 +704,7 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_status( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_secondary_status(lun, page, count); @@ -721,7 +719,7 @@ static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md( struct se_lun *lun, char *page) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_show_secondary_write_metadata(lun, page); @@ -732,7 +730,7 @@ static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md( const char *page, size_t count) { - if (!lun || !lun->lun_sep) + if (!lun || !lun->lun_se_dev) return -ENODEV; return core_alua_store_secondary_write_metadata(lun, page, count); @@ -811,7 +809,7 @@ static int target_fabric_port_unlink( { struct se_lun *lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group); - struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg; + struct se_portal_group *se_tpg = lun->lun_tpg; struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; if (tf->tf_ops->fabric_pre_unlink) { diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 23f992ed7cae..8d8737a13e6f 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -21,6 +21,7 @@ extern struct t10_alua_lu_gp *default_lu_gp; extern struct mutex g_device_mutex; extern struct list_head g_device_list; +int core_alloc_rtpi(struct se_lun *lun, struct se_device *dev); struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); void target_pr_kref_release(struct kref *); void core_free_device_list_for_node(struct se_node_acl *, @@ -32,10 +33,6 @@ int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); -int core_dev_export(struct se_device *, struct se_portal_group *, - struct se_lun *); -void core_dev_unexport(struct se_device *, struct se_portal_group *, - struct se_lun *); int core_dev_add_lun(struct se_portal_group *, struct se_device *, struct se_lun *lun); void core_dev_del_lun(struct se_portal_group *, struct se_lun *); @@ -43,8 +40,8 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group * struct se_node_acl *, u32, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *, struct se_lun *lun, u32); -int core_dev_del_initiator_node_lun_acl(struct se_portal_group *, - struct se_lun *, struct se_lun_acl *); +int core_dev_del_initiator_node_lun_acl(struct se_lun *, + struct se_lun_acl *); void core_dev_free_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *lacl); int core_dev_setup_virtual_lun0(void); @@ -120,4 +117,7 @@ void target_stat_setup_dev_default_groups(struct se_device *); void target_stat_setup_port_default_groups(struct se_lun *); void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); +/* target_core_xcopy.c */ +extern struct se_portal_group xcopy_pt_tpg; + #endif /* TARGET_CORE_INTERNAL_H */ diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index b983f8a54766..60624bb6c598 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -642,7 +642,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( pr_reg->pr_reg_deve = deve; pr_reg->pr_res_mapped_lun = mapped_lun; pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; - pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; + pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; pr_reg->pr_res_key = sa_res_key; pr_reg->pr_reg_all_tg_pt = all_tg_pt; pr_reg->pr_reg_aptpl = aptpl; @@ -680,8 +680,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_dev_entry *deve_tmp; struct se_node_acl *nacl_tmp; struct se_lun_acl *lacl_tmp; - struct se_lun *lun_tmp; - struct se_port *port, *port_tmp; + struct se_lun *lun_tmp, *next, *dest_lun; const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe; int ret; @@ -704,13 +703,12 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * for ALL_TG_PT=1 */ spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) { - atomic_inc_mb(&port->sep_tg_pt_ref_cnt); + list_for_each_entry_safe(lun_tmp, next, &dev->dev_sep_list, lun_dev_link) { + atomic_inc_mb(&lun_tmp->lun_active); spin_unlock(&dev->se_port_lock); - spin_lock_bh(&port->sep_alua_lock); - list_for_each_entry(deve_tmp, &port->sep_alua_list, - alua_port_list) { + spin_lock_bh(&lun_tmp->lun_deve_lock); + list_for_each_entry(deve_tmp, &lun_tmp->lun_deve_list, lun_link) { /* * This pointer will be NULL for demo mode MappedLUNs * that have not been make explicit via a ConfigFS @@ -720,7 +718,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; lacl_tmp = rcu_dereference_check(deve_tmp->se_lun_acl, - lockdep_is_held(&port->sep_alua_lock)); + lockdep_is_held(&lun_tmp->lun_deve_lock)); nacl_tmp = lacl_tmp->se_lun_nacl; /* * Skip the matching struct se_node_acl that is allocated @@ -742,7 +740,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( continue; kref_get(&deve_tmp->pr_kref); - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock_bh(&lun_tmp->lun_deve_lock); /* * Grab a configfs group dependency that is released * for the exception path at label out: below, or upon @@ -753,7 +751,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (ret < 0) { pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); - atomic_dec_mb(&port->sep_tg_pt_ref_cnt); + atomic_dec_mb(&lun->lun_active); kref_put(&deve_tmp->pr_kref, target_pr_kref_release); goto out; } @@ -764,27 +762,27 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * the original *pr_reg is processed in * __core_scsi3_add_registration() */ - lun_tmp = rcu_dereference_check(deve_tmp->se_lun, + dest_lun = rcu_dereference_check(deve_tmp->se_lun, atomic_read(&deve_tmp->pr_kref.refcount) != 0); pr_reg_atp = __core_scsi3_do_alloc_registration(dev, - nacl_tmp, lun_tmp, deve_tmp, + nacl_tmp, dest_lun, deve_tmp, deve_tmp->mapped_lun, NULL, sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { - atomic_dec_mb(&port->sep_tg_pt_ref_cnt); + atomic_dec_mb(&lun_tmp->lun_active); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list, &pr_reg->pr_reg_atp_list); - spin_lock_bh(&port->sep_alua_lock); + spin_lock_bh(&lun_tmp->lun_deve_lock); } - spin_unlock_bh(&port->sep_alua_lock); + spin_unlock_bh(&lun_tmp->lun_deve_lock); spin_lock(&dev->se_port_lock); - atomic_dec_mb(&port->sep_tg_pt_ref_cnt); + atomic_dec_mb(&lun_tmp->lun_active); } spin_unlock(&dev->se_port_lock); @@ -938,7 +936,7 @@ static int __core_scsi3_check_aptpl_registration( (pr_reg->pr_aptpl_target_lun == target_lun)) { pr_reg->pr_reg_nacl = nacl; - pr_reg->tg_pt_sep_rtpi = lun->lun_sep->sep_rtpi; + pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; list_del(&pr_reg->pr_reg_aptpl_list); spin_unlock(&pr_tmpl->aptpl_reg_lock); @@ -1465,7 +1463,6 @@ core_scsi3_decode_spec_i_port( int aptpl) { struct se_device *dev = cmd->se_dev; - struct se_port *tmp_port; struct se_portal_group *dest_tpg = NULL, *tmp_tpg; struct se_session *se_sess = cmd->se_sess; struct se_node_acl *dest_node_acl = NULL; @@ -1550,16 +1547,14 @@ core_scsi3_decode_spec_i_port( ptr = &buf[28]; while (tpdl > 0) { - struct se_lun *dest_lun; + struct se_lun *dest_lun, *tmp_lun; proto_ident = (ptr[0] & 0x0f); dest_tpg = NULL; spin_lock(&dev->se_port_lock); - list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) { - tmp_tpg = tmp_port->sep_tpg; - if (!tmp_tpg) - continue; + list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) { + tmp_tpg = tmp_lun->lun_tpg; /* * Look for the matching proto_ident provided by @@ -1567,7 +1562,7 @@ core_scsi3_decode_spec_i_port( */ if (tmp_tpg->proto_id != proto_ident) continue; - dest_rtpi = tmp_port->sep_rtpi; + dest_rtpi = tmp_lun->lun_rtpi; i_str = target_parse_pr_out_transport_id(tmp_tpg, (const char *)ptr, &tid_len, &iport_ptr); @@ -3119,9 +3114,8 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, struct se_session *se_sess = cmd->se_sess; struct se_device *dev = cmd->se_dev; struct se_dev_entry *dest_se_deve = NULL; - struct se_lun *se_lun = cmd->se_lun; + struct se_lun *se_lun = cmd->se_lun, *tmp_lun; struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL; - struct se_port *se_port; struct se_portal_group *se_tpg, *dest_se_tpg = NULL; const struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops; struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg; @@ -3206,12 +3200,10 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key, } spin_lock(&dev->se_port_lock); - list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) { - if (se_port->sep_rtpi != rtpi) - continue; - dest_se_tpg = se_port->sep_tpg; - if (!dest_se_tpg) + list_for_each_entry(tmp_lun, &dev->dev_sep_list, lun_dev_link) { + if (tmp_lun->lun_rtpi != rtpi) continue; + dest_se_tpg = tmp_lun->lun_tpg; dest_tf_ops = dest_se_tpg->se_tpg_tfo; if (!dest_tf_ops) continue; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 9f995b87b8d1..34d8292a4432 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -37,10 +37,9 @@ #include "target_core_ua.h" #include "target_core_xcopy.h" -static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) +static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf) { struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; /* * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS. @@ -53,17 +52,11 @@ static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) * * See spc4r17 section 6.4.2 Table 135 */ - if (!port) - return; - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - return; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (tg_pt_gp) buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); } sense_reason_t @@ -94,7 +87,7 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf) /* * Enable SCCS and TPGS fields for Emulated ALUA */ - spc_fill_alua_data(lun->lun_sep, buf); + spc_fill_alua_data(lun, buf); /* * Set Third-Party Copy (3PC) bit to indicate support for EXTENDED_COPY @@ -181,11 +174,9 @@ spc_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; struct se_lun *lun = cmd->se_lun; - struct se_port *port = NULL; struct se_portal_group *tpg = NULL; struct t10_alua_lu_gp_member *lu_gp_mem; struct t10_alua_tg_pt_gp *tg_pt_gp; - struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem; unsigned char *prod = &dev->t10_wwn.model[0]; u32 prod_len; u32 unit_serial_len, off = 0; @@ -267,18 +258,15 @@ check_t10_vend_desc: /* Header size for Designation descriptor */ len += (id_len + 4); off += (id_len + 4); - /* - * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD - */ - port = lun->lun_sep; - if (port) { + + if (1) { struct t10_alua_lu_gp *lu_gp; u32 padding, scsi_name_len, scsi_target_len; u16 lu_gp_id = 0; u16 tg_pt_gp_id = 0; u16 tpgt; - tpg = port->sep_tpg; + tpg = lun->lun_tpg; /* * Relative target port identifer, see spc4r17 * section 7.7.3.7 @@ -298,8 +286,8 @@ check_t10_vend_desc: /* Skip over Obsolete field in RTPI payload * in Table 472 */ off += 2; - buf[off++] = ((port->sep_rtpi >> 8) & 0xff); - buf[off++] = (port->sep_rtpi & 0xff); + buf[off++] = ((lun->lun_rtpi >> 8) & 0xff); + buf[off++] = (lun->lun_rtpi & 0xff); len += 8; /* Header size + Designation descriptor */ /* * Target port group identifier, see spc4r17 @@ -308,18 +296,14 @@ check_t10_vend_desc: * Get the PROTOCOL IDENTIFIER as defined by spc4r17 * section 7.5.1 Table 362 */ - tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; - if (!tg_pt_gp_mem) - goto check_lu_gp; - - spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); - tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; + spin_lock(&lun->lun_tg_pt_gp_lock); + tg_pt_gp = lun->lun_tg_pt_gp; if (!tg_pt_gp) { - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); goto check_lu_gp; } tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id; - spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); + spin_unlock(&lun->lun_tg_pt_gp_lock); buf[off] = tpg->proto_id << 4; buf[off++] |= 0x1; /* CODE SET == Binary */ @@ -694,7 +678,7 @@ static sense_reason_t spc_emulate_inquiry(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg; + struct se_portal_group *tpg = cmd->se_lun->lun_tpg; unsigned char *rbuf; unsigned char *cdb = cmd->t_task_cdb; unsigned char *buf; @@ -708,7 +692,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (dev == tpg->tpg_virt_lun0.lun_se_dev) + if (dev == tpg->tpg_virt_lun0->lun_se_dev) buf[0] = 0x3f; /* Not connected */ else buf[0] = dev->transport->get_device_type(dev); diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index ea1287940a7c..8e080efb0188 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -106,7 +106,7 @@ static ssize_t target_stat_scsi_dev_show_attr_ports( struct se_device *dev = container_of(sgrps, struct se_device, dev_stat_grps); - return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); + return snprintf(page, PAGE_SIZE, "%u\n", dev->export_count); } DEV_STAT_SCSI_DEV_ATTR_RO(ports); @@ -542,19 +542,13 @@ static ssize_t target_stat_scsi_port_show_attr_inst( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_device *dev = lun->lun_se_dev; - struct se_hba *hba; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - hba = dev->se_hba; - ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -564,17 +558,13 @@ static ssize_t target_stat_scsi_port_show_attr_dev( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_device *dev = lun->lun_se_dev; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -584,16 +574,13 @@ static ssize_t target_stat_scsi_port_show_attr_indx( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -603,20 +590,13 @@ static ssize_t target_stat_scsi_port_show_attr_role( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - ssize_t ret; - - if (!dev) - return -ENODEV; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -626,17 +606,15 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + /* FIXME: scsiPortBusyStatuses */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - /* FIXME: scsiPortBusyStatuses */ - ret = snprintf(page, PAGE_SIZE, "%u\n", 0); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -685,19 +663,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - struct se_hba *hba; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - hba = dev->se_hba; - ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -707,17 +679,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -727,16 +695,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -746,20 +711,16 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_portal_group *tpg = lun->lun_tpg; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - tpg = sep->sep_tpg; - - ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", - tpg->se_tpg_tfo->get_fabric_name(), sep->sep_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", + tpg->se_tpg_tfo->get_fabric_name(), + lun->lun_rtpi); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -769,21 +730,16 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_portal_group *tpg = lun->lun_tpg; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - tpg = sep->sep_tpg; - - ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", - tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", - tpg->se_tpg_tfo->tpg_get_tag(tpg)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", + tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", + tpg->se_tpg_tfo->tpg_get_tag(tpg)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -793,17 +749,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_stats.cmd_pdus); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -813,18 +765,14 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(sep->sep_stats.rx_data_octets >> 20)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(lun->lun_stats.rx_data_octets >> 20)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -834,18 +782,14 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(sep->sep_stats.tx_data_octets >> 20)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(lun->lun_stats.tx_data_octets >> 20)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -855,18 +799,15 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + /* FIXME: scsiTgtPortHsInCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - - /* FIXME: scsiTgtPortHsInCommands */ - ret = snprintf(page, PAGE_SIZE, "%u\n", 0); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -921,20 +862,13 @@ static ssize_t target_stat_scsi_transport_show_attr_inst( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - struct se_hba *hba; - ssize_t ret; + struct se_device *dev; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - - hba = dev->se_hba; - ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -944,20 +878,17 @@ static ssize_t target_stat_scsi_transport_show_attr_device( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_device *dev; + struct se_portal_group *tpg = lun->lun_tpg; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + /* scsiTransportType */ + ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", + tpg->se_tpg_tfo->get_fabric_name()); } - tpg = sep->sep_tpg; - /* scsiTransportType */ - ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", - tpg->se_tpg_tfo->get_fabric_name()); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -967,19 +898,15 @@ static ssize_t target_stat_scsi_transport_show_attr_indx( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_port *sep; - struct se_portal_group *tpg; - ssize_t ret; + struct se_device *dev; + struct se_portal_group *tpg = lun->lun_tpg; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; - } - tpg = sep->sep_tpg; - ret = snprintf(page, PAGE_SIZE, "%u\n", - tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); + dev = lun->lun_se_dev; + if (dev) + ret = snprintf(page, PAGE_SIZE, "%u\n", + tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); spin_unlock(&lun->lun_sep_lock); return ret; } @@ -990,24 +917,20 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); struct se_device *dev = lun->lun_se_dev; - struct se_port *sep; - struct se_portal_group *tpg; + struct se_portal_group *tpg = lun->lun_tpg; struct t10_wwn *wwn; - ssize_t ret; + ssize_t ret = -ENODEV; spin_lock(&lun->lun_sep_lock); - sep = lun->lun_sep; - if (!sep) { - spin_unlock(&lun->lun_sep_lock); - return -ENODEV; + dev = lun->lun_se_dev; + if (dev) { + wwn = &dev->t10_wwn; + /* scsiTransportDevName */ + ret = snprintf(page, PAGE_SIZE, "%s+%s\n", + tpg->se_tpg_tfo->tpg_get_wwn(tpg), + (strlen(wwn->unit_serial)) ? wwn->unit_serial : + wwn->vendor); } - tpg = sep->sep_tpg; - wwn = &dev->t10_wwn; - /* scsiTransportDevName */ - ret = snprintf(page, PAGE_SIZE, "%s+%s\n", - tpg->se_tpg_tfo->tpg_get_wwn(tpg), - (strlen(wwn->unit_serial)) ? wwn->unit_serial : - wwn->vendor); spin_unlock(&lun->lun_sep_lock); return ret; } diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index fd531fcf3191..499b1399035a 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -40,6 +40,7 @@ #include #include "target_core_internal.h" +#include "target_core_alua.h" #include "target_core_pr.h" extern struct se_device *g_lun0_dev; @@ -484,32 +485,14 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref) complete(&lun->lun_ref_comp); } -static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) -{ - /* Set in core_dev_setup_virtual_lun0() */ - struct se_device *dev = g_lun0_dev; - struct se_lun *lun = &se_tpg->tpg_virt_lun0; - u32 lun_access = TRANSPORT_LUNFLAGS_READ_ONLY; - int ret; - - lun->unpacked_lun = 0; - atomic_set(&lun->lun_acl_count, 0); - spin_lock_init(&lun->lun_sep_lock); - init_completion(&lun->lun_ref_comp); - - ret = core_tpg_add_lun(se_tpg, lun, lun_access, dev); - if (ret < 0) - return ret; - - return 0; -} - int core_tpg_register( const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, int proto_id) { + int ret; + INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); se_tpg->proto_id = proto_id; se_tpg->se_tpg_tfo = tfo; @@ -523,8 +506,16 @@ int core_tpg_register( mutex_init(&se_tpg->acl_node_mutex); if (se_tpg->proto_id >= 0) { - if (core_tpg_setup_virtual_lun0(se_tpg) < 0) - return -ENOMEM; + se_tpg->tpg_virt_lun0 = core_tpg_alloc_lun(se_tpg, 0); + if (IS_ERR(se_tpg->tpg_virt_lun0)) + return PTR_ERR(se_tpg->tpg_virt_lun0); + + ret = core_tpg_add_lun(se_tpg, se_tpg->tpg_virt_lun0, + TRANSPORT_LUNFLAGS_READ_ONLY, g_lun0_dev); + if (ret < 0) { + kfree(se_tpg->tpg_virt_lun0); + return ret; + } } spin_lock_bh(&tpg_lock); @@ -575,8 +566,10 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) kfree(nacl); } - if (se_tpg->proto_id >= 0) - core_tpg_remove_lun(se_tpg, &se_tpg->tpg_virt_lun0); + if (se_tpg->proto_id >= 0) { + core_tpg_remove_lun(se_tpg, se_tpg->tpg_virt_lun0); + kfree_rcu(se_tpg->tpg_virt_lun0, rcu_head); + } return 0; } @@ -607,6 +600,15 @@ struct se_lun *core_tpg_alloc_lun( atomic_set(&lun->lun_acl_count, 0); spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); + INIT_LIST_HEAD(&lun->lun_deve_list); + INIT_LIST_HEAD(&lun->lun_dev_link); + atomic_set(&lun->lun_tg_pt_secondary_offline, 0); + spin_lock_init(&lun->lun_deve_lock); + mutex_init(&lun->lun_tg_pt_md_mutex); + INIT_LIST_HEAD(&lun->lun_tg_pt_gp_link); + spin_lock_init(&lun->lun_tg_pt_gp_lock); + atomic_set(&lun->lun_active, 0); + lun->lun_tpg = tpg; return lun; } @@ -622,21 +624,40 @@ int core_tpg_add_lun( ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release, 0, GFP_KERNEL); if (ret < 0) - return ret; + goto out; - ret = core_dev_export(dev, tpg, lun); - if (ret < 0) { - percpu_ref_exit(&lun->lun_ref); - return ret; - } + ret = core_alloc_rtpi(lun, dev); + if (ret) + goto out_kill_ref; + + if (!(dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH) && + !(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) + target_attach_tg_pt_gp(lun, dev->t10_alua.default_tg_pt_gp); mutex_lock(&tpg->tpg_lun_mutex); + + spin_lock(&lun->lun_sep_lock); + lun->lun_index = dev->dev_index; + lun->lun_se_dev = dev; + spin_unlock(&lun->lun_sep_lock); + + spin_lock(&dev->se_port_lock); + rcu_assign_pointer(lun->lun_se_dev, dev); + dev->export_count++; + list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list); + spin_unlock(&dev->se_port_lock); + lun->lun_access = lun_access; if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_add_head_rcu(&lun->link, &tpg->tpg_lun_hlist); mutex_unlock(&tpg->tpg_lun_mutex); return 0; + +out_kill_ref: + percpu_ref_exit(&lun->lun_ref); +out: + return ret; } void core_tpg_remove_lun( @@ -648,9 +669,19 @@ void core_tpg_remove_lun( core_clear_lun_from_tpg(lun, tpg); transport_clear_lun_ref(lun); - core_dev_unexport(lun->lun_se_dev, tpg, lun); - mutex_lock(&tpg->tpg_lun_mutex); + if (lun->lun_se_dev) { + while (atomic_read(&lun->lun_active)) + cpu_relax(); + + target_detach_tg_pt_gp(lun); + + spin_lock(&dev->se_port_lock); + list_del(&lun->lun_dev_link); + dev->export_count--; + rcu_assign_pointer(lun->lun_se_dev, NULL); + spin_unlock(&dev->se_port_lock); + } if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) hlist_del_rcu(&lun->link); mutex_unlock(&tpg->tpg_lun_mutex); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7c0518a28186..ef6fdd8a47c4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -60,7 +60,6 @@ struct kmem_cache *t10_pr_reg_cache; struct kmem_cache *t10_alua_lu_gp_cache; struct kmem_cache *t10_alua_lu_gp_mem_cache; struct kmem_cache *t10_alua_tg_pt_gp_cache; -struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; struct kmem_cache *t10_alua_lba_map_cache; struct kmem_cache *t10_alua_lba_map_mem_cache; @@ -119,16 +118,6 @@ int init_se_kmem_caches(void) "cache failed\n"); goto out_free_lu_gp_mem_cache; } - t10_alua_tg_pt_gp_mem_cache = kmem_cache_create( - "t10_alua_tg_pt_gp_mem_cache", - sizeof(struct t10_alua_tg_pt_gp_member), - __alignof__(struct t10_alua_tg_pt_gp_member), - 0, NULL); - if (!t10_alua_tg_pt_gp_mem_cache) { - pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" - "mem_t failed\n"); - goto out_free_tg_pt_gp_cache; - } t10_alua_lba_map_cache = kmem_cache_create( "t10_alua_lba_map_cache", sizeof(struct t10_alua_lba_map), @@ -136,7 +125,7 @@ int init_se_kmem_caches(void) if (!t10_alua_lba_map_cache) { pr_err("kmem_cache_create() for t10_alua_lba_map_" "cache failed\n"); - goto out_free_tg_pt_gp_mem_cache; + goto out_free_tg_pt_gp_cache; } t10_alua_lba_map_mem_cache = kmem_cache_create( "t10_alua_lba_map_mem_cache", @@ -159,8 +148,6 @@ out_free_lba_map_mem_cache: kmem_cache_destroy(t10_alua_lba_map_mem_cache); out_free_lba_map_cache: kmem_cache_destroy(t10_alua_lba_map_cache); -out_free_tg_pt_gp_mem_cache: - kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); out_free_tg_pt_gp_cache: kmem_cache_destroy(t10_alua_tg_pt_gp_cache); out_free_lu_gp_mem_cache: @@ -186,7 +173,6 @@ void release_se_kmem_caches(void) kmem_cache_destroy(t10_alua_lu_gp_cache); kmem_cache_destroy(t10_alua_lu_gp_mem_cache); kmem_cache_destroy(t10_alua_tg_pt_gp_cache); - kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); kmem_cache_destroy(t10_alua_lba_map_cache); kmem_cache_destroy(t10_alua_lba_map_mem_cache); } @@ -1277,8 +1263,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) - cmd->se_lun->lun_sep->sep_stats.cmd_pdus++; + cmd->se_lun->lun_stats.cmd_pdus++; spin_unlock(&cmd->se_lun->lun_sep_lock); return 0; } @@ -2076,10 +2061,7 @@ queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) { - cmd->se_lun->lun_sep->sep_stats.tx_data_octets += - cmd->data_length; - } + cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; spin_unlock(&cmd->se_lun->lun_sep_lock); /* * Perform READ_STRIP of PI using software emulation when @@ -2104,20 +2086,14 @@ queue_rsp: break; case DMA_TO_DEVICE: spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) { - cmd->se_lun->lun_sep->sep_stats.rx_data_octets += - cmd->data_length; - } + cmd->se_lun->lun_stats.rx_data_octets += cmd->data_length; spin_unlock(&cmd->se_lun->lun_sep_lock); /* * Check if we need to send READ payload for BIDI-COMMAND */ if (cmd->se_cmd_flags & SCF_BIDI) { spin_lock(&cmd->se_lun->lun_sep_lock); - if (cmd->se_lun->lun_sep) { - cmd->se_lun->lun_sep->sep_stats.tx_data_octets += - cmd->data_length; - } + cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; spin_unlock(&cmd->se_lun->lun_sep_lock); ret = cmd->se_tfo->queue_data_in(cmd); if (ret == -EAGAIN || ret == -ENOMEM) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 3556a9dcee46..49111d39e795 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -348,8 +348,7 @@ struct xcopy_pt_cmd { unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; }; -static struct se_port xcopy_pt_port; -static struct se_portal_group xcopy_pt_tpg; +struct se_portal_group xcopy_pt_tpg; static struct se_session xcopy_pt_sess; static struct se_node_acl xcopy_pt_nacl; @@ -439,17 +438,11 @@ int target_xcopy_setup_pt(void) return -ENOMEM; } - memset(&xcopy_pt_port, 0, sizeof(struct se_port)); - INIT_LIST_HEAD(&xcopy_pt_port.sep_alua_list); - INIT_LIST_HEAD(&xcopy_pt_port.sep_list); - mutex_init(&xcopy_pt_port.sep_tg_pt_md_mutex); - memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group)); INIT_LIST_HEAD(&xcopy_pt_tpg.se_tpg_node); INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list); INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list); - xcopy_pt_port.sep_tpg = &xcopy_pt_tpg; xcopy_pt_tpg.se_tpg_tfo = &xcopy_pt_tfo; memset(&xcopy_pt_nacl, 0, sizeof(struct se_node_acl)); @@ -490,10 +483,6 @@ static void target_xcopy_setup_pt_port( */ if (remote_port) { xpt_cmd->remote_port = remote_port; - pt_cmd->se_lun->lun_sep = &xcopy_pt_port; - pr_debug("Setup emulated remote DEST xcopy_pt_port: %p to" - " cmd->se_lun->lun_sep for X-COPY data PUSH\n", - pt_cmd->se_lun->lun_sep); } else { pt_cmd->se_lun = ec_cmd->se_lun; pt_cmd->se_dev = ec_cmd->se_dev; @@ -513,10 +502,6 @@ static void target_xcopy_setup_pt_port( */ if (remote_port) { xpt_cmd->remote_port = remote_port; - pt_cmd->se_lun->lun_sep = &xcopy_pt_port; - pr_debug("Setup emulated remote SRC xcopy_pt_port: %p to" - " cmd->se_lun->lun_sep for X-COPY data PULL\n", - pt_cmd->se_lun->lun_sep); } else { pt_cmd->se_lun = ec_cmd->se_lun; pt_cmd->se_dev = ec_cmd->se_dev; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index ee7abdd6b7a2..1927dd5947a7 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -304,22 +304,13 @@ struct t10_alua_tg_pt_gp { struct se_device *tg_pt_gp_dev; struct config_group tg_pt_gp_group; struct list_head tg_pt_gp_list; - struct list_head tg_pt_gp_mem_list; - struct se_port *tg_pt_gp_alua_port; + struct list_head tg_pt_gp_lun_list; + struct se_lun *tg_pt_gp_alua_lun; struct se_node_acl *tg_pt_gp_alua_nacl; struct delayed_work tg_pt_gp_transition_work; struct completion *tg_pt_gp_transition_complete; }; -struct t10_alua_tg_pt_gp_member { - bool tg_pt_gp_assoc; - atomic_t tg_pt_gp_mem_ref_cnt; - spinlock_t tg_pt_gp_mem_lock; - struct t10_alua_tg_pt_gp *tg_pt_gp; - struct se_port *tg_pt; - struct list_head tg_pt_gp_mem_list; -}; - struct t10_vpd { unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN]; int protocol_identifier_set; @@ -650,6 +641,7 @@ struct se_dev_entry { #define DEF_PR_REG_ACTIVE 1 unsigned long deve_flags; struct list_head alua_port_list; + struct list_head lun_link; struct list_head ua_list; struct hlist_node link; struct rcu_head rcu_head; @@ -697,7 +689,14 @@ struct se_port_stat_grps { struct config_group scsi_transport_group; }; +struct scsi_port_stats { + u32 cmd_pdus; + u64 tx_data_octets; + u64 rx_data_octets; +}; + struct se_lun { + /* RELATIVE TARGET PORT IDENTIFER */ u16 lun_rtpi; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; @@ -707,12 +706,30 @@ struct se_lun { u32 lun_index; atomic_t lun_acl_count; spinlock_t lun_sep_lock; - struct se_device *lun_se_dev; - struct se_port *lun_sep; + struct se_device __rcu *lun_se_dev; + + struct list_head lun_deve_list; + spinlock_t lun_deve_lock; + + /* ALUA state */ + int lun_tg_pt_secondary_stat; + int lun_tg_pt_secondary_write_md; + atomic_t lun_tg_pt_secondary_offline; + struct mutex lun_tg_pt_md_mutex; + + /* ALUA target port group linkage */ + struct list_head lun_tg_pt_gp_link; + struct t10_alua_tg_pt_gp *lun_tg_pt_gp; + spinlock_t lun_tg_pt_gp_lock; + + atomic_t lun_active; + struct se_portal_group *lun_tpg; + struct scsi_port_stats lun_stats; struct config_group lun_group; struct se_port_stat_grps port_stat_grps; struct completion lun_ref_comp; struct percpu_ref lun_ref; + struct list_head lun_dev_link; struct hlist_node link; struct rcu_head rcu_head; }; @@ -737,7 +754,6 @@ struct se_device { #define DF_EMULATED_VPD_UNIT_SERIAL 0x00000004 #define DF_USING_UDEV_PATH 0x00000008 #define DF_USING_ALIAS 0x00000010 - u32 dev_port_count; /* Physical device queue depth */ u32 queue_depth; /* Used for SPC-2 reservations enforce of ISIDs */ @@ -754,7 +770,7 @@ struct se_device { atomic_t dev_ordered_id; atomic_t dev_ordered_sync; atomic_t dev_qf_count; - int export_count; + u32 export_count; spinlock_t delayed_cmd_lock; spinlock_t execute_task_lock; spinlock_t dev_reservation_lock; @@ -821,32 +837,6 @@ struct se_hba { struct target_backend *backend; }; -struct scsi_port_stats { - u64 cmd_pdus; - u64 tx_data_octets; - u64 rx_data_octets; -}; - -struct se_port { - /* RELATIVE TARGET PORT IDENTIFER */ - u16 sep_rtpi; - int sep_tg_pt_secondary_stat; - int sep_tg_pt_secondary_write_md; - u32 sep_index; - struct scsi_port_stats sep_stats; - /* Used for ALUA Target Port Groups membership */ - atomic_t sep_tg_pt_secondary_offline; - /* Used for PR ALL_TG_PT=1 */ - atomic_t sep_tg_pt_ref_cnt; - spinlock_t sep_alua_lock; - struct mutex sep_tg_pt_md_mutex; - struct t10_alua_tg_pt_gp_member *sep_alua_tg_pt_gp_mem; - struct se_lun *sep_lun; - struct se_portal_group *sep_tpg; - struct list_head sep_alua_list; - struct list_head sep_list; -}; - struct se_tpg_np { struct se_portal_group *tpg_np_parent; struct config_group tpg_np_group; @@ -872,7 +862,7 @@ struct se_portal_group { /* linked list for initiator ACL list */ struct list_head acl_node_list; struct hlist_head tpg_lun_hlist; - struct se_lun tpg_virt_lun0; + struct se_lun *tpg_virt_lun0; /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list; /* Pointer to $FABRIC_MOD dependent code */ -- cgit v1.2.3 From 4cc987eaff9144182cde88d6d132420c28d3f81b Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 19 May 2015 00:03:07 -0700 Subject: target: Drop lun_sep_lock for se_lun->lun_se_dev RCU usage With se_port and t10_alua_tg_pt_gp_member being absored into se_lun, there is no need for an extra lock to protect se_lun->lun_se_dev assignment. This patch also converts backend drivers to use call_rcu() release to allow any se_device readers to complete. The call_rcu() instead of kfree_rcu() is required here because se_device is embedded into the backend driver specific structure. Also, convert se_lun->lun_stats to use atomic_long_t within the target_complete_ok_work() completion callback, and add FIXME for transport_lookup_tmr_lun() with se_lun->lun_ref. Finally, update sbp_update_unit_directory() special case usage with proper rcu_dereference_raw() and configfs symlink comment. Reported-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Cc: Paul E. McKenney Cc: Chris Boot Signed-off-by: Nicholas Bellinger --- drivers/target/sbp/sbp_target.c | 7 +- drivers/target/target_core_alua.c | 12 +++- drivers/target/target_core_device.c | 47 ++++++++----- drivers/target/target_core_file.c | 11 ++- drivers/target/target_core_iblock.c | 10 ++- drivers/target/target_core_pscsi.c | 11 ++- drivers/target/target_core_rd.c | 10 ++- drivers/target/target_core_spc.c | 2 +- drivers/target/target_core_stat.c | 123 +++++++++++++++++---------------- drivers/target/target_core_tpg.c | 16 ++--- drivers/target/target_core_transport.c | 20 ++---- drivers/target/target_core_user.c | 11 ++- include/target/target_core_base.h | 10 +-- 13 files changed, 175 insertions(+), 115 deletions(-) (limited to 'include') diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 47fb12fbaf47..28e3adf1eb85 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1905,8 +1905,11 @@ static int sbp_update_unit_directory(struct sbp_tport *tport) hlist_for_each_entry_rcu(lun, &tport->tpg->se_tpg.tpg_lun_hlist, link) { struct se_device *dev; int type; - - dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + dev = rcu_dereference_raw(lun->lun_se_dev); type = dev->transport->get_device_type(dev); /* logical_unit_number */ diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 1109c2833fe6..0a0087311cfb 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1935,7 +1935,11 @@ ssize_t core_alua_store_tg_pt_gp_info( size_t count) { struct se_portal_group *tpg = lun->lun_tpg; - struct se_device *dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL; unsigned char buf[TG_PT_GROUP_NAME_BUF]; int move = 0; @@ -2189,7 +2193,11 @@ ssize_t core_alua_store_offline_bit( const char *page, size_t count) { - struct se_device *dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); unsigned long tmp; int ret; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8485e9a789fc..3baa6cd7fded 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -61,7 +61,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; struct se_node_acl *nacl = se_sess->se_node_acl; - struct se_device *dev; struct se_dev_entry *deve; if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) @@ -128,16 +127,21 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) percpu_ref_get(&se_lun->lun_ref); se_cmd->lun_ref_active = true; } + /* + * RCU reference protected by percpu se_lun->lun_ref taken above that + * must drop to zero (including initial reference) before this se_lun + * pointer can be kfree_rcu() by the final se_lun->lun_group put via + * target_core_fabric_configfs.c:target_fabric_port_release + */ + se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); + atomic_long_inc(&se_cmd->se_dev->num_cmds); - /* Directly associate cmd with se_dev */ - se_cmd->se_dev = se_lun->lun_se_dev; - - dev = se_lun->lun_se_dev; - atomic_long_inc(&dev->num_cmds); if (se_cmd->data_direction == DMA_TO_DEVICE) - atomic_long_add(se_cmd->data_length, &dev->write_bytes); + atomic_long_add(se_cmd->data_length, + &se_cmd->se_dev->write_bytes); else if (se_cmd->data_direction == DMA_FROM_DEVICE) - atomic_long_add(se_cmd->data_length, &dev->read_bytes); + atomic_long_add(se_cmd->data_length, + &se_cmd->se_dev->read_bytes); return 0; } @@ -173,10 +177,11 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) unpacked_lun); return -ENODEV; } - - /* Directly associate cmd with se_dev */ - se_cmd->se_dev = se_lun->lun_se_dev; - se_tmr->tmr_dev = se_lun->lun_se_dev; + /* + * XXX: Add percpu se_lun->lun_ref reference count for TMR + */ + se_cmd->se_dev = rcu_dereference_raw(se_lun->lun_se_dev); + se_tmr->tmr_dev = rcu_dereference_raw(se_lun->lun_se_dev); spin_lock_irqsave(&se_tmr->tmr_dev->se_tmr_lock, flags); list_add_tail(&se_tmr->tmr_list, &se_tmr->tmr_dev->dev_tmr_list); @@ -389,6 +394,11 @@ void core_disable_device_list_for_node( struct se_node_acl *nacl, struct se_portal_group *tpg) { + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); /* * If the MappedLUN entry is being disabled, the entry in * lun->lun_deve_list must be removed now before clearing the @@ -426,7 +436,7 @@ void core_disable_device_list_for_node( kfree_rcu(orig, rcu_head); - core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl); + core_scsi3_free_pr_reg_from_nacl(dev, nacl); } /* core_clear_lun_from_tpg(): @@ -629,6 +639,11 @@ int core_dev_add_initiator_node_lun_acl( u32 lun_access) { struct se_node_acl *nacl = lacl->se_lun_nacl; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); if (!nacl) return -EINVAL; @@ -652,7 +667,7 @@ int core_dev_add_initiator_node_lun_acl( * Check to see if there are any existing persistent reservation APTPL * pre-registrations that need to be enabled for this LUN ACL.. */ - core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, nacl, + core_scsi3_check_aptpl_registration(dev, tpg, lun, nacl, lacl->mapped_lun); return 0; } @@ -746,6 +761,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->se_hba = hba; dev->transport = hba->backend->ops; dev->prot_length = sizeof(struct se_dif_v1_tuple); + dev->hba_index = hba->hba_index; INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); @@ -802,8 +818,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN; xcopy_lun = &dev->xcopy_lun; - xcopy_lun->lun_se_dev = dev; - spin_lock_init(&xcopy_lun->lun_sep_lock); + rcu_assign_pointer(xcopy_lun->lun_se_dev, dev); init_completion(&xcopy_lun->lun_ref_comp); INIT_LIST_HEAD(&xcopy_lun->lun_deve_list); INIT_LIST_HEAD(&xcopy_lun->lun_dev_link); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 948b61f59a55..238e3a256d04 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -241,6 +241,14 @@ fail: return ret; } +static void fd_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct fd_dev *fd_dev = FD_DEV(dev); + + kfree(fd_dev); +} + static void fd_free_device(struct se_device *dev) { struct fd_dev *fd_dev = FD_DEV(dev); @@ -249,8 +257,7 @@ static void fd_free_device(struct se_device *dev) filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } - - kfree(fd_dev); + call_rcu(&dev->rcu_head, fd_dev_call_rcu); } static int fd_do_rw(struct se_cmd *cmd, struct file *fd, diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 6d4738252564..ae8ad2da6632 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -191,6 +191,14 @@ out: return ret; } +static void iblock_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct iblock_dev *ib_dev = IBLOCK_DEV(dev); + + kfree(ib_dev); +} + static void iblock_free_device(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); @@ -200,7 +208,7 @@ static void iblock_free_device(struct se_device *dev) if (ib_dev->ibd_bio_set != NULL) bioset_free(ib_dev->ibd_bio_set); - kfree(ib_dev); + call_rcu(&dev->rcu_head, iblock_dev_call_rcu); } static unsigned long long iblock_emulate_read_cap_with_block_size( diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index afb87a8d5668..c673980ded04 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -579,6 +579,14 @@ static int pscsi_configure_device(struct se_device *dev) return -ENODEV; } +static void pscsi_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); + + kfree(pdv); +} + static void pscsi_free_device(struct se_device *dev) { struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); @@ -610,8 +618,7 @@ static void pscsi_free_device(struct se_device *dev) pdv->pdv_sd = NULL; } - - kfree(pdv); + call_rcu(&dev->rcu_head, pscsi_dev_call_rcu); } static void pscsi_transport_complete(struct se_cmd *cmd, struct scatterlist *sg, diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 55dd73e7f213..e98432705f39 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -350,12 +350,20 @@ fail: return ret; } +static void rd_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct rd_dev *rd_dev = RD_DEV(dev); + + kfree(rd_dev); +} + static void rd_free_device(struct se_device *dev) { struct rd_dev *rd_dev = RD_DEV(dev); rd_release_device_space(rd_dev); - kfree(rd_dev); + call_rcu(&dev->rcu_head, rd_dev_call_rcu); } static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 34d8292a4432..a2b377e06cfa 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -692,7 +692,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } - if (dev == tpg->tpg_virt_lun0->lun_se_dev) + if (dev == rcu_access_pointer(tpg->tpg_virt_lun0->lun_se_dev)) buf[0] = 0x3f; /* Not connected */ else buf[0] = dev->transport->get_device_type(dev); diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index 8e080efb0188..79c785242375 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c @@ -545,11 +545,11 @@ static ssize_t target_stat_scsi_port_show_attr_inst( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(inst); @@ -561,11 +561,11 @@ static ssize_t target_stat_scsi_port_show_attr_dev( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(dev); @@ -577,11 +577,11 @@ static ssize_t target_stat_scsi_port_show_attr_indx( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(indx); @@ -593,11 +593,11 @@ static ssize_t target_stat_scsi_port_show_attr_role( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(role); @@ -609,13 +609,13 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { /* FIXME: scsiPortBusyStatuses */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); @@ -666,11 +666,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); @@ -682,11 +682,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); @@ -698,11 +698,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_rtpi); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); @@ -715,13 +715,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", tpg->se_tpg_tfo->get_fabric_name(), lun->lun_rtpi); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); @@ -734,13 +734,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", tpg->se_tpg_tfo->tpg_get_wwn(tpg), "+t+", tpg->se_tpg_tfo->tpg_get_tag(tpg)); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); @@ -752,11 +752,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_stats.cmd_pdus); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%lu\n", + atomic_long_read(&lun->lun_stats.cmd_pdus)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); @@ -768,12 +769,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(lun->lun_stats.rx_data_octets >> 20)); - spin_unlock(&lun->lun_sep_lock); + (u32)(atomic_long_read(&lun->lun_stats.rx_data_octets) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); @@ -785,12 +786,12 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", - (u32)(lun->lun_stats.tx_data_octets >> 20)); - spin_unlock(&lun->lun_sep_lock); + (u32)(atomic_long_read(&lun->lun_stats.tx_data_octets) >> 20)); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); @@ -802,13 +803,13 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { /* FIXME: scsiTgtPortHsInCommands */ ret = snprintf(page, PAGE_SIZE, "%u\n", 0); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); @@ -865,11 +866,11 @@ static ssize_t target_stat_scsi_transport_show_attr_inst( struct se_device *dev; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) - ret = snprintf(page, PAGE_SIZE, "%u\n", dev->se_hba->hba_index); - spin_unlock(&lun->lun_sep_lock); + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->hba_index); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); @@ -882,14 +883,14 @@ static ssize_t target_stat_scsi_transport_show_attr_device( struct se_portal_group *tpg = lun->lun_tpg; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { /* scsiTransportType */ ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", tpg->se_tpg_tfo->get_fabric_name()); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); @@ -902,12 +903,12 @@ static ssize_t target_stat_scsi_transport_show_attr_indx( struct se_portal_group *tpg = lun->lun_tpg; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) ret = snprintf(page, PAGE_SIZE, "%u\n", tpg->se_tpg_tfo->tpg_get_inst_index(tpg)); - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); @@ -916,13 +917,13 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( struct se_port_stat_grps *pgrps, char *page) { struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); - struct se_device *dev = lun->lun_se_dev; + struct se_device *dev; struct se_portal_group *tpg = lun->lun_tpg; struct t10_wwn *wwn; ssize_t ret = -ENODEV; - spin_lock(&lun->lun_sep_lock); - dev = lun->lun_se_dev; + rcu_read_lock(); + dev = rcu_dereference(lun->lun_se_dev); if (dev) { wwn = &dev->t10_wwn; /* scsiTransportDevName */ @@ -931,7 +932,7 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name( (strlen(wwn->unit_serial)) ? wwn->unit_serial : wwn->vendor); } - spin_unlock(&lun->lun_sep_lock); + rcu_read_unlock(); return ret; } DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 499b1399035a..5b30940ccaf2 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -102,7 +102,8 @@ void core_tpg_add_node_to_devs( if (lun_orig && lun != lun_orig) continue; - dev = lun->lun_se_dev; + dev = rcu_dereference_check(lun->lun_se_dev, + lockdep_is_held(&tpg->tpg_lun_mutex)); /* * By default in LIO-Target $FABRIC_MOD, * demo_mode_write_protect is ON, or READ_ONLY; @@ -598,7 +599,6 @@ struct se_lun *core_tpg_alloc_lun( lun->unpacked_lun = unpacked_lun; lun->lun_link_magic = SE_LUN_LINK_MAGIC; atomic_set(&lun->lun_acl_count, 0); - spin_lock_init(&lun->lun_sep_lock); init_completion(&lun->lun_ref_comp); INIT_LIST_HEAD(&lun->lun_deve_list); INIT_LIST_HEAD(&lun->lun_dev_link); @@ -636,12 +636,8 @@ int core_tpg_add_lun( mutex_lock(&tpg->tpg_lun_mutex); - spin_lock(&lun->lun_sep_lock); - lun->lun_index = dev->dev_index; - lun->lun_se_dev = dev; - spin_unlock(&lun->lun_sep_lock); - spin_lock(&dev->se_port_lock); + lun->lun_index = dev->dev_index; rcu_assign_pointer(lun->lun_se_dev, dev); dev->export_count++; list_add_tail(&lun->lun_dev_link, &dev->dev_sep_list); @@ -664,7 +660,11 @@ void core_tpg_remove_lun( struct se_portal_group *tpg, struct se_lun *lun) { - struct se_device *dev = lun->lun_se_dev; + /* + * rcu_dereference_raw protected by se_lun->lun_group symlink + * reference to se_device->dev_group. + */ + struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); core_clear_lun_from_tpg(lun, tpg); transport_clear_lun_ref(lun); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ef6fdd8a47c4..d8a59122fe3b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1261,10 +1261,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) return ret; cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; - - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.cmd_pdus++; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_inc(&cmd->se_lun->lun_stats.cmd_pdus); return 0; } EXPORT_SYMBOL(target_setup_cmd_from_cdb); @@ -2060,9 +2057,8 @@ static void target_complete_ok_work(struct work_struct *work) queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_add(cmd->data_length, + &cmd->se_lun->lun_stats.tx_data_octets); /* * Perform READ_STRIP of PI using software emulation when * backend had PI enabled, if the transport will not be @@ -2085,16 +2081,14 @@ queue_rsp: goto queue_full; break; case DMA_TO_DEVICE: - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.rx_data_octets += cmd->data_length; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_add(cmd->data_length, + &cmd->se_lun->lun_stats.rx_data_octets); /* * Check if we need to send READ payload for BIDI-COMMAND */ if (cmd->se_cmd_flags & SCF_BIDI) { - spin_lock(&cmd->se_lun->lun_sep_lock); - cmd->se_lun->lun_stats.tx_data_octets += cmd->data_length; - spin_unlock(&cmd->se_lun->lun_sep_lock); + atomic_long_add(cmd->data_length, + &cmd->se_lun->lun_stats.tx_data_octets); ret = cmd->se_tfo->queue_data_in(cmd); if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index aebaad55e23f..949e6165ef8a 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -950,6 +950,14 @@ static int tcmu_check_pending_cmd(int id, void *p, void *data) return -EINVAL; } +static void tcmu_dev_call_rcu(struct rcu_head *p) +{ + struct se_device *dev = container_of(p, struct se_device, rcu_head); + struct tcmu_dev *udev = TCMU_DEV(dev); + + kfree(udev); +} + static void tcmu_free_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); @@ -975,8 +983,7 @@ static void tcmu_free_device(struct se_device *dev) kfree(udev->uio_info.name); kfree(udev->name); } - - kfree(udev); + call_rcu(&dev->rcu_head, tcmu_dev_call_rcu); } enum { diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 1927dd5947a7..b82a989a4d3b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -690,9 +690,9 @@ struct se_port_stat_grps { }; struct scsi_port_stats { - u32 cmd_pdus; - u64 tx_data_octets; - u64 rx_data_octets; + atomic_long_t cmd_pdus; + atomic_long_t tx_data_octets; + atomic_long_t rx_data_octets; }; struct se_lun { @@ -705,7 +705,6 @@ struct se_lun { u32 unpacked_lun; u32 lun_index; atomic_t lun_acl_count; - spinlock_t lun_sep_lock; struct se_device __rcu *lun_se_dev; struct list_head lun_deve_list; @@ -818,6 +817,9 @@ struct se_device { struct se_lun xcopy_lun; /* Protection Information */ int prot_length; + /* For se_lun->lun_se_dev RCU read-side critical access */ + u32 hba_index; + struct rcu_head rcu_head; }; struct se_hba { -- cgit v1.2.3 From 9e37d042cfcb003b885bb4c531cd6f07f62647d1 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 20 May 2015 21:21:08 -0700 Subject: target: Drop se_lun->lun_active for existing percpu lun_ref With se_port_t and t10_alua_tg_pt_gp_member being absored into se_lun, there is no need for an extra atomic_t based reference count for PR ALL_TG_PT=1 and ALUA access state transition. Go ahead and use the existing percpu se_lun->lun_ref instead, and convert the two special cases to percpu_ref_tryget_live() to avoid se_lun if transport_clear_lun_ref() has already been invoked to shutdown the se_lun. Cc: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_alua.c | 5 +++-- drivers/target/target_core_pr.c | 9 +++++---- drivers/target/target_core_tpg.c | 10 ++++++---- include/target/target_core_base.h | 1 - 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 0a0087311cfb..02d8e1a8a6a5 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -969,7 +969,8 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) * every I_T nexus other than the I_T nexus on which the SET * TARGET PORT GROUPS command */ - atomic_inc_mb(&lun->lun_active); + if (!percpu_ref_tryget_live(&lun->lun_ref)) + continue; spin_unlock(&tg_pt_gp->tg_pt_gp_lock); spin_lock_bh(&lun->lun_deve_lock); @@ -998,7 +999,7 @@ static void core_alua_do_transition_tg_pt_work(struct work_struct *work) spin_unlock_bh(&lun->lun_deve_lock); spin_lock(&tg_pt_gp->tg_pt_gp_lock); - atomic_dec_mb(&lun->lun_active); + percpu_ref_put(&lun->lun_ref); } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 60624bb6c598..94935eaa7fa7 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -704,7 +704,8 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( */ spin_lock(&dev->se_port_lock); list_for_each_entry_safe(lun_tmp, next, &dev->dev_sep_list, lun_dev_link) { - atomic_inc_mb(&lun_tmp->lun_active); + if (!percpu_ref_tryget_live(&lun_tmp->lun_ref)) + continue; spin_unlock(&dev->se_port_lock); spin_lock_bh(&lun_tmp->lun_deve_lock); @@ -751,7 +752,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( if (ret < 0) { pr_err("core_scsi3_lunacl_depend" "_item() failed\n"); - atomic_dec_mb(&lun->lun_active); + percpu_ref_put(&lun_tmp->lun_ref); kref_put(&deve_tmp->pr_kref, target_pr_kref_release); goto out; } @@ -770,7 +771,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( deve_tmp->mapped_lun, NULL, sa_res_key, all_tg_pt, aptpl); if (!pr_reg_atp) { - atomic_dec_mb(&lun_tmp->lun_active); + percpu_ref_put(&lun_tmp->lun_ref); core_scsi3_lunacl_undepend_item(deve_tmp); goto out; } @@ -782,7 +783,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( spin_unlock_bh(&lun_tmp->lun_deve_lock); spin_lock(&dev->se_port_lock); - atomic_dec_mb(&lun_tmp->lun_active); + percpu_ref_put(&lun_tmp->lun_ref); } spin_unlock(&dev->se_port_lock); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 5b30940ccaf2..b9fcf2c4898e 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -607,7 +607,6 @@ struct se_lun *core_tpg_alloc_lun( mutex_init(&lun->lun_tg_pt_md_mutex); INIT_LIST_HEAD(&lun->lun_tg_pt_gp_link); spin_lock_init(&lun->lun_tg_pt_gp_lock); - atomic_set(&lun->lun_active, 0); lun->lun_tpg = tpg; return lun; @@ -667,13 +666,16 @@ void core_tpg_remove_lun( struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); core_clear_lun_from_tpg(lun, tpg); + /* + * Wait for any active I/O references to percpu se_lun->lun_ref to + * be released. Also, se_lun->lun_ref is now used by PR and ALUA + * logic when referencing a remote target port during ALL_TGT_PT=1 + * and generating UNIT_ATTENTIONs for ALUA access state transition. + */ transport_clear_lun_ref(lun); mutex_lock(&tpg->tpg_lun_mutex); if (lun->lun_se_dev) { - while (atomic_read(&lun->lun_active)) - cpu_relax(); - target_detach_tg_pt_gp(lun); spin_lock(&dev->se_port_lock); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index b82a989a4d3b..eefc2b0cfaa3 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -721,7 +721,6 @@ struct se_lun { struct t10_alua_tg_pt_gp *lun_tg_pt_gp; spinlock_t lun_tg_pt_gp_lock; - atomic_t lun_active; struct se_portal_group *lun_tpg; struct scsi_port_stats lun_stats; struct config_group lun_group; -- cgit v1.2.3 From cf561f0d2eb74574ad9985a2feab134267a9d298 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:24:27 +0200 Subject: virtio: introduce virtio_is_little_endian() helper Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck Reviewed-by: David Gibson --- include/linux/virtio_config.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 1e306f727edc..170947eb11b5 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -205,35 +205,40 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) return 0; } +static inline bool virtio_is_little_endian(struct virtio_device *vdev) +{ + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); +} + /* Memory accessors */ static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) { - return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) { - return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); } static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) { - return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) { - return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); } static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) { - return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); } static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) { - return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val); + return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); } /* Config space accessors. */ -- cgit v1.2.3 From 5da7b160b36a42f161980c5e20d3960d6d076fb8 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:24:58 +0200 Subject: vringh: introduce vringh_is_little_endian() helper Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Acked-by: Cornelia Huck Reviewed-by: David Gibson --- include/linux/vringh.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/vringh.h b/include/linux/vringh.h index a3fa537e717a..3ed62efc2bc5 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -226,33 +226,38 @@ static inline void vringh_notify(struct vringh *vrh) vrh->notify(vrh); } +static inline bool vringh_is_little_endian(const struct vringh *vrh) +{ + return vrh->little_endian; +} + static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) { - return __virtio16_to_cpu(vrh->little_endian, val); + return __virtio16_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio16 cpu_to_vringh16(const struct vringh *vrh, u16 val) { - return __cpu_to_virtio16(vrh->little_endian, val); + return __cpu_to_virtio16(vringh_is_little_endian(vrh), val); } static inline u32 vringh32_to_cpu(const struct vringh *vrh, __virtio32 val) { - return __virtio32_to_cpu(vrh->little_endian, val); + return __virtio32_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio32 cpu_to_vringh32(const struct vringh *vrh, u32 val) { - return __cpu_to_virtio32(vrh->little_endian, val); + return __cpu_to_virtio32(vringh_is_little_endian(vrh), val); } static inline u64 vringh64_to_cpu(const struct vringh *vrh, __virtio64 val) { - return __virtio64_to_cpu(vrh->little_endian, val); + return __virtio64_to_cpu(vringh_is_little_endian(vrh), val); } static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val) { - return __cpu_to_virtio64(vrh->little_endian, val); + return __cpu_to_virtio64(vringh_is_little_endian(vrh), val); } #endif /* _LINUX_VRINGH_H */ -- cgit v1.2.3 From 7d82410950aa74adccf035c332e409af2bb93e92 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:26:24 +0200 Subject: virtio: add explicit big-endian support to memory accessors The current memory accessors logic is: - little endian if little_endian - native endian (i.e. no byteswap) if !little_endian If we want to fully support cross-endian vhost, we also need to be able to convert to big endian. Instead of changing the little_endian argument to some 3-value enum, this patch changes the logic to: - little endian if little_endian - big endian if !little_endian The native endian case is handled by all users with a trivial helper. This patch doesn't change any functionality, nor it does add overhead. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/net/macvtap.c | 3 ++- drivers/net/tun.c | 3 ++- drivers/vhost/vhost.h | 3 ++- include/linux/virtio_byteorder.h | 24 ++++++++++++++---------- include/linux/virtio_config.h | 3 ++- include/linux/vringh.h | 3 ++- 6 files changed, 24 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 4fdb88102082..072ccbaf7c45 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -51,7 +51,8 @@ struct macvtap_queue { static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { - return q->flags & MACVTAP_VNET_LE; + return q->flags & MACVTAP_VNET_LE || + virtio_legacy_is_little_endian(); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 301e87c89a9f..b210139bef8f 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -208,7 +208,8 @@ struct tun_struct { static inline bool tun_is_little_endian(struct tun_struct *tun) { - return tun->flags & TUN_VNET_LE; + return tun->flags & TUN_VNET_LE || + virtio_legacy_is_little_endian(); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6a499603d856..a4fa33a79bf2 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,7 +175,8 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1); + return vhost_has_feature(vq, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h index 51865d05b267..ce63a2c3a612 100644 --- a/include/linux/virtio_byteorder.h +++ b/include/linux/virtio_byteorder.h @@ -3,17 +3,21 @@ #include #include -/* - * Low-level memory accessors for handling virtio in modern little endian and in - * compatibility native endian format. - */ +static inline bool virtio_legacy_is_little_endian(void) +{ +#ifdef __LITTLE_ENDIAN + return true; +#else + return false; +#endif +} static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) { if (little_endian) return le16_to_cpu((__force __le16)val); else - return (__force u16)val; + return be16_to_cpu((__force __be16)val); } static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) @@ -21,7 +25,7 @@ static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) if (little_endian) return (__force __virtio16)cpu_to_le16(val); else - return (__force __virtio16)val; + return (__force __virtio16)cpu_to_be16(val); } static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) @@ -29,7 +33,7 @@ static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) if (little_endian) return le32_to_cpu((__force __le32)val); else - return (__force u32)val; + return be32_to_cpu((__force __be32)val); } static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) @@ -37,7 +41,7 @@ static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) if (little_endian) return (__force __virtio32)cpu_to_le32(val); else - return (__force __virtio32)val; + return (__force __virtio32)cpu_to_be32(val); } static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) @@ -45,7 +49,7 @@ static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) if (little_endian) return le64_to_cpu((__force __le64)val); else - return (__force u64)val; + return be64_to_cpu((__force __be64)val); } static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) @@ -53,7 +57,7 @@ static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) if (little_endian) return (__force __virtio64)cpu_to_le64(val); else - return (__force __virtio64)val; + return (__force __virtio64)cpu_to_be64(val); } #endif /* _LINUX_VIRTIO_BYTEORDER */ diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 170947eb11b5..e5ce8ab0b8b0 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -207,7 +207,8 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu) static inline bool virtio_is_little_endian(struct virtio_device *vdev) { - return virtio_has_feature(vdev, VIRTIO_F_VERSION_1); + return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) || + virtio_legacy_is_little_endian(); } /* Memory accessors */ diff --git a/include/linux/vringh.h b/include/linux/vringh.h index 3ed62efc2bc5..bc6c28d04263 100644 --- a/include/linux/vringh.h +++ b/include/linux/vringh.h @@ -228,7 +228,8 @@ static inline void vringh_notify(struct vringh *vrh) static inline bool vringh_is_little_endian(const struct vringh *vrh) { - return vrh->little_endian; + return vrh->little_endian || + virtio_legacy_is_little_endian(); } static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) -- cgit v1.2.3 From 2751c9882b947292fcfb084c4f604e01724af804 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:27:24 +0200 Subject: vhost: cross-endian support for legacy devices This patch brings cross-endian support to vhost when used to implement legacy virtio devices. Since it is a relatively rare situation, the feature availability is controlled by a kernel config option (not set by default). The vq->is_le boolean field is added to cache the endianness to be used for ring accesses. It defaults to native endian, as expected by legacy virtio devices. When the ring gets active, we force little endian if the device is modern. When the ring is deactivated, we revert to the native endian default. If cross-endian was compiled in, a vq->user_be boolean field is added so that userspace may request a specific endianness. This field is used to override the default when activating the ring of a legacy device. It has no effect on modern devices. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Reviewed-by: Cornelia Huck Reviewed-by: David Gibson --- drivers/vhost/Kconfig | 15 ++++++++ drivers/vhost/vhost.c | 85 +++++++++++++++++++++++++++++++++++++++++++++- drivers/vhost/vhost.h | 11 ++++-- include/uapi/linux/vhost.h | 14 ++++++++ 4 files changed, 122 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 017a1e8a8f6f..533eaf04f12f 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -32,3 +32,18 @@ config VHOST ---help--- This option is selected by any driver which needs to access the core of vhost. + +config VHOST_CROSS_ENDIAN_LEGACY + bool "Cross-endian support for vhost" + default n + ---help--- + This option allows vhost to support guests with a different byte + ordering from host while using legacy virtio. + + Userspace programs can control the feature using the + VHOST_SET_VRING_ENDIAN and VHOST_GET_VRING_ENDIAN ioctls. + + This is only useful on a few platforms (ppc64 and arm64). Since it + adds some overhead, it is disabled by default. + + If unsure, say "N". diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ee28266fd07..9e8e004bb1c3 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -36,6 +36,77 @@ enum { #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num]) #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ + vq->user_be = !virtio_legacy_is_little_endian(); +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + struct vhost_vring_state s; + + if (vq->private_data) + return -EBUSY; + + if (copy_from_user(&s, argp, sizeof(s))) + return -EFAULT; + + if (s.num != VHOST_VRING_LITTLE_ENDIAN && + s.num != VHOST_VRING_BIG_ENDIAN) + return -EINVAL; + + vq->user_be = s.num; + + return 0; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + struct vhost_vring_state s = { + .index = idx, + .num = vq->user_be + }; + + if (copy_to_user(argp, &s, sizeof(s))) + return -EFAULT; + + return 0; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + /* Note for legacy virtio: user_be is initialized at reset time + * according to the host endianness. If userspace does not set an + * explicit endianness, the default behavior is native endian, as + * expected by legacy virtio. + */ + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; +} +#else +static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +{ +} + +static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, + int __user *argp) +{ + return -ENOIOCTLCMD; +} + +static void vhost_init_is_le(struct vhost_virtqueue *vq) +{ + if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) + vq->is_le = true; +} +#endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -199,6 +270,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; + vq->is_le = virtio_legacy_is_little_endian(); + vhost_vq_reset_user_be(vq); } static int vhost_worker(void *data) @@ -806,6 +879,12 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) } else filep = eventfp; break; + case VHOST_SET_VRING_ENDIAN: + r = vhost_set_vring_endian(vq, argp); + break; + case VHOST_GET_VRING_ENDIAN: + r = vhost_get_vring_endian(vq, idx, argp); + break; default: r = -ENOIOCTLCMD; } @@ -1044,8 +1123,12 @@ int vhost_init_used(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; - if (!vq->private_data) + if (!vq->private_data) { + vq->is_le = virtio_legacy_is_little_endian(); return 0; + } + + vhost_init_is_le(vq); r = vhost_update_used_flags(vq); if (r) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index a4fa33a79bf2..ce6f6da4b09f 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -106,6 +106,14 @@ struct vhost_virtqueue { /* Log write descriptors */ void __user *log_base; struct vhost_log *log; + + /* Ring endianness. Defaults to legacy native endianness. + * Set to true when starting a modern virtio device. */ + bool is_le; +#ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY + /* Ring endianness requested by userspace for cross-endian support. */ + bool user_be; +#endif }; struct vhost_dev { @@ -175,8 +183,7 @@ static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit) static inline bool vhost_is_little_endian(struct vhost_virtqueue *vq) { - return vhost_has_feature(vq, VIRTIO_F_VERSION_1) || - virtio_legacy_is_little_endian(); + return vq->is_le; } /* Memory accessors */ diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index bb6a5b4cb3c5..ab3731917bac 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -103,6 +103,20 @@ struct vhost_memory { /* Get accessor: reads index, writes value in num */ #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state) +/* Set the vring byte order in num. Valid values are VHOST_VRING_LITTLE_ENDIAN + * or VHOST_VRING_BIG_ENDIAN (other values return -EINVAL). + * The byte order cannot be changed while the device is active: trying to do so + * returns -EBUSY. + * This is a legacy only API that is simply ignored when VIRTIO_F_VERSION_1 is + * set. + * Not all kernel configurations support this ioctl, but all configurations that + * support SET also support GET. + */ +#define VHOST_VRING_LITTLE_ENDIAN 0 +#define VHOST_VRING_BIG_ENDIAN 1 +#define VHOST_SET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x13, struct vhost_vring_state) +#define VHOST_GET_VRING_ENDIAN _IOW(VHOST_VIRTIO, 0x14, struct vhost_vring_state) + /* The following ioctls use eventfd file descriptors to signal and poll * for events. */ -- cgit v1.2.3 From 8b8e658b16336f0f50aba733f51db636ef121f50 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 24 Apr 2015 14:50:36 +0200 Subject: macvtap/tun: cross-endian support for little-endian hosts The VNET_LE flag was introduced to fix accesses to virtio 1.0 headers that are always little-endian. It can also be used to handle the special case of a legacy little-endian device implemented by a big-endian host. Let's add a flag and ioctls for big-endian devices as well. If both flags are set, little-endian wins. Since this is isn't a common usecase, the feature is controlled by a kernel config option (not set by default). Both macvtap and tun are covered by this patch since they share the same API with userland. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin Reviewed-by: David Gibson --- drivers/net/Kconfig | 14 +++++++++++ drivers/net/macvtap.c | 57 ++++++++++++++++++++++++++++++++++++++++++- drivers/net/tun.c | 59 ++++++++++++++++++++++++++++++++++++++++++++- include/uapi/linux/if_tun.h | 6 +++++ 4 files changed, 134 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d6025a90..71ac0ece2d75 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -244,6 +244,20 @@ config TUN If you don't know what to use this for, you don't need it. +config TUN_VNET_CROSS_LE + bool "Support for cross-endian vnet headers on little-endian kernels" + default n + ---help--- + This option allows TUN/TAP and MACVTAP device drivers in a + little-endian kernel to parse vnet headers that come from a + big-endian legacy virtio device. + + Userspace programs can control the feature using the TUNSETVNETBE + and TUNGETVNETBE ioctls. + + Unless you have a little-endian system hosting a big-endian virtual + machine with a legacy virtio NIC, you should say N. + config VETH tristate "Virtual ethernet pair device" ---help--- diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 072ccbaf7c45..928f3f4db629 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -48,11 +48,60 @@ struct macvtap_queue { #define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE) #define MACVTAP_VNET_LE 0x80000000 +#define MACVTAP_VNET_BE 0x40000000 + +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return q->flags & MACVTAP_VNET_BE ? false : + virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s = !!(q->flags & MACVTAP_VNET_BE); + + if (put_user(s, sp)) + return -EFAULT; + + return 0; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *sp) +{ + int s; + + if (get_user(s, sp)) + return -EFAULT; + + if (s) + q->flags |= MACVTAP_VNET_BE; + else + q->flags &= ~MACVTAP_VNET_BE; + + return 0; +} +#else +static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q) +{ + return virtio_legacy_is_little_endian(); +} + +static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} + +static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *argp) +{ + return -EINVAL; +} +#endif /* CONFIG_TUN_VNET_CROSS_LE */ static inline bool macvtap_is_little_endian(struct macvtap_queue *q) { return q->flags & MACVTAP_VNET_LE || - virtio_legacy_is_little_endian(); + macvtap_legacy_is_little_endian(q); } static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val) @@ -1096,6 +1145,12 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, q->flags &= ~MACVTAP_VNET_LE; return 0; + case TUNGETVNETBE: + return macvtap_get_vnet_be(q, sp); + + case TUNSETVNETBE: + return macvtap_set_vnet_be(q, sp); + case TUNSETOFFLOAD: /* let the user check for future flags */ if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | diff --git a/drivers/net/tun.c b/drivers/net/tun.c index b210139bef8f..cb376b2d548a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -111,6 +111,7 @@ do { \ #define TUN_FASYNC IFF_ATTACH_QUEUE /* High bits in flags field are unused. */ #define TUN_VNET_LE 0x80000000 +#define TUN_VNET_BE 0x40000000 #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \ IFF_MULTI_QUEUE) @@ -206,10 +207,58 @@ struct tun_struct { u32 flow_count; }; +#ifdef CONFIG_TUN_VNET_CROSS_LE +static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) +{ + return tun->flags & TUN_VNET_BE ? false : + virtio_legacy_is_little_endian(); +} + +static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) +{ + int be = !!(tun->flags & TUN_VNET_BE); + + if (put_user(be, argp)) + return -EFAULT; + + return 0; +} + +static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) +{ + int be; + + if (get_user(be, argp)) + return -EFAULT; + + if (be) + tun->flags |= TUN_VNET_BE; + else + tun->flags &= ~TUN_VNET_BE; + + return 0; +} +#else +static inline bool tun_legacy_is_little_endian(struct tun_struct *tun) +{ + return virtio_legacy_is_little_endian(); +} + +static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp) +{ + return -EINVAL; +} + +static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp) +{ + return -EINVAL; +} +#endif /* CONFIG_TUN_VNET_CROSS_LE */ + static inline bool tun_is_little_endian(struct tun_struct *tun) { return tun->flags & TUN_VNET_LE || - virtio_legacy_is_little_endian(); + tun_legacy_is_little_endian(tun); } static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val) @@ -2062,6 +2111,14 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, tun->flags &= ~TUN_VNET_LE; break; + case TUNGETVNETBE: + ret = tun_get_vnet_be(tun, argp); + break; + + case TUNSETVNETBE: + ret = tun_set_vnet_be(tun, argp); + break; + case TUNATTACHFILTER: /* Can be set only for TAPs */ ret = -EINVAL; diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index 50ae24335444..3cb5e1d85ddd 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h @@ -50,6 +50,12 @@ #define TUNGETFILTER _IOR('T', 219, struct sock_fprog) #define TUNSETVNETLE _IOW('T', 220, int) #define TUNGETVNETLE _IOR('T', 221, int) +/* The TUNSETVNETBE and TUNGETVNETBE ioctls are for cross-endian support on + * little-endian hosts. Not all kernel configurations support them, but all + * configurations that support SET also support GET. + */ +#define TUNSETVNETBE _IOW('T', 222, int) +#define TUNGETVNETBE _IOR('T', 223, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 -- cgit v1.2.3 From 632dda833e28fe43049a01b4bc53e409176e7843 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 11 May 2015 14:04:50 -0400 Subject: SUNRPC: Clean up bc_send() Clean up: Merge bc_send() into bc_svc_process(). Note: even thought this touches svc.c, it is a client-side change. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/bc_xprt.h | 1 - net/sunrpc/Makefile | 2 +- net/sunrpc/bc_svc.c | 63 ------------------------------------------ net/sunrpc/svc.c | 33 ++++++++++++++++------ 4 files changed, 26 insertions(+), 73 deletions(-) delete mode 100644 net/sunrpc/bc_svc.c (limited to 'include') diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index 2ca67b55e0fe..8df43c9f11dc 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h @@ -37,7 +37,6 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied); void xprt_free_bc_request(struct rpc_rqst *req); int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs); -int bc_send(struct rpc_rqst *req); /* * Determine if a shared backchannel is in use diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile index 15e6f6c23c5d..1b8e68d0e690 100644 --- a/net/sunrpc/Makefile +++ b/net/sunrpc/Makefile @@ -15,6 +15,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ sunrpc_syms.o cache.o rpc_pipe.o \ svc_xprt.o sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o -sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o bc_svc.o +sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o sunrpc-$(CONFIG_PROC_FS) += stats.o sunrpc-$(CONFIG_SYSCTL) += sysctl.o diff --git a/net/sunrpc/bc_svc.c b/net/sunrpc/bc_svc.c deleted file mode 100644 index 15c7a8a1c24f..000000000000 --- a/net/sunrpc/bc_svc.c +++ /dev/null @@ -1,63 +0,0 @@ -/****************************************************************************** - -(c) 2007 Network Appliance, Inc. All Rights Reserved. -(c) 2009 NetApp. All Rights Reserved. - -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -http://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -******************************************************************************/ - -/* - * The NFSv4.1 callback service helper routines. - * They implement the transport level processing required to send the - * reply over an existing open connection previously established by the client. - */ - -#include - -#include -#include -#include - -#define RPCDBG_FACILITY RPCDBG_SVCDSP - -/* Empty callback ops */ -static const struct rpc_call_ops nfs41_callback_ops = { -}; - - -/* - * Send the callback reply - */ -int bc_send(struct rpc_rqst *req) -{ - struct rpc_task *task; - int ret; - - dprintk("RPC: bc_send req= %p\n", req); - task = rpc_run_bc_task(req, &nfs41_callback_ops); - if (IS_ERR(task)) - ret = PTR_ERR(task); - else { - WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); - ret = task->tk_status; - rpc_put_task(task); - } - dprintk("RPC: bc_send ret= %d\n", ret); - return ret; -} - diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 78974e4d9ad2..e144902d382e 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1350,6 +1350,11 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, { struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; + static const struct rpc_call_ops reply_ops = { }; + struct rpc_task *task; + int error; + + dprintk("svc: %s(%p)\n", __func__, req); /* Build the svc_rqst used by the common processing routine */ rqstp->rq_xprt = serv->sv_bc_xprt; @@ -1372,21 +1377,33 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, /* * Skip the next two words because they've already been - * processed in the trasport + * processed in the transport */ svc_getu32(argv); /* XID */ svc_getnl(argv); /* CALLDIR */ - /* Returns 1 for send, 0 for drop */ - if (svc_process_common(rqstp, argv, resv)) { - memcpy(&req->rq_snd_buf, &rqstp->rq_res, - sizeof(req->rq_snd_buf)); - return bc_send(req); - } else { - /* drop request */ + /* Parse and execute the bc call */ + if (!svc_process_common(rqstp, argv, resv)) { + /* Processing error: drop the request */ xprt_free_bc_request(req); return 0; } + + /* Finally, send the reply synchronously */ + memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); + task = rpc_run_bc_task(req, &reply_ops); + if (IS_ERR(task)) { + error = PTR_ERR(task); + goto out; + } + + WARN_ON_ONCE(atomic_read(&task->tk_count) != 1); + error = task->tk_status; + rpc_put_task(task); + +out: + dprintk("svc: %s(), error=%d\n", __func__, error); + return error; } EXPORT_SYMBOL_GPL(bc_svc_process); #endif /* CONFIG_SUNRPC_BACKCHANNEL */ -- cgit v1.2.3 From 0f41979164a52a1ca0f0a601f90000fc18e3a396 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 1 Jun 2015 22:59:08 -0400 Subject: SUNRPC: Remove unused argument 'tk_ops' in rpc_run_bc_task Signed-off-by: Trond Myklebust --- include/linux/sunrpc/sched.h | 3 +-- net/sunrpc/clnt.c | 6 ++---- net/sunrpc/svc.c | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 5f1e6bd4c316..2aa68976a482 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -205,8 +205,7 @@ struct rpc_wait_queue { */ struct rpc_task *rpc_new_task(const struct rpc_task_setup *); struct rpc_task *rpc_run_task(const struct rpc_task_setup *); -struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, - const struct rpc_call_ops *ops); +struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req); void rpc_put_task(struct rpc_task *); void rpc_put_task_async(struct rpc_task *); void rpc_exit_task(struct rpc_task *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index fa70f663eb92..f6717170480e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1031,15 +1031,13 @@ EXPORT_SYMBOL_GPL(rpc_call_async); * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run * rpc_execute against it * @req: RPC request - * @tk_ops: RPC call ops */ -struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, - const struct rpc_call_ops *tk_ops) +struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) { struct rpc_task *task; struct xdr_buf *xbufp = &req->rq_snd_buf; struct rpc_task_setup task_setup_data = { - .callback_ops = tk_ops, + .callback_ops = &rpc_default_ops, }; dprintk("RPC: rpc_run_bc_task req= %p\n", req); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index e144902d382e..51c8cad5e765 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1350,7 +1350,6 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, { struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; - static const struct rpc_call_ops reply_ops = { }; struct rpc_task *task; int error; @@ -1391,7 +1390,7 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, /* Finally, send the reply synchronously */ memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf)); - task = rpc_run_bc_task(req, &reply_ops); + task = rpc_run_bc_task(req); if (IS_ERR(task)) { error = PTR_ERR(task); goto out; -- cgit v1.2.3 From 0d2a970d0ae55086520e1e58e572a7acd519429c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 4 Jun 2015 15:37:10 -0400 Subject: SUNRPC: Fix a backchannel race We need to allow the server to send a new request immediately after we've replied to the previous one. Right now, there is a window between the send and the release of the old request in rpc_put_task(), where the server could send us a new backchannel RPC call, and we have no request to service it. Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 3 ++- net/sunrpc/backchannel_rqst.c | 37 ++++++++++++++++++++++++------------- net/sunrpc/svc.c | 6 +++++- 3 files changed, 31 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 8b93ef53df3c..bc9c39d6d30d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -212,7 +212,8 @@ struct rpc_xprt { #if defined(CONFIG_SUNRPC_BACKCHANNEL) struct svc_serv *bc_serv; /* The RPC service which will */ /* process the callback */ - unsigned int bc_alloc_count; /* Total number of preallocs */ + int bc_alloc_count; /* Total number of preallocs */ + atomic_t bc_free_slots; spinlock_t bc_pa_lock; /* Protects the preallocated * items */ struct list_head bc_pa_list; /* List of preallocated diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 1baa41099469..9825ff0f91d6 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -37,16 +37,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static inline int xprt_need_to_requeue(struct rpc_xprt *xprt) { - return xprt->bc_alloc_count > 0; + return xprt->bc_alloc_count < atomic_read(&xprt->bc_free_slots); } static inline void xprt_inc_alloc_count(struct rpc_xprt *xprt, unsigned int n) { + atomic_add(n, &xprt->bc_free_slots); xprt->bc_alloc_count += n; } static inline int xprt_dec_alloc_count(struct rpc_xprt *xprt, unsigned int n) { + atomic_sub(n, &xprt->bc_free_slots); return xprt->bc_alloc_count -= n; } @@ -232,9 +234,15 @@ static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid) struct rpc_rqst *req = NULL; dprintk("RPC: allocate a backchannel request\n"); - if (list_empty(&xprt->bc_pa_list)) + if (atomic_read(&xprt->bc_free_slots) <= 0) goto not_found; - + if (list_empty(&xprt->bc_pa_list)) { + req = xprt_alloc_bc_req(xprt, GFP_ATOMIC); + if (!req) + goto not_found; + /* Note: this 'free' request adds it to xprt->bc_pa_list */ + xprt_free_bc_request(req); + } req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst, rq_bc_pa_list); req->rq_reply_bytes_recvd = 0; @@ -260,11 +268,21 @@ void xprt_free_bc_request(struct rpc_rqst *req) req->rq_connect_cookie = xprt->connect_cookie - 1; smp_mb__before_atomic(); - WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state)); clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); smp_mb__after_atomic(); - if (!xprt_need_to_requeue(xprt)) { + /* + * Return it to the list of preallocations so that it + * may be reused by a new callback request. + */ + spin_lock_bh(&xprt->bc_pa_lock); + if (xprt_need_to_requeue(xprt)) { + list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list); + xprt->bc_alloc_count++; + req = NULL; + } + spin_unlock_bh(&xprt->bc_pa_lock); + if (req != NULL) { /* * The last remaining session was destroyed while this * entry was in use. Free the entry and don't attempt @@ -275,14 +293,6 @@ void xprt_free_bc_request(struct rpc_rqst *req) xprt_free_allocation(req); return; } - - /* - * Return it to the list of preallocations so that it - * may be reused by a new callback request. - */ - spin_lock_bh(&xprt->bc_pa_lock); - list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list); - spin_unlock_bh(&xprt->bc_pa_lock); } /* @@ -326,6 +336,7 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) spin_lock(&xprt->bc_pa_lock); list_del(&req->rq_bc_pa_list); + xprt->bc_alloc_count--; spin_unlock(&xprt->bc_pa_lock); req->rq_private_buf.len = copied; diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 51c8cad5e765..b47f02f60b9c 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1351,6 +1351,7 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; struct rpc_task *task; + int proc_error; int error; dprintk("svc: %s(%p)\n", __func__, req); @@ -1382,7 +1383,10 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, svc_getnl(argv); /* CALLDIR */ /* Parse and execute the bc call */ - if (!svc_process_common(rqstp, argv, resv)) { + proc_error = svc_process_common(rqstp, argv, resv); + + atomic_inc(&req->rq_xprt->bc_free_slots); + if (!proc_error) { /* Processing error: drop the request */ xprt_free_bc_request(req); return 0; -- cgit v1.2.3 From b1999477ed91c3c33891acfe0e18a4457e5c4915 Mon Sep 17 00:00:00 2001 From: Guo Zeng Date: Tue, 14 Apr 2015 11:55:55 +0000 Subject: ARM: prima2: move to use REGMAP APIs for rtciobrg all devices behind rtciobrg needs a special way to access. currently they are using a platform-specific API. this patch moves to REGMAP, then clients can use regmap APIs to read/write. for the moment, old APIs are still kept, once all clients move to regmap, old APIs will be dropped. this patch also does minor clean for comments, authors statement. Signed-off-by: Guo Zeng Signed-off-by: Barry Song --- arch/arm/mach-prima2/Kconfig | 1 + arch/arm/mach-prima2/rtciobrg.c | 48 +++++++++++++++++++++++++++++++++--- include/linux/rtc/sirfsoc_rtciobrg.h | 4 +++ 3 files changed, 50 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-prima2/Kconfig b/arch/arm/mach-prima2/Kconfig index e03d8b5c9ad0..9ab8932403e5 100644 --- a/arch/arm/mach-prima2/Kconfig +++ b/arch/arm/mach-prima2/Kconfig @@ -4,6 +4,7 @@ menuconfig ARCH_SIRF select ARCH_REQUIRE_GPIOLIB select GENERIC_IRQ_CHIP select NO_IOPORT_MAP + select REGMAP select PINCTRL select PINCTRL_SIRF help diff --git a/arch/arm/mach-prima2/rtciobrg.c b/arch/arm/mach-prima2/rtciobrg.c index 8f66d8f7ca75..d4852d24dc7d 100644 --- a/arch/arm/mach-prima2/rtciobrg.c +++ b/arch/arm/mach-prima2/rtciobrg.c @@ -1,5 +1,5 @@ /* - * RTC I/O Bridge interfaces for CSR SiRFprimaII + * RTC I/O Bridge interfaces for CSR SiRFprimaII/atlas7 * ARM access the registers of SYSRTC, GPSRTC and PWRC through this module * * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ u32 sirfsoc_rtc_iobrg_readl(u32 addr) { unsigned long flags, val; + /* TODO: add hwspinlock to sync with M3 */ spin_lock_irqsave(&rtciobrg_lock, flags); val = __sirfsoc_rtc_iobrg_readl(addr); @@ -90,6 +92,7 @@ void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr) { unsigned long flags; + /* TODO: add hwspinlock to sync with M3 */ spin_lock_irqsave(&rtciobrg_lock, flags); sirfsoc_rtc_iobrg_pre_writel(val, addr); @@ -102,6 +105,45 @@ void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr) } EXPORT_SYMBOL_GPL(sirfsoc_rtc_iobrg_writel); + +static int regmap_iobg_regwrite(void *context, unsigned int reg, + unsigned int val) +{ + sirfsoc_rtc_iobrg_writel(val, reg); + return 0; +} + +static int regmap_iobg_regread(void *context, unsigned int reg, + unsigned int *val) +{ + *val = (u32)sirfsoc_rtc_iobrg_readl(reg); + return 0; +} + +static struct regmap_bus regmap_iobg = { + .reg_write = regmap_iobg_regwrite, + .reg_read = regmap_iobg_regread, +}; + +/** + * devm_regmap_init_iobg(): Initialise managed register map + * + * @iobg: Device that will be interacted with + * @config: Configuration for register map + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a struct regmap. The regmap will be automatically freed by the + * device management code. + */ +struct regmap *devm_regmap_init_iobg(struct device *dev, + const struct regmap_config *config) +{ + const struct regmap_bus *bus = ®map_iobg; + + return devm_regmap_init(dev, bus, dev, config); +} +EXPORT_SYMBOL_GPL(devm_regmap_init_iobg); + static const struct of_device_id rtciobrg_ids[] = { { .compatible = "sirf,prima2-rtciobg" }, {} @@ -132,7 +174,7 @@ static int __init sirfsoc_rtciobrg_init(void) } postcore_initcall(sirfsoc_rtciobrg_init); -MODULE_AUTHOR("Zhiwu Song , " - "Barry Song "); +MODULE_AUTHOR("Zhiwu Song "); +MODULE_AUTHOR("Barry Song "); MODULE_DESCRIPTION("CSR SiRFprimaII rtc io bridge"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/rtc/sirfsoc_rtciobrg.h b/include/linux/rtc/sirfsoc_rtciobrg.h index 2c92e1c8e055..aefd997262e4 100644 --- a/include/linux/rtc/sirfsoc_rtciobrg.h +++ b/include/linux/rtc/sirfsoc_rtciobrg.h @@ -9,10 +9,14 @@ #ifndef _SIRFSOC_RTC_IOBRG_H_ #define _SIRFSOC_RTC_IOBRG_H_ +struct regmap_config; + extern void sirfsoc_rtc_iobrg_besyncing(void); extern u32 sirfsoc_rtc_iobrg_readl(u32 addr); extern void sirfsoc_rtc_iobrg_writel(u32 val, u32 addr); +struct regmap *devm_regmap_init_iobg(struct device *dev, + const struct regmap_config *config); #endif -- cgit v1.2.3 From 3c87ef6efb40f0e339d705c194b2224f854ec38e Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 3 Jun 2015 16:14:25 -0400 Subject: sunrpc: keep a count of swapfiles associated with the rpc_clnt Jerome reported seeing a warning pop when working with a swapfile on NFS. The nfs_swap_activate can end up calling sk_set_memalloc while holding the rcu_read_lock and that function can sleep. To fix that, we need to take a reference to the xprt while holding the rcu_read_lock, set the socket up for swapping and then drop that reference. But, xprt_put is not exported and having NFS deal with the underlying xprt is a bit of layering violation anyway. Fix this by adding a set of activate/deactivate functions that take a rpc_clnt pointer instead of an rpc_xprt, and have nfs_swap_activate and nfs_swap_deactivate call those. Also, add a per-rpc_clnt atomic counter to keep track of the number of active swapfiles associated with it. When the counter does a 0->1 transition, we enable swapping on the xprt, when we do a 1->0 transition we disable swapping on it. This also allows us to be a bit more selective with the RPC_TASK_SWAPPER flag. If non-swapper and swapper clnts are sharing a xprt, then we only need to flag the tasks from the swapper clnt with that flag. Acked-by: Mel Gorman Reported-by: Jerome Marchand Signed-off-by: Jeff Layton Reviewed-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 15 ++-------- include/linux/sunrpc/clnt.h | 1 + include/linux/sunrpc/sched.h | 16 +++++++++++ net/sunrpc/clnt.c | 67 ++++++++++++++++++++++++++++++++++++++------ net/sunrpc/xprtsock.c | 3 +- 5 files changed, 78 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 8b8d83a526ce..cc4fa1ed61fc 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -555,31 +555,22 @@ static int nfs_launder_page(struct page *page) return nfs_wb_page(inode, page); } -#ifdef CONFIG_NFS_SWAP static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file, sector_t *span) { - int ret; struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host); *span = sis->pages; - rcu_read_lock(); - ret = xs_swapper(rcu_dereference(clnt->cl_xprt), 1); - rcu_read_unlock(); - - return ret; + return rpc_clnt_swap_activate(clnt); } static void nfs_swap_deactivate(struct file *file) { struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host); - rcu_read_lock(); - xs_swapper(rcu_dereference(clnt->cl_xprt), 0); - rcu_read_unlock(); + rpc_clnt_swap_deactivate(clnt); } -#endif const struct address_space_operations nfs_file_aops = { .readpage = nfs_readpage, @@ -596,10 +587,8 @@ const struct address_space_operations nfs_file_aops = { .launder_page = nfs_launder_page, .is_dirty_writeback = nfs_check_dirty_writeback, .error_remove_page = generic_error_remove_page, -#ifdef CONFIG_NFS_SWAP .swap_activate = nfs_swap_activate, .swap_deactivate = nfs_swap_deactivate, -#endif }; /* diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 598ba80ec30c..131032f15cc1 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -56,6 +56,7 @@ struct rpc_clnt { struct rpc_rtt * cl_rtt; /* RTO estimator data */ const struct rpc_timeout *cl_timeout; /* Timeout strategy */ + atomic_t cl_swapper; /* swapfile count */ int cl_nodelen; /* nodename length */ char cl_nodename[UNX_MAXNODENAME+1]; struct rpc_pipe_dir_head cl_pipedir_objects; diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 2aa68976a482..d703f0ef37d8 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h @@ -268,4 +268,20 @@ static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, } #endif +#if IS_ENABLED(CONFIG_SUNRPC_SWAP) +int rpc_clnt_swap_activate(struct rpc_clnt *clnt); +void rpc_clnt_swap_deactivate(struct rpc_clnt *clnt); +#else +static inline int +rpc_clnt_swap_activate(struct rpc_clnt *clnt) +{ + return -EINVAL; +} + +static inline void +rpc_clnt_swap_deactivate(struct rpc_clnt *clnt) +{ +} +#endif /* CONFIG_SUNRPC_SWAP */ + #endif /* _LINUX_SUNRPC_SCHED_H_ */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f6717170480e..0ba65156a62b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -891,15 +891,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) task->tk_flags |= RPC_TASK_SOFT; if (clnt->cl_noretranstimeo) task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; - if (sk_memalloc_socks()) { - struct rpc_xprt *xprt; - - rcu_read_lock(); - xprt = rcu_dereference(clnt->cl_xprt); - if (xprt->swapper) - task->tk_flags |= RPC_TASK_SWAPPER; - rcu_read_unlock(); - } + if (atomic_read(&clnt->cl_swapper)) + task->tk_flags |= RPC_TASK_SWAPPER; /* Add to the client's list of all tasks */ spin_lock(&clnt->cl_lock); list_add_tail(&task->tk_task, &clnt->cl_tasks); @@ -2479,3 +2472,59 @@ void rpc_show_tasks(struct net *net) spin_unlock(&sn->rpc_client_lock); } #endif + +#if IS_ENABLED(CONFIG_SUNRPC_SWAP) +int +rpc_clnt_swap_activate(struct rpc_clnt *clnt) +{ + int ret = 0; + struct rpc_xprt *xprt; + + if (atomic_inc_return(&clnt->cl_swapper) == 1) { +retry: + rcu_read_lock(); + xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); + rcu_read_unlock(); + if (!xprt) { + /* + * If we didn't get a reference, then we likely are + * racing with a migration event. Wait for a grace + * period and try again. + */ + synchronize_rcu(); + goto retry; + } + + ret = xs_swapper(xprt, 1); + xprt_put(xprt); + } + return ret; +} +EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate); + +void +rpc_clnt_swap_deactivate(struct rpc_clnt *clnt) +{ + struct rpc_xprt *xprt; + + if (atomic_dec_if_positive(&clnt->cl_swapper) == 0) { +retry: + rcu_read_lock(); + xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); + rcu_read_unlock(); + if (!xprt) { + /* + * If we didn't get a reference, then we likely are + * racing with a migration event. Wait for a grace + * period and try again. + */ + synchronize_rcu(); + goto retry; + } + + xs_swapper(xprt, 0); + xprt_put(xprt); + } +} +EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate); +#endif /* CONFIG_SUNRPC_SWAP */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b142feef0cf4..f344c0f8974c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1955,7 +1955,7 @@ static void xs_local_connect(struct rpc_xprt *xprt, struct rpc_task *task) msleep_interruptible(15000); } -#ifdef CONFIG_SUNRPC_SWAP +#if IS_ENABLED(CONFIG_SUNRPC_SWAP) static void xs_set_memalloc(struct rpc_xprt *xprt) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, @@ -1987,7 +1987,6 @@ int xs_swapper(struct rpc_xprt *xprt, int enable) return err; } -EXPORT_SYMBOL_GPL(xs_swapper); #else static void xs_set_memalloc(struct rpc_xprt *xprt) { -- cgit v1.2.3 From 8e2281330f9930bccf77cf04027ec60b6cc0fb34 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 3 Jun 2015 16:14:26 -0400 Subject: sunrpc: make xprt->swapper an atomic_t Split xs_swapper into enable/disable functions and eliminate the "enable" flag. Currently, it's racy if you have multiple swapon/swapoff operations running in parallel over the same xprt. Also fix it so that we only set it to a memalloc socket on a 0->1 transition and only clear it on a 1->0 transition. Cc: Mel Gorman Signed-off-by: Jeff Layton Reviewed-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 5 +++-- net/sunrpc/clnt.c | 4 ++-- net/sunrpc/xprtsock.c | 38 +++++++++++++++++++++++++------------- 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index bc9c39d6d30d..9a3308703c15 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -180,7 +180,7 @@ struct rpc_xprt { atomic_t num_reqs; /* total slots */ unsigned long state; /* transport state */ unsigned char resvport : 1; /* use a reserved port */ - unsigned int swapper; /* we're swapping over this + atomic_t swapper; /* we're swapping over this transport */ unsigned int bind_index; /* bind function index */ @@ -346,7 +346,8 @@ void xprt_release_rqst_cong(struct rpc_task *task); void xprt_disconnect_done(struct rpc_xprt *xprt); void xprt_force_disconnect(struct rpc_xprt *xprt); void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); -int xs_swapper(struct rpc_xprt *xprt, int enable); +int xs_swapper_enable(struct rpc_xprt *xprt); +void xs_swapper_disable(struct rpc_xprt *xprt); bool xprt_lock_connect(struct rpc_xprt *, struct rpc_task *, void *); void xprt_unlock_connect(struct rpc_xprt *, void *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0ba65156a62b..801044aeeedd 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -2495,7 +2495,7 @@ retry: goto retry; } - ret = xs_swapper(xprt, 1); + ret = xs_swapper_enable(xprt); xprt_put(xprt); } return ret; @@ -2522,7 +2522,7 @@ retry: goto retry; } - xs_swapper(xprt, 0); + xs_swapper_disable(xprt); xprt_put(xprt); } } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index f344c0f8974c..6538e6fbb7ba 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1961,31 +1961,43 @@ static void xs_set_memalloc(struct rpc_xprt *xprt) struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - if (xprt->swapper) + if (atomic_read(&xprt->swapper)) sk_set_memalloc(transport->inet); } /** - * xs_swapper - Tag this transport as being used for swap. + * xs_swapper_enable - Tag this transport as being used for swap. * @xprt: transport to tag - * @enable: enable/disable * + * Take a reference to this transport on behalf of the rpc_clnt, and + * optionally mark it for swapping if it wasn't already. */ -int xs_swapper(struct rpc_xprt *xprt, int enable) +int +xs_swapper_enable(struct rpc_xprt *xprt) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - int err = 0; - if (enable) { - xprt->swapper++; - xs_set_memalloc(xprt); - } else if (xprt->swapper) { - xprt->swapper--; - sk_clear_memalloc(transport->inet); - } + if (atomic_inc_return(&xprt->swapper) == 1) + sk_set_memalloc(transport->inet); + return 0; +} - return err; +/** + * xs_swapper_disable - Untag this transport as being used for swap. + * @xprt: transport to tag + * + * Drop a "swapper" reference to this xprt on behalf of the rpc_clnt. If the + * swapper refcount goes to 0, untag the socket as a memalloc socket. + */ +void +xs_swapper_disable(struct rpc_xprt *xprt) +{ + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, + xprt); + + if (atomic_dec_and_test(&xprt->swapper)) + sk_clear_memalloc(transport->inet); } #else static void xs_set_memalloc(struct rpc_xprt *xprt) -- cgit v1.2.3 From d67fa4d85a2143b46052b2e9ccc6749a4c97b2de Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 3 Jun 2015 16:14:29 -0400 Subject: sunrpc: turn swapper_enable/disable functions into rpc_xprt_ops RDMA xprts don't have a sock_xprt, but an rdma_xprt, so the xs_swapper_enable/disable functions will likely oops when fed an RDMA xprt. Turn these functions into rpc_xprt_ops so that that doesn't occur. For now the RDMA versions are no-ops that just return -EINVAL on an attempt to swapon. Cc: Chuck Lever Signed-off-by: Jeff Layton Reviewed-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 16 ++++++++++++++-- net/sunrpc/clnt.c | 4 ++-- net/sunrpc/xprtrdma/transport.c | 15 ++++++++++++++- net/sunrpc/xprtsock.c | 31 +++++++++++++++++++++++++------ 4 files changed, 55 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 9a3308703c15..b6096592b1d4 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -133,6 +133,8 @@ struct rpc_xprt_ops { void (*close)(struct rpc_xprt *xprt); void (*destroy)(struct rpc_xprt *xprt); void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq); + int (*enable_swap)(struct rpc_xprt *xprt); + void (*disable_swap)(struct rpc_xprt *xprt); }; /* @@ -328,6 +330,18 @@ static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 * return p + xprt->tsh_size; } +static inline int +xprt_enable_swap(struct rpc_xprt *xprt) +{ + return xprt->ops->enable_swap(xprt); +} + +static inline void +xprt_disable_swap(struct rpc_xprt *xprt) +{ + xprt->ops->disable_swap(xprt); +} + /* * Transport switch helper functions */ @@ -346,8 +360,6 @@ void xprt_release_rqst_cong(struct rpc_task *task); void xprt_disconnect_done(struct rpc_xprt *xprt); void xprt_force_disconnect(struct rpc_xprt *xprt); void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); -int xs_swapper_enable(struct rpc_xprt *xprt); -void xs_swapper_disable(struct rpc_xprt *xprt); bool xprt_lock_connect(struct rpc_xprt *, struct rpc_task *, void *); void xprt_unlock_connect(struct rpc_xprt *, void *); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 801044aeeedd..576d6ae39f25 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -2495,7 +2495,7 @@ retry: goto retry; } - ret = xs_swapper_enable(xprt); + ret = xprt_enable_swap(xprt); xprt_put(xprt); } return ret; @@ -2522,7 +2522,7 @@ retry: goto retry; } - xs_swapper_disable(xprt); + xprt_disable_swap(xprt); xprt_put(xprt); } } diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 54f23b1be986..ebf6fe759f0e 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -682,6 +682,17 @@ static void xprt_rdma_print_stats(struct rpc_xprt *xprt, struct seq_file *seq) r_xprt->rx_stats.bad_reply_count); } +static int +xprt_rdma_enable_swap(struct rpc_xprt *xprt) +{ + return -EINVAL; +} + +static void +xprt_rdma_disable_swap(struct rpc_xprt *xprt) +{ +} + /* * Plumbing for rpc transport switch and kernel module */ @@ -700,7 +711,9 @@ static struct rpc_xprt_ops xprt_rdma_procs = { .send_request = xprt_rdma_send_request, .close = xprt_rdma_close, .destroy = xprt_rdma_destroy, - .print_stats = xprt_rdma_print_stats + .print_stats = xprt_rdma_print_stats, + .enable_swap = xprt_rdma_enable_swap, + .disable_swap = xprt_rdma_disable_swap, }; static struct xprt_class xprt_rdma = { diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e0efd8514886..bf20726d4ab5 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1980,14 +1980,14 @@ static void xs_set_memalloc(struct rpc_xprt *xprt) } /** - * xs_swapper_enable - Tag this transport as being used for swap. + * xs_enable_swap - Tag this transport as being used for swap. * @xprt: transport to tag * * Take a reference to this transport on behalf of the rpc_clnt, and * optionally mark it for swapping if it wasn't already. */ -int -xs_swapper_enable(struct rpc_xprt *xprt) +static int +xs_enable_swap(struct rpc_xprt *xprt) { struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt); @@ -2002,14 +2002,14 @@ xs_swapper_enable(struct rpc_xprt *xprt) } /** - * xs_swapper_disable - Untag this transport as being used for swap. + * xs_disable_swap - Untag this transport as being used for swap. * @xprt: transport to tag * * Drop a "swapper" reference to this xprt on behalf of the rpc_clnt. If the * swapper refcount goes to 0, untag the socket as a memalloc socket. */ -void -xs_swapper_disable(struct rpc_xprt *xprt) +static void +xs_disable_swap(struct rpc_xprt *xprt) { struct sock_xprt *xs = container_of(xprt, struct sock_xprt, xprt); @@ -2025,6 +2025,17 @@ xs_swapper_disable(struct rpc_xprt *xprt) static void xs_set_memalloc(struct rpc_xprt *xprt) { } + +static int +xs_enable_swap(struct rpc_xprt *xprt) +{ + return -EINVAL; +} + +static void +xs_disable_swap(struct rpc_xprt *xprt) +{ +} #endif static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) @@ -2488,6 +2499,8 @@ static struct rpc_xprt_ops xs_local_ops = { .close = xs_close, .destroy = xs_destroy, .print_stats = xs_local_print_stats, + .enable_swap = xs_enable_swap, + .disable_swap = xs_disable_swap, }; static struct rpc_xprt_ops xs_udp_ops = { @@ -2507,6 +2520,8 @@ static struct rpc_xprt_ops xs_udp_ops = { .close = xs_close, .destroy = xs_destroy, .print_stats = xs_udp_print_stats, + .enable_swap = xs_enable_swap, + .disable_swap = xs_disable_swap, }; static struct rpc_xprt_ops xs_tcp_ops = { @@ -2523,6 +2538,8 @@ static struct rpc_xprt_ops xs_tcp_ops = { .close = xs_tcp_shutdown, .destroy = xs_destroy, .print_stats = xs_tcp_print_stats, + .enable_swap = xs_enable_swap, + .disable_swap = xs_disable_swap, }; /* @@ -2540,6 +2557,8 @@ static struct rpc_xprt_ops bc_tcp_ops = { .close = bc_close, .destroy = bc_destroy, .print_stats = xs_tcp_print_stats, + .enable_swap = xs_enable_swap, + .disable_swap = xs_disable_swap, }; static int xs_init_anyaddr(const int family, struct sockaddr *sap) -- cgit v1.2.3 From 11598b8ff2b97cf034d0c025cf125c92b574bafc Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 10 Jun 2015 16:54:28 -0400 Subject: NFS: Remove unused nfs_rw_ops->rw_release() function This was only ever set to nfs_writeback_release_common(), a function which is completely empty. Let's just drop this function pointer and simplify the code a bit. Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/pagelist.c | 2 -- fs/nfs/write.c | 6 ------ include/linux/nfs_page.h | 1 - 3 files changed, 9 deletions(-) (limited to 'include') diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 282b39369510..e9953ab1ac40 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -690,8 +690,6 @@ static int nfs_pgio_error(struct nfs_pageio_descriptor *desc, static void nfs_pgio_release(void *calldata) { struct nfs_pgio_header *hdr = calldata; - if (hdr->rw_ops->rw_release) - hdr->rw_ops->rw_release(hdr); nfs_pgio_data_destroy(hdr); hdr->completion_ops->completion(hdr); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index dfc19f1575a1..d0f1f210342e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1347,11 +1347,6 @@ void nfs_commit_prepare(struct rpc_task *task, void *calldata) NFS_PROTO(data->inode)->commit_rpc_prepare(task, data); } -static void nfs_writeback_release_common(struct nfs_pgio_header *hdr) -{ - /* do nothing! */ -} - /* * Special version of should_remove_suid() that ignores capabilities. */ @@ -2012,7 +2007,6 @@ static const struct nfs_rw_ops nfs_rw_write_ops = { .rw_mode = FMODE_WRITE, .rw_alloc_header = nfs_writehdr_alloc, .rw_free_header = nfs_writehdr_free, - .rw_release = nfs_writeback_release_common, .rw_done = nfs_writeback_done, .rw_result = nfs_writeback_result, .rw_initiate = nfs_initiate_write, diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 3eb072dbce83..f2f650f136ee 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h @@ -67,7 +67,6 @@ struct nfs_rw_ops { const fmode_t rw_mode; struct nfs_pgio_header *(*rw_alloc_header)(void); void (*rw_free_header)(struct nfs_pgio_header *); - void (*rw_release)(struct nfs_pgio_header *); int (*rw_done)(struct rpc_task *, struct nfs_pgio_header *, struct inode *); void (*rw_result)(struct rpc_task *, struct nfs_pgio_header *); -- cgit v1.2.3 From 4a06825839889cc1756d0dd8a52d6b1071ee0263 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 11 May 2015 14:02:25 -0400 Subject: SUNRPC: Transport fault injection It has been exceptionally useful to exercise the logic that handles local immediate errors and RDMA connection loss. To enable developers to test this regularly and repeatably, add logic to simulate connection loss every so often. Fault injection is disabled by default. It is enabled with $ sudo echo xxx > /sys/kernel/debug/sunrpc/inject_fault/disconnect where "xxx" is a large positive number of transport method calls before a disconnect. A value of several thousand is usually a good number that allows reasonable forward progress while still causing a lot of connection drops. These hooks are disabled when SUNRPC_DEBUG is turned off. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 19 ++++++++++ net/sunrpc/clnt.c | 1 + net/sunrpc/debugfs.c | 77 +++++++++++++++++++++++++++++++++++++++++ net/sunrpc/xprt.c | 2 ++ net/sunrpc/xprtrdma/transport.c | 11 ++++++ net/sunrpc/xprtsock.c | 10 ++++++ 6 files changed, 120 insertions(+) (limited to 'include') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index b6096592b1d4..0fb9acbb4780 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -135,6 +135,7 @@ struct rpc_xprt_ops { void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq); int (*enable_swap)(struct rpc_xprt *xprt); void (*disable_swap)(struct rpc_xprt *xprt); + void (*inject_disconnect)(struct rpc_xprt *xprt); }; /* @@ -244,6 +245,7 @@ struct rpc_xprt { const char *address_strings[RPC_DISPLAY_MAX]; #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) struct dentry *debugfs; /* debugfs directory */ + atomic_t inject_disconnect; #endif }; @@ -445,6 +447,23 @@ static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt) return test_and_set_bit(XPRT_BINDING, &xprt->state); } +#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) +extern unsigned int rpc_inject_disconnect; +static inline void xprt_inject_disconnect(struct rpc_xprt *xprt) +{ + if (!rpc_inject_disconnect) + return; + if (atomic_dec_return(&xprt->inject_disconnect)) + return; + atomic_set(&xprt->inject_disconnect, rpc_inject_disconnect); + xprt->ops->inject_disconnect(xprt); +} +#else +static inline void xprt_inject_disconnect(struct rpc_xprt *xprt) +{ +} +#endif + #endif /* __KERNEL__*/ #endif /* _LINUX_SUNRPC_XPRT_H */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 576d6ae39f25..f41ed882ed3c 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1605,6 +1605,7 @@ call_allocate(struct rpc_task *task) req->rq_callsize + req->rq_rcvsize); if (req->rq_buffer != NULL) return; + xprt_inject_disconnect(xprt); dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid); diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c index 82962f7e6e88..7cc1b8a6ef6d 100644 --- a/net/sunrpc/debugfs.c +++ b/net/sunrpc/debugfs.c @@ -10,9 +10,12 @@ #include "netns.h" static struct dentry *topdir; +static struct dentry *rpc_fault_dir; static struct dentry *rpc_clnt_dir; static struct dentry *rpc_xprt_dir; +unsigned int rpc_inject_disconnect; + struct rpc_clnt_iter { struct rpc_clnt *clnt; loff_t pos; @@ -257,6 +260,8 @@ rpc_xprt_debugfs_register(struct rpc_xprt *xprt) debugfs_remove_recursive(xprt->debugfs); xprt->debugfs = NULL; } + + atomic_set(&xprt->inject_disconnect, rpc_inject_disconnect); } void @@ -266,11 +271,78 @@ rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt) xprt->debugfs = NULL; } +static int +fault_open(struct inode *inode, struct file *filp) +{ + filp->private_data = kmalloc(128, GFP_KERNEL); + if (!filp->private_data) + return -ENOMEM; + return 0; +} + +static int +fault_release(struct inode *inode, struct file *filp) +{ + kfree(filp->private_data); + return 0; +} + +static ssize_t +fault_disconnect_read(struct file *filp, char __user *user_buf, + size_t len, loff_t *offset) +{ + char *buffer = (char *)filp->private_data; + size_t size; + + size = sprintf(buffer, "%u\n", rpc_inject_disconnect); + return simple_read_from_buffer(user_buf, len, offset, buffer, size); +} + +static ssize_t +fault_disconnect_write(struct file *filp, const char __user *user_buf, + size_t len, loff_t *offset) +{ + char buffer[16]; + + len = min(len, sizeof(buffer) - 1); + if (copy_from_user(buffer, user_buf, len)) + return -EFAULT; + buffer[len] = '\0'; + if (kstrtouint(buffer, 10, &rpc_inject_disconnect)) + return -EINVAL; + return len; +} + +static const struct file_operations fault_disconnect_fops = { + .owner = THIS_MODULE, + .open = fault_open, + .read = fault_disconnect_read, + .write = fault_disconnect_write, + .release = fault_release, +}; + +static struct dentry * +inject_fault_dir(struct dentry *topdir) +{ + struct dentry *faultdir; + + faultdir = debugfs_create_dir("inject_fault", topdir); + if (!faultdir) + return NULL; + + if (!debugfs_create_file("disconnect", S_IFREG | S_IRUSR, faultdir, + NULL, &fault_disconnect_fops)) + return NULL; + + return faultdir; +} + void __exit sunrpc_debugfs_exit(void) { debugfs_remove_recursive(topdir); topdir = NULL; + rpc_fault_dir = NULL; rpc_clnt_dir = NULL; rpc_xprt_dir = NULL; } @@ -282,6 +354,10 @@ sunrpc_debugfs_init(void) if (!topdir) return; + rpc_fault_dir = inject_fault_dir(topdir); + if (!rpc_fault_dir) + goto out_remove; + rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir); if (!rpc_clnt_dir) goto out_remove; @@ -294,5 +370,6 @@ sunrpc_debugfs_init(void) out_remove: debugfs_remove_recursive(topdir); topdir = NULL; + rpc_fault_dir = NULL; rpc_clnt_dir = NULL; } diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1d4fe24af06a..e1fb538e10e0 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -967,6 +967,7 @@ void xprt_transmit(struct rpc_task *task) task->tk_status = status; return; } + xprt_inject_disconnect(xprt); dprintk("RPC: %5u xmit complete\n", task->tk_pid); task->tk_flags |= RPC_TASK_SENT; @@ -1285,6 +1286,7 @@ void xprt_release(struct rpc_task *task) spin_unlock_bh(&xprt->transport_lock); if (req->rq_buffer) xprt->ops->buf_free(req->rq_buffer); + xprt_inject_disconnect(xprt); if (req->rq_cred != NULL) put_rpccred(req->rq_cred); task->tk_rqstp = NULL; diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index ebf6fe759f0e..b8aac23b1b0c 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -246,6 +246,16 @@ xprt_rdma_connect_worker(struct work_struct *work) xprt_clear_connecting(xprt); } +static void +xprt_rdma_inject_disconnect(struct rpc_xprt *xprt) +{ + struct rpcrdma_xprt *r_xprt = container_of(xprt, struct rpcrdma_xprt, + rx_xprt); + + pr_info("rpcrdma: injecting transport disconnect on xprt=%p\n", xprt); + rdma_disconnect(r_xprt->rx_ia.ri_id); +} + /* * xprt_rdma_destroy * @@ -714,6 +724,7 @@ static struct rpc_xprt_ops xprt_rdma_procs = { .print_stats = xprt_rdma_print_stats, .enable_swap = xprt_rdma_enable_swap, .disable_swap = xprt_rdma_disable_swap, + .inject_disconnect = xprt_rdma_inject_disconnect }; static struct xprt_class xprt_rdma = { diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index bf20726d4ab5..fda8ec8c74c0 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -866,6 +866,13 @@ static void xs_close(struct rpc_xprt *xprt) xprt_disconnect_done(xprt); } +static void xs_inject_disconnect(struct rpc_xprt *xprt) +{ + dprintk("RPC: injecting transport disconnect on xprt=%p\n", + xprt); + xprt_disconnect_done(xprt); +} + static void xs_xprt_free(struct rpc_xprt *xprt) { xs_free_peer_addresses(xprt); @@ -2522,6 +2529,7 @@ static struct rpc_xprt_ops xs_udp_ops = { .print_stats = xs_udp_print_stats, .enable_swap = xs_enable_swap, .disable_swap = xs_disable_swap, + .inject_disconnect = xs_inject_disconnect, }; static struct rpc_xprt_ops xs_tcp_ops = { @@ -2540,6 +2548,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { .print_stats = xs_tcp_print_stats, .enable_swap = xs_enable_swap, .disable_swap = xs_disable_swap, + .inject_disconnect = xs_inject_disconnect, }; /* @@ -2559,6 +2568,7 @@ static struct rpc_xprt_ops bc_tcp_ops = { .print_stats = xs_tcp_print_stats, .enable_swap = xs_enable_swap, .disable_swap = xs_disable_swap, + .inject_disconnect = xs_inject_disconnect, }; static int xs_init_anyaddr(const int family, struct sockaddr *sap) -- cgit v1.2.3 From 7e53df111beea8db2543424d07bdee2a630698c3 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 26 May 2015 11:53:04 -0400 Subject: xprtrdma: Remove rpcrdma_ia::ri_memreg_strategy Clean up: This field is no longer used. Signed-off-by: Chuck Lever Reviewed-by: Steve Wise Reviewed-by: Sagi Grimberg Reviewed-by: Devesh Sharma Tested-By: Devesh Sharma Reviewed-by: Doug Ledford Signed-off-by: Anna Schumaker --- include/linux/sunrpc/xprtrdma.h | 3 ++- net/sunrpc/xprtrdma/verbs.c | 3 --- net/sunrpc/xprtrdma/xprt_rdma.h | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/sunrpc/xprtrdma.h b/include/linux/sunrpc/xprtrdma.h index c984c85981ea..b17613052cc3 100644 --- a/include/linux/sunrpc/xprtrdma.h +++ b/include/linux/sunrpc/xprtrdma.h @@ -56,7 +56,8 @@ #define RPCRDMA_INLINE_PAD_THRESH (512)/* payload threshold to pad (bytes) */ -/* memory registration strategies */ +/* Memory registration strategies, by number. + * This is part of a kernel / user space API. Do not remove. */ enum rpcrdma_memreg { RPCRDMA_BOUNCEBUFFERS = 0, RPCRDMA_REGISTER, diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index db9303a6a145..cc1a52609974 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -665,9 +665,6 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) dprintk("RPC: %s: memory registration strategy is '%s'\n", __func__, ia->ri_ops->ro_displayname); - /* Else will do memory reg/dereg for each chunk */ - ia->ri_memreg_strategy = memreg; - rwlock_init(&ia->ri_qplock); return 0; diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index f19376d35750..3ecee38bf1a0 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h @@ -70,7 +70,6 @@ struct rpcrdma_ia { int ri_have_dma_lkey; struct completion ri_done; int ri_async_rc; - enum rpcrdma_memreg ri_memreg_strategy; unsigned int ri_max_frmr_depth; struct ib_device_attr ri_devattr; struct ib_qp_attr ri_qp_attr; -- cgit v1.2.3 From bc0c94b1404b225b19b6b53a0e508f43e269ed1e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Wed, 20 May 2015 21:48:03 -0700 Subject: target: Drop unnecessary core_tpg_register TFO parameter This patch drops unnecessary target_core_fabric_ops parameter usage for core_tpg_register() during fabric driver TFO->fabric_make_tpg() se_portal_group creation callback execution. Instead, use the existing se_wwn->wwn_tf->tf_ops pointer to ensure fabric driver is really using the same TFO provided at module_init time. Also go ahead and drop the forward TFO declarations tree-wide, and handling the special case for iscsi-target discovery TPG. Cc: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/srpt/ib_srpt.c | 4 +--- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 9 ++------- drivers/target/iscsi/iscsi_target_configfs.c | 3 +-- drivers/target/iscsi/iscsi_target_tpg.c | 8 ++++++-- drivers/target/loopback/tcm_loop.c | 5 +---- drivers/target/sbp/sbp_target.c | 2 +- drivers/target/target_core_tpg.c | 30 +++++++++++++++++++++++----- drivers/target/tcm_fc/tfc_conf.c | 5 +---- drivers/usb/gadget/legacy/tcm_usb_gadget.c | 5 +---- drivers/vhost/scsi.c | 4 +--- drivers/xen/xen-scsiback.c | 5 +---- include/target/target_core_fabric.h | 3 +-- 12 files changed, 42 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index dbad5c67a294..cea207e8b5d2 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -92,7 +92,6 @@ MODULE_PARM_DESC(srpt_service_guid, " instead of using the node_guid of the first HCA."); static struct ib_client srpt_client; -static const struct target_core_fabric_ops srpt_template; static void srpt_release_channel(struct srpt_rdma_ch *ch); static int srpt_queue_status(struct se_cmd *cmd); @@ -3733,8 +3732,7 @@ static struct se_portal_group *srpt_make_tpg(struct se_wwn *wwn, int res; /* Initialize sport->port_wwn and sport->port_tpg_1 */ - res = core_tpg_register(&srpt_template, &sport->port_wwn, - &sport->port_tpg_1, SCSI_PROTOCOL_SRP); + res = core_tpg_register(&sport->port_wwn, &sport->port_tpg_1, SCSI_PROTOCOL_SRP); if (res) return ERR_PTR(res); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index cb53144c72d0..e14a7fd7d810 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -52,9 +52,6 @@ static struct workqueue_struct *tcm_qla2xxx_free_wq; static struct workqueue_struct *tcm_qla2xxx_cmd_wq; -static const struct target_core_fabric_ops tcm_qla2xxx_ops; -static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops; - /* * Parse WWN. * If strict, we require lower-case hex and colon separators to be sure @@ -1004,8 +1001,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_FCP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; @@ -1124,8 +1120,7 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( tpg->tpg_attrib.cache_dynamic_acls = 1; tpg->tpg_attrib.demo_mode_login_only = 1; - ret = core_tpg_register(&tcm_qla2xxx_npiv_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_FCP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 523ae556e22c..c1898c84b3d2 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1419,8 +1419,7 @@ static struct se_portal_group *lio_target_tiqn_addtpg( if (!tpg) return NULL; - ret = core_tpg_register(&iscsi_ops, wwn, &tpg->tpg_se_tpg, - SCSI_PROTOCOL_ISCSI); + ret = core_tpg_register(wwn, &tpg->tpg_se_tpg, SCSI_PROTOCOL_ISCSI); if (ret < 0) return NULL; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index de8829102ab4..968068ffcb1c 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -66,8 +66,12 @@ int iscsit_load_discovery_tpg(void) pr_err("Unable to allocate struct iscsi_portal_group\n"); return -1; } - - ret = core_tpg_register(&iscsi_ops, NULL, &tpg->tpg_se_tpg, -1); + /* + * Save iscsi_ops pointer for special case discovery TPG that + * doesn't exist as se_wwn->wwn_group within configfs. + */ + tpg->tpg_se_tpg.se_tpg_tfo = &iscsi_ops; + ret = core_tpg_register(NULL, &tpg->tpg_se_tpg, -1); if (ret < 0) { kfree(tpg); return -1; diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b0c17614493e..bd9d11a6f823 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -40,8 +40,6 @@ #define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) -static const struct target_core_fabric_ops loop_ops; - static struct workqueue_struct *tcm_loop_workqueue; static struct kmem_cache *tcm_loop_cmd_cache; @@ -1081,8 +1079,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( /* * Register the tl_tpg as a emulated SAS TCM Target Endpoint */ - ret = core_tpg_register(&loop_ops, wwn, &tl_tpg->tl_se_tpg, - tl_hba->tl_proto_id); + ret = core_tpg_register(wwn, &tl_tpg->tl_se_tpg, tl_hba->tl_proto_id); if (ret < 0) return ERR_PTR(-ENOMEM); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 28e3adf1eb85..42f82d32ca85 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -2055,7 +2055,7 @@ static struct se_portal_group *sbp_make_tpg( goto out_free_tpg; } - ret = core_tpg_register(&sbp_ops, wwn, &tpg->se_tpg, SCSI_PROTOCOL_SBP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SBP); if (ret < 0) goto out_unreg_mgt_agt; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index b9fcf2c4898e..2e77eebe1671 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -37,6 +37,7 @@ #include #include +#include #include #include "target_core_internal.h" @@ -487,16 +488,34 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref) } int core_tpg_register( - const struct target_core_fabric_ops *tfo, struct se_wwn *se_wwn, struct se_portal_group *se_tpg, int proto_id) { int ret; + if (!se_tpg) + return -EINVAL; + /* + * For the typical case where core_tpg_register() is called by a + * fabric driver from target_core_fabric_ops->fabric_make_tpg() + * configfs context, use the original tf_ops pointer already saved + * by target-core in target_fabric_make_wwn(). + * + * Otherwise, for special cases like iscsi-target discovery TPGs + * the caller is responsible for setting ->se_tpg_tfo ahead of + * calling core_tpg_register(). + */ + if (se_wwn) + se_tpg->se_tpg_tfo = se_wwn->wwn_tf->tf_ops; + + if (!se_tpg->se_tpg_tfo) { + pr_err("Unable to locate se_tpg->se_tpg_tfo pointer\n"); + return -EINVAL; + } + INIT_HLIST_HEAD(&se_tpg->tpg_lun_hlist); se_tpg->proto_id = proto_id; - se_tpg->se_tpg_tfo = tfo; se_tpg->se_tpg_wwn = se_wwn; atomic_set(&se_tpg->tpg_pr_ref_count, 0); INIT_LIST_HEAD(&se_tpg->acl_node_list); @@ -524,9 +543,10 @@ int core_tpg_register( spin_unlock_bh(&tpg_lock); pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, " - "Proto: %d, Portal Tag: %u\n", tfo->get_fabric_name(), - tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, - se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); + "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->get_fabric_name(), + se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ? + se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) : NULL, + se_tpg->proto_id, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); return 0; } diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 8e1a54f2642c..80a4477fa7ee 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -47,8 +47,6 @@ #include "tcm_fc.h" -static const struct target_core_fabric_ops ft_fabric_ops; - static LIST_HEAD(ft_wwn_list); DEFINE_MUTEX(ft_lport_lock); @@ -282,8 +280,7 @@ static struct se_portal_group *ft_add_tpg( return NULL; } - ret = core_tpg_register(&ft_fabric_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_FCP); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP); if (ret < 0) { destroy_workqueue(wq); kfree(tpg); diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c index 16b9a16678fe..4ff426edf22a 100644 --- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c +++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c @@ -28,8 +28,6 @@ USB_GADGET_COMPOSITE_OPTIONS(); -static const struct target_core_fabric_ops usbg_ops; - static inline struct f_uas *to_f_uas(struct usb_function *f) { return container_of(f, struct f_uas, function); @@ -1418,8 +1416,7 @@ static struct se_portal_group *usbg_make_tpg( * SPC doesn't assign a protocol identifier for USB-SCSI, so we * pretend to be SAS.. */ - ret = core_tpg_register(&usbg_ops, wwn, &tpg->se_tpg, - SCSI_PROTOCOL_SAS); + ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_SAS); if (ret < 0) { destroy_workqueue(tpg->workqueue); kfree(tpg); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index dcd228b59ded..450aece0227c 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -206,7 +206,6 @@ struct vhost_scsi { int vs_events_nr; /* num of pending events, protected by vq->mutex */ }; -static struct target_core_fabric_ops vhost_scsi_ops; static struct workqueue_struct *vhost_scsi_workqueue; /* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */ @@ -2001,8 +2000,7 @@ vhost_scsi_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&vhost_scsi_ops, wwn, &tpg->se_tpg, - tport->tport_proto_id); + ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 555033bd9239..25144a0ff07c 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -203,8 +203,6 @@ static LIST_HEAD(scsiback_free_pages); static DEFINE_MUTEX(scsiback_mutex); static LIST_HEAD(scsiback_list); -static const struct target_core_fabric_ops scsiback_ops; - static void scsiback_get(struct vscsibk_info *info) { atomic_inc(&info->nr_unreplied_reqs); @@ -1765,8 +1763,7 @@ scsiback_make_tpg(struct se_wwn *wwn, tpg->tport = tport; tpg->tport_tpgt = tpgt; - ret = core_tpg_register(&scsiback_ops, wwn, &tpg->se_tpg, - tport->tport_proto_id); + ret = core_tpg_register(wwn, &tpg->se_tpg, tport->tport_proto_id); if (ret < 0) { kfree(tpg); return NULL; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index b1e00a7d66de..d6216b761333 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -161,8 +161,7 @@ int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *, unsigned char *, u32, int); int core_tpg_set_initiator_node_tag(struct se_portal_group *, struct se_node_acl *, const char *); -int core_tpg_register(const struct target_core_fabric_ops *, - struct se_wwn *, struct se_portal_group *, int); +int core_tpg_register(struct se_wwn *, struct se_portal_group *, int); int core_tpg_deregister(struct se_portal_group *); /* -- cgit v1.2.3 From f2d30680204f20b815e6796437923fb870b6c193 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 10 Jun 2015 08:41:22 +0200 Subject: target: use 64-bit LUNs As we're now using a list to hold the LUNs the target core can now converted to use 64-bit LUNs internally. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_tmr.c | 4 +-- drivers/target/loopback/tcm_loop.c | 4 +-- drivers/target/target_core_alua.c | 2 +- drivers/target/target_core_configfs.c | 12 ++++---- drivers/target/target_core_device.c | 30 +++++++++---------- drivers/target/target_core_fabric_configfs.c | 18 ++++-------- drivers/target/target_core_internal.h | 10 +++---- drivers/target/target_core_pr.c | 43 ++++++++++++++-------------- drivers/target/target_core_pr.h | 6 ++-- drivers/target/target_core_tpg.c | 6 ++-- drivers/target/target_core_transport.c | 6 ++-- drivers/target/target_core_ua.c | 8 +++--- drivers/target/target_core_ua.h | 2 +- include/target/target_core_base.h | 19 ++++++------ include/target/target_core_fabric.h | 10 +++---- 15 files changed, 88 insertions(+), 92 deletions(-) (limited to 'include') diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index b0224a77e26d..515988258e9e 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -120,7 +120,7 @@ u8 iscsit_tmr_task_reassign( struct iscsi_tmr_req *tmr_req = cmd->tmr_req; struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; struct iscsi_tm *hdr = (struct iscsi_tm *) buf; - int ret, ref_lun; + u64 ret, ref_lun; pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x," " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n", @@ -164,7 +164,7 @@ u8 iscsit_tmr_task_reassign( ref_lun = scsilun_to_int(&hdr->lun); if (ref_lun != ref_cmd->se_cmd.orig_fe_lun) { pr_err("Unable to perform connection recovery for" - " differing ref_lun: %d ref_cmd orig_fe_lun: %u\n", + " differing ref_lun: %llu ref_cmd orig_fe_lun: %llu\n", ref_lun, ref_cmd->se_cmd.orig_fe_lun); return ISCSI_TMF_RSP_REJECTED; } diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index bd9d11a6f823..a556bdebd775 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -215,7 +215,7 @@ static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) * to struct scsi_device */ static int tcm_loop_issue_tmr(struct tcm_loop_tpg *tl_tpg, - int lun, int task, enum tcm_tmreq_table tmr) + u64 lun, int task, enum tcm_tmreq_table tmr) { struct se_cmd *se_cmd = NULL; struct se_session *se_sess; @@ -747,7 +747,7 @@ static void tcm_loop_port_unlink( se_lun->unpacked_lun); if (!sd) { pr_err("Unable to locate struct scsi_device for %d:%d:" - "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); + "%llu\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); return; } /* diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 02d8e1a8a6a5..2318e6e5ce52 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -1257,7 +1257,7 @@ static int core_alua_update_tpg_secondary_metadata(struct se_lun *lun) atomic_read(&lun->lun_tg_pt_secondary_offline), lun->lun_tg_pt_secondary_stat); - snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u", + snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%llu", se_tpg->se_tpg_tfo->get_fabric_name(), wwn, lun->unpacked_lun); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index f97b969e6714..68addbc7eb7b 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1438,7 +1438,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port( tfo->tpg_get_wwn(se_tpg)); len += sprintf(page+len, "SPC-3 Reservation: Relative Port" " Identifier Tag: %hu %s Portal Group Tag: %hu" - " %s Logical Unit: %u\n", pr_reg->tg_pt_sep_rtpi, + " %s Logical Unit: %llu\n", pr_reg->tg_pt_sep_rtpi, tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg), tfo->get_fabric_name(), pr_reg->pr_aptpl_target_lun); @@ -1565,12 +1565,12 @@ static match_table_t tokens = { {Opt_res_type, "res_type=%d"}, {Opt_res_scope, "res_scope=%d"}, {Opt_res_all_tg_pt, "res_all_tg_pt=%d"}, - {Opt_mapped_lun, "mapped_lun=%d"}, + {Opt_mapped_lun, "mapped_lun=%lld"}, {Opt_target_fabric, "target_fabric=%s"}, {Opt_target_node, "target_node=%s"}, {Opt_tpgt, "tpgt=%d"}, {Opt_port_rtpi, "port_rtpi=%d"}, - {Opt_target_lun, "target_lun=%d"}, + {Opt_target_lun, "target_lun=%lld"}, {Opt_err, NULL} }; @@ -1585,7 +1585,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( substring_t args[MAX_OPT_ARGS]; unsigned long long tmp_ll; u64 sa_res_key = 0; - u32 mapped_lun = 0, target_lun = 0; + u64 mapped_lun = 0, target_lun = 0; int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token; u16 tpgt = 0; u8 type = 0; @@ -1675,7 +1675,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_mapped_lun: match_int(args, &arg); - mapped_lun = (u32)arg; + mapped_lun = (u64)arg; break; /* * PR APTPL Metadata for Target Port @@ -1710,7 +1710,7 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_target_lun: match_int(args, &arg); - target_lun = (u32)arg; + target_lun = (u64)arg; break; default: break; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index db531fb5e787..2ea7322c4dd4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -56,7 +56,7 @@ static struct se_hba *lun0_hba; struct se_device *g_lun0_dev; sense_reason_t -transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) +transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) { struct se_lun *se_lun = NULL; struct se_session *se_sess = se_cmd->se_sess; @@ -74,7 +74,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) if ((se_cmd->data_direction == DMA_TO_DEVICE) && (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) { pr_err("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN" - " Access for 0x%08x\n", + " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); rcu_read_unlock(); @@ -107,7 +107,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) */ if (unpacked_lun != 0) { pr_err("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" - " Access for 0x%08x\n", + " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); return TCM_NON_EXISTENT_LUN; @@ -147,7 +147,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) } EXPORT_SYMBOL(transport_lookup_cmd_lun); -int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) +int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) { struct se_dev_entry *deve; struct se_lun *se_lun = NULL; @@ -172,7 +172,7 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) if (!se_lun) { pr_debug("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN" - " Access for 0x%08x\n", + " Access for 0x%08llx\n", se_cmd->se_tfo->get_fabric_name(), unpacked_lun); return -ENODEV; @@ -260,7 +260,7 @@ void core_free_device_list_for_node( } void core_update_device_list_access( - u32 mapped_lun, + u64 mapped_lun, u32 lun_access, struct se_node_acl *nacl) { @@ -283,7 +283,7 @@ void core_update_device_list_access( /* * Called with rcu_read_lock or nacl->device_list_lock held. */ -struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *nacl, u32 mapped_lun) +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *nacl, u64 mapped_lun) { struct se_dev_entry *deve; @@ -309,7 +309,7 @@ void target_pr_kref_release(struct kref *kref) int core_enable_device_list_for_node( struct se_lun *lun, struct se_lun_acl *lun_acl, - u32 mapped_lun, + u64 mapped_lun, u32 lun_access, struct se_node_acl *nacl, struct se_portal_group *tpg) @@ -550,7 +550,7 @@ int core_dev_add_lun( if (rc < 0) return rc; - pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from" + pr_debug("%s_TPG[%u]_LUN[%llu] - Activated %s Logical Unit from" " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id); @@ -583,7 +583,7 @@ void core_dev_del_lun( struct se_portal_group *tpg, struct se_lun *lun) { - pr_debug("%s_TPG[%u]_LUN[%u] - Deactivating %s Logical Unit from" + pr_debug("%s_TPG[%u]_LUN[%llu] - Deactivating %s Logical Unit from" " device object\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, tpg->se_tpg_tfo->get_fabric_name()); @@ -594,7 +594,7 @@ void core_dev_del_lun( struct se_lun_acl *core_dev_init_initiator_node_lun_acl( struct se_portal_group *tpg, struct se_node_acl *nacl, - u32 mapped_lun, + u64 mapped_lun, int *ret) { struct se_lun_acl *lacl; @@ -646,7 +646,7 @@ int core_dev_add_initiator_node_lun_acl( lun_access, nacl, tpg) < 0) return -EINVAL; - pr_debug("%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for " + pr_debug("%s_TPG[%hu]_LUN[%llu->%llu] - Added %s ACL for " " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", @@ -678,8 +678,8 @@ int core_dev_del_initiator_node_lun_acl( core_disable_device_list_for_node(lun, deve, nacl, tpg); mutex_unlock(&nacl->lun_entry_mutex); - pr_debug("%s_TPG[%hu]_LUN[%u] - Removed ACL for" - " InitiatorNode: %s Mapped LUN: %u\n", + pr_debug("%s_TPG[%hu]_LUN[%llu] - Removed ACL for" + " InitiatorNode: %s Mapped LUN: %llu\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->initiatorname, lacl->mapped_lun); @@ -692,7 +692,7 @@ void core_dev_free_initiator_node_lun_acl( struct se_lun_acl *lacl) { pr_debug("%s_TPG[%hu] - Freeing ACL for %s InitiatorNode: %s" - " Mapped LUN: %u\n", tpg->se_tpg_tfo->get_fabric_name(), + " Mapped LUN: %llu\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), tpg->se_tpg_tfo->get_fabric_name(), lacl->initiatorname, lacl->mapped_lun); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 0ee182fce1a6..2fd493e416b0 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -202,7 +202,7 @@ static ssize_t target_fabric_mappedlun_store_write_protect( lacl->se_lun_nacl); pr_debug("%s_ConfigFS: Changed Initiator ACL: %s" - " Mapped LUN: %u Write Protect bit to %s\n", + " Mapped LUN: %llu Write Protect bit to %s\n", se_tpg->se_tpg_tfo->get_fabric_name(), lacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF"); @@ -322,7 +322,7 @@ static struct config_group *target_fabric_make_mappedlun( struct config_item *acl_ci; struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; char *buf; - unsigned long mapped_lun; + unsigned long long mapped_lun; int ret = 0; acl_ci = &group->cg_item; @@ -350,15 +350,11 @@ static struct config_group *target_fabric_make_mappedlun( * Determine the Mapped LUN value. This is what the SCSI Initiator * Port will actually see. */ - ret = kstrtoul(buf + 4, 0, &mapped_lun); + ret = kstrtoull(buf + 4, 0, &mapped_lun); if (ret) goto out; - if (mapped_lun > UINT_MAX) { - ret = -EINVAL; - goto out; - } if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("Mapped LUN: %lu exceeds TRANSPORT_MAX_LUNS_PER_TPG" + pr_err("Mapped LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" "-1: %u for Target Portal Group: %u\n", mapped_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); @@ -881,7 +877,7 @@ static struct config_group *target_fabric_make_lun( struct se_portal_group, tpg_lun_group); struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct config_group *lun_cg = NULL, *port_stat_grp = NULL; - unsigned long unpacked_lun; + unsigned long long unpacked_lun; int errno; if (strstr(name, "lun_") != name) { @@ -889,11 +885,9 @@ static struct config_group *target_fabric_make_lun( " \"lun_$LUN_NUMBER\"\n"); return ERR_PTR(-EINVAL); } - errno = kstrtoul(name + 4, 0, &unpacked_lun); + errno = kstrtoull(name + 4, 0, &unpacked_lun); if (errno) return ERR_PTR(errno); - if (unpacked_lun > UINT_MAX) - return ERR_PTR(-EINVAL); lun = core_tpg_alloc_lun(se_tpg, unpacked_lun); if (IS_ERR(lun)) diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 8d8737a13e6f..511178969df3 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -26,10 +26,10 @@ struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16); void target_pr_kref_release(struct kref *); void core_free_device_list_for_node(struct se_node_acl *, struct se_portal_group *); -void core_update_device_list_access(u32, u32, struct se_node_acl *); -struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u32); +void core_update_device_list_access(u64, u32, struct se_node_acl *); +struct se_dev_entry *target_nacl_find_deve(struct se_node_acl *, u64); int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *, - u32, u32, struct se_node_acl *, struct se_portal_group *); + u64, u32, struct se_node_acl *, struct se_portal_group *); void core_disable_device_list_for_node(struct se_lun *, struct se_dev_entry *, struct se_node_acl *, struct se_portal_group *); void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *); @@ -37,7 +37,7 @@ int core_dev_add_lun(struct se_portal_group *, struct se_device *, struct se_lun *lun); void core_dev_del_lun(struct se_portal_group *, struct se_lun *); struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *, - struct se_node_acl *, u32, int *); + struct se_node_acl *, u64, int *); int core_dev_add_initiator_node_lun_acl(struct se_portal_group *, struct se_lun_acl *, struct se_lun *lun, u32); int core_dev_del_initiator_node_lun_acl(struct se_lun *, @@ -80,7 +80,7 @@ struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tp void core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *, struct se_lun *); void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *); -struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32); +struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u64); int core_tpg_add_lun(struct se_portal_group *, struct se_lun *, u32, struct se_device *); void core_tpg_remove_lun(struct se_portal_group *, struct se_lun *); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 94935eaa7fa7..436e30b14a11 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -229,8 +229,9 @@ target_scsi2_reservation_release(struct se_cmd *cmd) dev->dev_reservation_flags &= ~DRF_SPC2_RESERVATIONS_WITH_ISID; } tpg = sess->se_tpg; - pr_debug("SCSI-2 Released reservation for %s LUN: %u ->" - " MAPPED LUN: %u for %s\n", tpg->se_tpg_tfo->get_fabric_name(), + pr_debug("SCSI-2 Released reservation for %s LUN: %llu ->" + " MAPPED LUN: %llu for %s\n", + tpg->se_tpg_tfo->get_fabric_name(), cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); @@ -275,10 +276,10 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) (dev->dev_reserved_node_acl != sess->se_node_acl)) { pr_err("SCSI-2 RESERVATION CONFLIFT for %s fabric\n", tpg->se_tpg_tfo->get_fabric_name()); - pr_err("Original reserver LUN: %u %s\n", + pr_err("Original reserver LUN: %llu %s\n", cmd->se_lun->unpacked_lun, dev->dev_reserved_node_acl->initiatorname); - pr_err("Current attempt - LUN: %u -> MAPPED LUN: %u" + pr_err("Current attempt - LUN: %llu -> MAPPED LUN: %llu" " from %s \n", cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); @@ -292,7 +293,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) dev->dev_res_bin_isid = sess->sess_bin_isid; dev->dev_reservation_flags |= DRF_SPC2_RESERVATIONS_WITH_ISID; } - pr_debug("SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u" + pr_debug("SCSI-2 Reserved %s LUN: %llu -> MAPPED LUN: %llu" " for %s\n", tpg->se_tpg_tfo->get_fabric_name(), cmd->se_lun->unpacked_lun, cmd->orig_fe_lun, sess->se_node_acl->initiatorname); @@ -618,7 +619,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( struct se_node_acl *nacl, struct se_lun *lun, struct se_dev_entry *deve, - u32 mapped_lun, + u64 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -671,7 +672,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( struct se_node_acl *nacl, struct se_lun *lun, struct se_dev_entry *deve, - u32 mapped_lun, + u64 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -804,10 +805,10 @@ int core_scsi3_alloc_aptpl_registration( u64 sa_res_key, unsigned char *i_port, unsigned char *isid, - u32 mapped_lun, + u64 mapped_lun, unsigned char *t_port, u16 tpgt, - u32 target_lun, + u64 target_lun, int res_holder, int all_tg_pt, u8 type) @@ -901,9 +902,9 @@ static int __core_scsi3_check_aptpl_registration( struct se_device *dev, struct se_portal_group *tpg, struct se_lun *lun, - u32 target_lun, + u64 target_lun, struct se_node_acl *nacl, - u32 mapped_lun) + u64 mapped_lun) { struct t10_pr_registration *pr_reg, *pr_reg_tmp; struct t10_reservation *pr_tmpl = &dev->t10_pr; @@ -972,7 +973,7 @@ int core_scsi3_check_aptpl_registration( struct se_portal_group *tpg, struct se_lun *lun, struct se_node_acl *nacl, - u32 mapped_lun) + u64 mapped_lun) { if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS) return 0; @@ -1094,7 +1095,7 @@ static int core_scsi3_alloc_registration( struct se_node_acl *nacl, struct se_lun *lun, struct se_dev_entry *deve, - u32 mapped_lun, + u64 mapped_lun, unsigned char *isid, u64 sa_res_key, int all_tg_pt, @@ -1668,7 +1669,7 @@ core_scsi3_decode_spec_i_port( } pr_debug("SPC-3 PR SPEC_I_PT: Located %s Node: %s" - " dest_se_deve mapped_lun: %u\n", + " dest_se_deve mapped_lun: %llu\n", dest_tpg->se_tpg_tfo->get_fabric_name(), dest_node_acl->initiatorname, dest_se_deve->mapped_lun); @@ -1780,7 +1781,7 @@ core_scsi3_decode_spec_i_port( pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully" " registered Transport ID for Node: %s%s Mapped LUN:" - " %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), + " %llu\n", dest_tpg->se_tpg_tfo->get_fabric_name(), dest_node_acl->initiatorname, i_buf, (dest_se_deve) ? dest_se_deve->mapped_lun : 0); @@ -1873,7 +1874,7 @@ static int core_scsi3_update_aptpl_buf( "sa_res_key=%llu\n" "res_holder=1\nres_type=%02x\n" "res_scope=%02x\nres_all_tg_pt=%d\n" - "mapped_lun=%u\n", reg_count, + "mapped_lun=%llu\n", reg_count, tpg->se_tpg_tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, isid_buf, pr_reg->pr_res_key, pr_reg->pr_res_type, @@ -1883,7 +1884,7 @@ static int core_scsi3_update_aptpl_buf( snprintf(tmp, 512, "PR_REG_START: %d\n" "initiator_fabric=%s\ninitiator_node=%s\n%s" "sa_res_key=%llu\nres_holder=0\n" - "res_all_tg_pt=%d\nmapped_lun=%u\n", + "res_all_tg_pt=%d\nmapped_lun=%llu\n", reg_count, tpg->se_tpg_tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, isid_buf, pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt, @@ -1902,7 +1903,7 @@ static int core_scsi3_update_aptpl_buf( * Include information about the associated SCSI target port. */ snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n" - "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:" + "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%llu\nPR_REG_END:" " %d\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_wwn(tpg), tpg->se_tpg_tfo->tpg_get_tag(tpg), @@ -2646,7 +2647,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key) struct se_session *se_sess = cmd->se_sess; struct t10_reservation *pr_tmpl = &dev->t10_pr; struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; - u32 pr_res_mapped_lun = 0; + u64 pr_res_mapped_lun = 0; int calling_it_nexus = 0; /* * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2802,7 +2803,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, LIST_HEAD(preempt_and_abort_list); struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder; struct t10_reservation *pr_tmpl = &dev->t10_pr; - u32 pr_res_mapped_lun = 0; + u64 pr_res_mapped_lun = 0; int all_reg = 0, calling_it_nexus = 0; bool sa_res_key_unmatched = sa_res_key != 0; int prh_type = 0, prh_scope = 0; @@ -3350,7 +3351,7 @@ after_iport_check: } pr_debug("SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN" - " ACL for dest_se_deve->mapped_lun: %u\n", + " ACL for dest_se_deve->mapped_lun: %llu\n", dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname, dest_se_deve->mapped_lun); diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index 749fd7bb7510..e3d26e9126a0 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -56,11 +56,11 @@ extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *); extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *); extern int core_scsi3_alloc_aptpl_registration( struct t10_reservation *, u64, - unsigned char *, unsigned char *, u32, - unsigned char *, u16, u32, int, int, u8); + unsigned char *, unsigned char *, u64, + unsigned char *, u16, u64, int, int, u8); extern int core_scsi3_check_aptpl_registration(struct se_device *, struct se_portal_group *, struct se_lun *, - struct se_node_acl *, u32); + struct se_node_acl *, u64); extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *, struct se_node_acl *); extern void core_scsi3_free_all_registrations(struct se_device *); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 2e77eebe1671..82ed8a0f3f0e 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -122,7 +122,7 @@ void core_tpg_add_node_to_devs( lun_access = TRANSPORT_LUNFLAGS_READ_WRITE; } - pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%u] - Adding %s" + pr_debug("TARGET_CORE[%s]->TPG[%u]_LUN[%llu] - Adding %s" " access for LUN in Demo Mode\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, @@ -598,12 +598,12 @@ EXPORT_SYMBOL(core_tpg_deregister); struct se_lun *core_tpg_alloc_lun( struct se_portal_group *tpg, - u32 unpacked_lun) + u64 unpacked_lun) { struct se_lun *lun; if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG" + pr_err("%s LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" "-1: %u for Target Portal Group: %u\n", tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d8a59122fe3b..eed9580b7f6c 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1366,7 +1366,7 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, * assumes internal allocation of fabric payload buffer by target-core. */ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, + unsigned char *cdb, unsigned char *sense, u64 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags, struct scatterlist *sgl, u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count, @@ -1502,7 +1502,7 @@ EXPORT_SYMBOL(target_submit_cmd_map_sgls); * It also assumes interal target core SGL memory allocation. */ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *cdb, unsigned char *sense, u32 unpacked_lun, + unsigned char *cdb, unsigned char *sense, u64 unpacked_lun, u32 data_length, int task_attr, int data_dir, int flags) { return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense, @@ -1539,7 +1539,7 @@ static void target_complete_tmr_failure(struct work_struct *work) **/ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *sense, u32 unpacked_lun, + unsigned char *sense, u64 unpacked_lun, void *fabric_tmr_ptr, unsigned char tm_type, gfp_t gfp, unsigned int tag, int flags) { diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index 6c9616d212b1..e53d4eec2ebc 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -88,7 +88,7 @@ target_scsi3_ua_check(struct se_cmd *cmd) int core_scsi3_ua_allocate( struct se_node_acl *nacl, - u32 unpacked_lun, + u64 unpacked_lun, u8 asc, u8 ascq) { @@ -177,7 +177,7 @@ int core_scsi3_ua_allocate( list_add_tail(&ua->ua_nacl_list, &deve->ua_list); spin_unlock(&deve->ua_lock); - pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:" + pr_debug("[%s]: Allocated UNIT ATTENTION, mapped LUN: %llu, ASC:" " 0x%02x, ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), unpacked_lun, asc, ascq); @@ -267,7 +267,7 @@ void core_scsi3_ua_for_check_condition( rcu_read_unlock(); pr_debug("[%s]: %s UNIT ATTENTION condition with" - " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x" + " INTLCK_CTRL: %d, mapped LUN: %llu, got CDB: 0x%02x" " reported ASC: 0x%02x, ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" : @@ -329,7 +329,7 @@ int core_scsi3_ua_clear_for_request_sense( rcu_read_unlock(); pr_debug("[%s]: Released UNIT ATTENTION condition, mapped" - " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x," + " LUN: %llu, got REQUEST_SENSE reported ASC: 0x%02x," " ASCQ: 0x%02x\n", nacl->se_tpg->se_tpg_tfo->get_fabric_name(), cmd->orig_fe_lun, *asc, *ascq); diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index a6b56b364e7a..6e592b10a8c0 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -28,7 +28,7 @@ extern struct kmem_cache *se_ua_cache; extern sense_reason_t target_scsi3_ua_check(struct se_cmd *); -extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8); +extern int core_scsi3_ua_allocate(struct se_node_acl *, u64, u8, u8); extern void core_scsi3_ua_release_all(struct se_dev_entry *); extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *); extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index eefc2b0cfaa3..836ff8abdf18 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -355,8 +355,8 @@ struct t10_pr_registration { int pr_res_scope; /* Used for fabric initiator WWPNs using a ISID */ bool isid_present_at_reg; - u32 pr_res_mapped_lun; - u32 pr_aptpl_target_lun; + u64 pr_res_mapped_lun; + u64 pr_aptpl_target_lun; u16 tg_pt_sep_rtpi; u32 pr_res_generation; u64 pr_reg_bin_isid; @@ -476,7 +476,7 @@ struct se_cmd { /* Total size in bytes associated with command */ u32 data_length; u32 residual_count; - u32 orig_fe_lun; + u64 orig_fe_lun; /* Persistent Reservation key */ u64 pr_res_key; /* Used for sense data */ @@ -614,7 +614,7 @@ struct se_ml_stat_grps { struct se_lun_acl { char initiatorname[TRANSPORT_IQN_LEN]; - u32 mapped_lun; + u64 mapped_lun; struct se_node_acl *se_lun_nacl; struct se_lun *se_lun; struct config_group se_lun_group; @@ -623,10 +623,10 @@ struct se_lun_acl { struct se_dev_entry { /* See transport_lunflags_table */ - u32 lun_flags; - u32 mapped_lun; + u64 mapped_lun; u64 pr_res_key; u64 creation_time; + u32 lun_flags; u32 attach_count; atomic_long_t total_cmds; atomic_long_t read_bytes; @@ -696,14 +696,15 @@ struct scsi_port_stats { }; struct se_lun { - /* RELATIVE TARGET PORT IDENTIFER */ - u16 lun_rtpi; + u64 unpacked_lun; #define SE_LUN_LINK_MAGIC 0xffff7771 u32 lun_link_magic; u32 lun_access; u32 lun_flags; - u32 unpacked_lun; u32 lun_index; + + /* RELATIVE TARGET PORT IDENTIFER */ + u16 lun_rtpi; atomic_t lun_acl_count; struct se_device __rcu *lun_se_dev; diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index d6216b761333..18afef91b447 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -116,16 +116,16 @@ void transport_deregister_session(struct se_session *); void transport_init_se_cmd(struct se_cmd *, const struct target_core_fabric_ops *, struct se_session *, u32, int, int, unsigned char *); -sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32); +sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u64); sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *); int target_submit_cmd_map_sgls(struct se_cmd *, struct se_session *, - unsigned char *, unsigned char *, u32, u32, int, int, int, + unsigned char *, unsigned char *, u64, u32, int, int, int, struct scatterlist *, u32, struct scatterlist *, u32, struct scatterlist *, u32); int target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *, - unsigned char *, u32, u32, int, int, int); + unsigned char *, u64, u32, int, int, int); int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess, - unsigned char *sense, u32 unpacked_lun, + unsigned char *sense, u64 unpacked_lun, void *fabric_tmr_ptr, unsigned char tm_type, gfp_t, unsigned int, int); int transport_handle_cdb_direct(struct se_cmd *); @@ -151,7 +151,7 @@ void core_tmr_release_req(struct se_tmr_req *); int transport_generic_handle_tmr(struct se_cmd *); void transport_generic_request_failure(struct se_cmd *, sense_reason_t); void __target_execute_cmd(struct se_cmd *); -int transport_lookup_tmr_lun(struct se_cmd *, u32); +int transport_lookup_tmr_lun(struct se_cmd *, u64); struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); -- cgit v1.2.3 From 196e2e2aa362850bf45bcb14b9517124b23b921e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 10 Jun 2015 08:41:23 +0200 Subject: target: Remove TARGET_MAX_LUNS_PER_TRANSPORT LUN allocation is now fully dynamic, so there is no need to artificially restrain the number of exported LUNs. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 9 --------- drivers/target/target_core_fabric_configfs.c | 8 -------- drivers/target/target_core_tpg.c | 9 --------- drivers/xen/xen-scsiback.c | 7 ++++--- include/target/target_core_base.h | 3 --- 5 files changed, 4 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 2ea7322c4dd4..ed084023e7d4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -63,9 +63,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) struct se_node_acl *nacl = se_sess->se_node_acl; struct se_dev_entry *deve; - if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return TCM_NON_EXISTENT_LUN; - rcu_read_lock(); deve = target_nacl_find_deve(nacl, unpacked_lun); if (deve) { @@ -156,9 +153,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; unsigned long flags; - if (unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) - return -ENODEV; - rcu_read_lock(); deve = target_nacl_find_deve(nacl, unpacked_lun); if (deve) { @@ -197,9 +191,6 @@ bool target_lun_is_rdonly(struct se_cmd *cmd) struct se_dev_entry *deve; bool ret; - if (cmd->se_lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) - return true; - rcu_read_lock(); deve = target_nacl_find_deve(se_sess->se_node_acl, cmd->orig_fe_lun); ret = (deve && deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 2fd493e416b0..6cfee595f3f2 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -353,14 +353,6 @@ static struct config_group *target_fabric_make_mappedlun( ret = kstrtoull(buf + 4, 0, &mapped_lun); if (ret) goto out; - if (mapped_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("Mapped LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" - "-1: %u for Target Portal Group: %u\n", mapped_lun, - TRANSPORT_MAX_LUNS_PER_TPG-1, - se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg)); - ret = -EINVAL; - goto out; - } lacl = core_dev_init_initiator_node_lun_acl(se_tpg, se_nacl, mapped_lun, &ret); diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index 82ed8a0f3f0e..aa39bc89227b 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -602,15 +602,6 @@ struct se_lun *core_tpg_alloc_lun( { struct se_lun *lun; - if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) { - pr_err("%s LUN: %llu exceeds TRANSPORT_MAX_LUNS_PER_TPG" - "-1: %u for Target Portal Group: %u\n", - tpg->se_tpg_tfo->get_fabric_name(), - unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1, - tpg->se_tpg_tfo->tpg_get_tag(tpg)); - return ERR_PTR(-EOVERFLOW); - } - lun = kzalloc(sizeof(*lun), GFP_KERNEL); if (!lun) { pr_err("Unable to allocate se_lun memory\n"); diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 25144a0ff07c..10d67802a2fb 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -864,7 +864,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, struct list_head *head = &(info->v2p_entry_lists); unsigned long flags; char *lunp; - unsigned int unpacked_lun; + unsigned long long unpacked_lun; struct se_lun *se_lun; struct scsiback_tpg *tpg_entry, *tpg = NULL; char *error = "doesn't exist"; @@ -876,9 +876,10 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, } *lunp = 0; lunp++; - if (kstrtouint(lunp, 10, &unpacked_lun) || unpacked_lun >= TRANSPORT_MAX_LUNS_PER_TPG) { + err = kstrtoull(lunp, 10, &unpacked_lun); + if (err < 0) { pr_err("lun number not valid: %s\n", lunp); - return -EINVAL; + return err; } mutex_lock(&scsiback_mutex); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 836ff8abdf18..8cb612613c10 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -13,9 +13,6 @@ #define TARGET_CORE_MOD_VERSION "v4.1.0" #define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION -/* Maximum Number of LUNs per Target Portal Group */ -/* Don't raise above 511 or REPORT_LUNS needs to handle >1 page */ -#define TRANSPORT_MAX_LUNS_PER_TPG 256 /* * By default we use 32-byte CDBs in TCM Core and subsystem plugin code. * -- cgit v1.2.3 From 316058134ffa0017199b460318e109aa79432cc6 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 11 Jun 2015 10:01:25 +0200 Subject: target: Remove 'ua_nacl' pointer from se_ua structure Unused. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_ua.c | 1 - include/target/target_core_base.h | 1 - 2 files changed, 2 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index e53d4eec2ebc..e5062245171e 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -107,7 +107,6 @@ int core_scsi3_ua_allocate( } INIT_LIST_HEAD(&ua->ua_nacl_list); - ua->ua_nacl = nacl; ua->ua_asc = asc; ua->ua_ascq = ascq; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 8cb612613c10..8a4f861f12b7 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -548,7 +548,6 @@ struct se_cmd { struct se_ua { u8 ua_asc; u8 ua_ascq; - struct se_node_acl *ua_nacl; struct list_head ua_nacl_list; }; -- cgit v1.2.3 From 764ad8ba8cd4c6f836fca9378f8c5121aece0842 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 9 Jun 2015 19:43:56 -0400 Subject: nfs: increase size of EXCHANGE_ID name string buffer The current buffer is much too small if you have a relatively long hostname. Bring it up to the size of the one that SETCLIENTID has. Cc: Reported-by: Michael Skralivetsky Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- include/linux/nfs_xdr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 93ab6071bbe9..e9e9a8dcfb47 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1142,7 +1142,7 @@ struct nfs41_state_protection { struct nfs4_op_map allow; }; -#define NFS4_EXCHANGE_ID_LEN (48) +#define NFS4_EXCHANGE_ID_LEN (127) struct nfs41_exchange_id_args { struct nfs_client *client; nfs4_verifier *verifier; -- cgit v1.2.3 From 3a6bb738792500e8b4534c0350c13a132bac0492 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 9 Jun 2015 19:43:57 -0400 Subject: nfs: convert setclientid and exchange_id encoders to use clp->cl_owner_id ...instead of buffers that are part of their arg structs. We already hold a reference to the client, so we might as well use the allocated buffer. In the event that we can't allocate the clp->cl_owner_id, then just return -ENOMEM. Note too that we switch from a GFP_KERNEL allocation here to GFP_NOFS. It's possible we could end up trying to do a SETCLIENTID or EXCHANGE_ID in order to reclaim some memory, and the GFP_KERNEL allocations in the existing code could cause recursion back into NFS reclaim. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 21 ++++++++++++++++----- fs/nfs/nfs4xdr.c | 8 +++++--- include/linux/nfs_xdr.h | 2 +- 3 files changed, 22 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d689ea37be84..b2afe9556147 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5046,7 +5046,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, struct nfs4_setclientid setclientid = { .sc_verifier = &sc_verifier, .sc_prog = program, - .sc_cb_ident = clp->cl_cb_ident, + .sc_clnt = clp, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], @@ -5076,6 +5076,12 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, nfs4_init_nonuniform_client_string(clp, setclientid.sc_name, sizeof(setclientid.sc_name)); + + if (!clp->cl_owner_id) { + status = -ENOMEM; + goto out; + } + /* cb_client4 */ setclientid.sc_netid_len = nfs4_init_callback_netid(clp, @@ -5085,9 +5091,9 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, sizeof(setclientid.sc_uaddr), "%s.%u.%u", clp->cl_ipaddr, port >> 8, port & 255); - dprintk("NFS call setclientid auth=%s, '%.*s'\n", + dprintk("NFS call setclientid auth=%s, '%s'\n", clp->cl_rpcclient->cl_auth->au_ops->au_name, - setclientid.sc_name_len, setclientid.sc_name); + clp->cl_owner_id); task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) { status = PTR_ERR(task); @@ -6850,9 +6856,14 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, nfs4_init_boot_verifier(clp, &verifier); args.id_len = nfs4_init_uniform_client_string(clp, args.id, sizeof(args.id)); - dprintk("NFS call exchange_id auth=%s, '%.*s'\n", + if (!clp->cl_owner_id) { + status = -ENOMEM; + goto out; + } + + dprintk("NFS call exchange_id auth=%s, '%s'\n", clp->cl_rpcclient->cl_auth->au_ops->au_name, - args.id_len, args.id); + clp->cl_owner_id); res.server_owner = kzalloc(sizeof(struct nfs41_server_owner), GFP_NOFS); diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 0aea97841d30..f58e8a979397 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1667,13 +1667,14 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr); encode_nfs4_verifier(xdr, setclientid->sc_verifier); - encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name); + encode_string(xdr, strlen(setclientid->sc_clnt->cl_owner_id), + setclientid->sc_clnt->cl_owner_id); p = reserve_space(xdr, 4); *p = cpu_to_be32(setclientid->sc_prog); encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid); encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr); p = reserve_space(xdr, 4); - *p = cpu_to_be32(setclientid->sc_cb_ident); + *p = cpu_to_be32(setclientid->sc_clnt->cl_cb_ident); } static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr) @@ -1747,7 +1748,8 @@ static void encode_exchange_id(struct xdr_stream *xdr, encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr); encode_nfs4_verifier(xdr, args->verifier); - encode_string(xdr, args->id_len, args->id); + encode_string(xdr, strlen(args->client->cl_owner_id), + args->client->cl_owner_id); encode_uint32(xdr, args->flags); encode_uint32(xdr, args->state_protect.how); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index e9e9a8dcfb47..6c0b423d781b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -994,7 +994,7 @@ struct nfs4_setclientid { char sc_netid[RPCBIND_MAXNETIDLEN + 1]; unsigned int sc_uaddr_len; char sc_uaddr[RPCBIND_MAXUADDRLEN + 1]; - u32 sc_cb_ident; + struct nfs_client *sc_clnt; struct rpc_cred *sc_cred; }; -- cgit v1.2.3 From 873e385116b2cc5c7daca8f51881371fadb90970 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 9 Jun 2015 19:44:00 -0400 Subject: nfs: make nfs4_init_uniform_client_string use a dynamically allocated buffer Change the uniform client string generator to dynamically allocate the NFSv4 client name string buffer. With this patch, we can eliminate the buffers that are embedded within the "args" structs and simply use the name string that is hanging off the client. This uniform string case is a little simpler than the nonuniform since we don't need to deal with RCU, but we do have two different cases, depending on whether there is a uniquifier or not. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 112 +++++++++++++++++++++++++++++++++--------------- include/linux/nfs_xdr.h | 6 --- 2 files changed, 77 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c20322636a68..d181090124db 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5007,28 +5007,78 @@ retry: return 0; } -static unsigned int -nfs4_init_uniform_client_string(struct nfs_client *clp, - char *buf, size_t len) +static int +nfs4_init_uniquifier_client_string(struct nfs_client *clp) { - const char *nodename = clp->cl_rpcclient->cl_nodename; - unsigned int result; + int result; + size_t len; + char *str; + + len = 10 + 10 + 1 + 10 + 1 + + strlen(nfs4_client_id_uniquifier) + 1 + + strlen(clp->cl_rpcclient->cl_nodename) + 1; + + if (len > NFS4_OPAQUE_LIMIT + 1) + return -EINVAL; + + /* + * Since this string is allocated at mount time, and held until the + * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying + * about a memory-reclaim deadlock. + */ + str = kmalloc(len, GFP_KERNEL); + if (!str) + return -ENOMEM; + + result = scnprintf(str, len, "Linux NFSv%u.%u %s/%s", + clp->rpc_ops->version, clp->cl_minorversion, + nfs4_client_id_uniquifier, + clp->cl_rpcclient->cl_nodename); + if (result >= len) { + kfree(str); + return -EINVAL; + } + clp->cl_owner_id = str; + return 0; +} + +static int +nfs4_init_uniform_client_string(struct nfs_client *clp) +{ + int result; + size_t len; + char *str; if (clp->cl_owner_id != NULL) - return strlcpy(buf, clp->cl_owner_id, len); + return 0; if (nfs4_client_id_uniquifier[0] != '\0') - result = scnprintf(buf, len, "Linux NFSv%u.%u %s/%s", - clp->rpc_ops->version, - clp->cl_minorversion, - nfs4_client_id_uniquifier, - nodename); - else - result = scnprintf(buf, len, "Linux NFSv%u.%u %s", - clp->rpc_ops->version, clp->cl_minorversion, - nodename); - clp->cl_owner_id = kstrdup(buf, GFP_KERNEL); - return result; + return nfs4_init_uniquifier_client_string(clp); + + len = 10 + 10 + 1 + 10 + 1 + + strlen(clp->cl_rpcclient->cl_nodename) + 1; + + if (len > NFS4_OPAQUE_LIMIT + 1) + return -EINVAL; + + /* + * Since this string is allocated at mount time, and held until the + * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying + * about a memory-reclaim deadlock. + */ + str = kmalloc(len, GFP_KERNEL); + if (!str) + return -ENOMEM; + + result = scnprintf(str, len, "Linux NFSv%u.%u %s", + clp->rpc_ops->version, clp->cl_minorversion, + clp->cl_rpcclient->cl_nodename); + if (result >= len) { + kfree(str); + return -EINVAL; + } + clp->cl_owner_id = str; + return 0; } /* @@ -5095,20 +5145,14 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, /* nfs_client_id4 */ nfs4_init_boot_verifier(clp, &sc_verifier); - if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags)) { - setclientid.sc_name_len = - nfs4_init_uniform_client_string(clp, - setclientid.sc_name, - sizeof(setclientid.sc_name)); - if (!clp->cl_owner_id) { - status = -ENOMEM; - goto out; - } - } else { + + if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags)) + status = nfs4_init_uniform_client_string(clp); + else status = nfs4_init_nonuniform_client_string(clp); - if (status) - goto out; - } + + if (status) + goto out; /* cb_client4 */ setclientid.sc_netid_len = @@ -6882,12 +6926,10 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred, }; nfs4_init_boot_verifier(clp, &verifier); - args.id_len = nfs4_init_uniform_client_string(clp, args.id, - sizeof(args.id)); - if (!clp->cl_owner_id) { - status = -ENOMEM; + + status = nfs4_init_uniform_client_string(clp); + if (status) goto out; - } dprintk("NFS call exchange_id auth=%s, '%s'\n", clp->cl_rpcclient->cl_auth->au_ops->au_name, diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 6c0b423d781b..c959e7eb5bd4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -984,11 +984,8 @@ struct nfs4_readlink_res { struct nfs4_sequence_res seq_res; }; -#define NFS4_SETCLIENTID_NAMELEN (127) struct nfs4_setclientid { const nfs4_verifier * sc_verifier; - unsigned int sc_name_len; - char sc_name[NFS4_SETCLIENTID_NAMELEN + 1]; u32 sc_prog; unsigned int sc_netid_len; char sc_netid[RPCBIND_MAXNETIDLEN + 1]; @@ -1142,12 +1139,9 @@ struct nfs41_state_protection { struct nfs4_op_map allow; }; -#define NFS4_EXCHANGE_ID_LEN (127) struct nfs41_exchange_id_args { struct nfs_client *client; nfs4_verifier *verifier; - unsigned int id_len; - char id[NFS4_EXCHANGE_ID_LEN]; u32 flags; struct nfs41_state_protection state_protect; }; -- cgit v1.2.3 From fec47d863587c272d6fbf4e50066209c953d5e60 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Fri, 22 May 2015 15:45:27 -0500 Subject: remoteproc: introduce rproc_get_by_phandle API Allow users of remoteproc the ability to get a handle to an rproc by passing a phandle supplied in the user's device tree node. This is useful in situations that require manual booting of the rproc. This patch uses the code removed by commit 40e575b1d0b3 ("remoteproc: remove the get_by_name/put API") for the ref counting but is modified to use a simple list and locking mechanism and has rproc_get_by_name replaced with an rproc_get_by_phandle API. Signed-off-by: Dave Gerlach Signed-off-by: Suman Anna [fix order of Signed-off-by tags] Signed-off-by: Ohad Ben-Cohen --- Documentation/remoteproc.txt | 6 +++++ drivers/remoteproc/remoteproc_core.c | 50 ++++++++++++++++++++++++++++++++++++ include/linux/remoteproc.h | 7 ++--- 3 files changed, 60 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt index e6469fdcf89a..ef0219fa4bb4 100644 --- a/Documentation/remoteproc.txt +++ b/Documentation/remoteproc.txt @@ -51,6 +51,12 @@ cost. rproc_shutdown() returns, and users can still use it with a subsequent rproc_boot(), if needed. + struct rproc *rproc_get_by_phandle(phandle phandle) + - Find an rproc handle using a device tree phandle. Returns the rproc + handle on success, and NULL on failure. This function increments + the remote processor's refcount, so always use rproc_put() to + decrement it back once rproc isn't needed anymore. + 3. Typical usage #include diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index e991512e04ed..e1a6d693b8bb 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -44,6 +44,9 @@ #include "remoteproc_internal.h" +static DEFINE_MUTEX(rproc_list_mutex); +static LIST_HEAD(rproc_list); + typedef int (*rproc_handle_resources_t)(struct rproc *rproc, struct resource_table *table, int len); typedef int (*rproc_handle_resource_t)(struct rproc *rproc, @@ -1144,6 +1147,43 @@ out: } EXPORT_SYMBOL(rproc_shutdown); +/** + * rproc_get_by_phandle() - find a remote processor by phandle + * @phandle: phandle to the rproc + * + * Finds an rproc handle using the remote processor's phandle, and then + * return a handle to the rproc. + * + * This function increments the remote processor's refcount, so always + * use rproc_put() to decrement it back once rproc isn't needed anymore. + * + * Returns the rproc handle on success, and NULL on failure. + */ +struct rproc *rproc_get_by_phandle(phandle phandle) +{ + struct rproc *rproc = NULL, *r; + struct device_node *np; + + np = of_find_node_by_phandle(phandle); + if (!np) + return NULL; + + mutex_lock(&rproc_list_mutex); + list_for_each_entry(r, &rproc_list, node) { + if (r->dev.parent && r->dev.parent->of_node == np) { + rproc = r; + get_device(&rproc->dev); + break; + } + } + mutex_unlock(&rproc_list_mutex); + + of_node_put(np); + + return rproc; +} +EXPORT_SYMBOL(rproc_get_by_phandle); + /** * rproc_add() - register a remote processor * @rproc: the remote processor handle to register @@ -1173,6 +1213,11 @@ int rproc_add(struct rproc *rproc) if (ret < 0) return ret; + /* expose to rproc_get_by_phandle users */ + mutex_lock(&rproc_list_mutex); + list_add(&rproc->node, &rproc_list); + mutex_unlock(&rproc_list_mutex); + dev_info(dev, "%s is available\n", rproc->name); dev_info(dev, "Note: remoteproc is still under development and considered experimental.\n"); @@ -1360,6 +1405,11 @@ int rproc_del(struct rproc *rproc) /* Free the copy of the resource table */ kfree(rproc->cached_table); + /* the rproc is downref'ed as soon as it's removed from the klist */ + mutex_lock(&rproc_list_mutex); + list_del(&rproc->node); + mutex_unlock(&rproc_list_mutex); + device_del(&rproc->dev); return 0; diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 78b8a9b9d40a..56739e5df1e6 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -36,11 +36,11 @@ #define REMOTEPROC_H #include -#include #include #include #include #include +#include /** * struct resource_table - firmware resource table header @@ -375,7 +375,7 @@ enum rproc_crash_type { /** * struct rproc - represents a physical remote processor device - * @node: klist node of this rproc object + * @node: list node of this rproc object * @domain: iommu domain * @name: human readable name of the rproc * @firmware: name of firmware file to be loaded @@ -407,7 +407,7 @@ enum rproc_crash_type { * @has_iommu: flag to indicate if remote processor is behind an MMU */ struct rproc { - struct klist_node node; + struct list_head node; struct iommu_domain *domain; const char *name; const char *firmware; @@ -481,6 +481,7 @@ struct rproc_vdev { u32 rsc_offset; }; +struct rproc *rproc_get_by_phandle(phandle phandle); struct rproc *rproc_alloc(struct device *dev, const char *name, const struct rproc_ops *ops, const char *firmware, int len); -- cgit v1.2.3 From a01f7cd657c95941079d548ef7fbf0cc370c1259 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Fri, 22 May 2015 15:45:28 -0500 Subject: remoteproc: add a rproc ops for performing address translation The rproc_da_to_va API is currently used to perform any device to kernel address translations to meet the different needs of the remoteproc core/drivers (eg: loading). The functionality is achieved within the remoteproc core, and is limited only for carveouts allocated within the core. A new rproc ops, da_to_va, is added to provide flexibility to platform implementations to perform the address translation themselves when the above conditions cannot be met by the implementations. The rproc_da_to_va() API is extended to invoke this ops if present, and fallback to regular processing if the platform implementation cannot provide the translation. This will allow any remoteproc implementations to translate addresses for dedicated memories like internal memories. While at this, also update the rproc_da_to_va() documentation since it is an exported function. Signed-off-by: Suman Anna Signed-off-by: Dave Gerlach Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/remoteproc_core.c | 31 +++++++++++++++++++++++++------ include/linux/remoteproc.h | 2 ++ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index e1a6d693b8bb..b4ab38015cf2 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -137,28 +137,46 @@ static void rproc_disable_iommu(struct rproc *rproc) iommu_domain_free(domain); } -/* +/** + * rproc_da_to_va() - lookup the kernel virtual address for a remoteproc address + * @rproc: handle of a remote processor + * @da: remoteproc device address to translate + * @len: length of the memory region @da is pointing to + * * Some remote processors will ask us to allocate them physically contiguous * memory regions (which we call "carveouts"), and map them to specific - * device addresses (which are hardcoded in the firmware). + * device addresses (which are hardcoded in the firmware). They may also have + * dedicated memory regions internal to the processors, and use them either + * exclusively or alongside carveouts. * * They may then ask us to copy objects into specific device addresses (e.g. * code/data sections) or expose us certain symbols in other device address * (e.g. their trace buffer). * - * This function is an internal helper with which we can go over the allocated - * carveouts and translate specific device address to kernel virtual addresses - * so we can access the referenced memory. + * This function is a helper function with which we can go over the allocated + * carveouts and translate specific device addresses to kernel virtual addresses + * so we can access the referenced memory. This function also allows to perform + * translations on the internal remoteproc memory regions through a platform + * implementation specific da_to_va ops, if present. + * + * The function returns a valid kernel address on success or NULL on failure. * * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too, * but only on kernel direct mapped RAM memory. Instead, we're just using - * here the output of the DMA API, which should be more correct. + * here the output of the DMA API for the carveouts, which should be more + * correct. */ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) { struct rproc_mem_entry *carveout; void *ptr = NULL; + if (rproc->ops->da_to_va) { + ptr = rproc->ops->da_to_va(rproc, da, len); + if (ptr) + goto out; + } + list_for_each_entry(carveout, &rproc->carveouts, node) { int offset = da - carveout->da; @@ -175,6 +193,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, int len) break; } +out: return ptr; } EXPORT_SYMBOL(rproc_da_to_va); diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 56739e5df1e6..9c4e1384f636 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -330,11 +330,13 @@ struct rproc; * @start: power on the device and boot it * @stop: power off the device * @kick: kick a virtqueue (virtqueue id given as a parameter) + * @da_to_va: optional platform hook to perform address translations */ struct rproc_ops { int (*start)(struct rproc *rproc); int (*stop)(struct rproc *rproc); void (*kick)(struct rproc *rproc, int vqid); + void * (*da_to_va)(struct rproc *rproc, u64 da, int len); }; /** -- cgit v1.2.3 From a01bc0d5f557bd8becd0ba75d09c39192004697e Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Fri, 22 May 2015 15:45:30 -0500 Subject: remoteproc/wkup_m3: add a remoteproc driver for TI Wakeup M3 Add a remoteproc driver to load the firmware and boot a small Wakeup M3 processor present on TI AM33xx and AM43xx SoCs. This Wakeup M3 remote processor is an integrated Cortex M3 that allows the SoC to enter the lowest possible power state by taking control from the MPU after it has gone into its own low power state and shutting off any additional peripherals. The Wakeup M3 processor has two internal memory regions - 16 kB of unified instruction memory called UMEM used to store executable code, and 8 kB of data memory called DMEM used for all data sections. The Wakeup M3 processor executes its code entirely from within the UMEM and uses the DMEM for any data. It does not use any external memory or any other external resources. The device address view has the UMEM at address 0x0 and DMEM at address 0x80000, and these are computed automatically within the driver based on relative address calculation from the corresponding device tree IOMEM resources. These device addresses are used to aid the core remoteproc ELF loader code to properly translate and load the firmware segments through the .rproc_da_to_va ops. Signed-off-by: Dave Gerlach Signed-off-by: Suman Anna Signed-off-by: Ohad Ben-Cohen --- drivers/remoteproc/Kconfig | 13 ++ drivers/remoteproc/Makefile | 1 + drivers/remoteproc/wkup_m3_rproc.c | 257 ++++++++++++++++++++++++++++++++++ include/linux/platform_data/wkup_m3.h | 30 ++++ 4 files changed, 301 insertions(+) create mode 100644 drivers/remoteproc/wkup_m3_rproc.c create mode 100644 include/linux/platform_data/wkup_m3.h (limited to 'include') diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 5e343bab9458..28c711f0ac6b 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -41,6 +41,19 @@ config STE_MODEM_RPROC This can be either built-in or a loadable module. If unsure say N. +config WKUP_M3_RPROC + tristate "AMx3xx Wakeup M3 remoteproc support" + depends on SOC_AM33XX || SOC_AM43XX + select REMOTEPROC + help + Say y here to support Wakeup M3 remote processor on TI AM33xx + and AM43xx family of SoCs. + + Required for Suspend-to-RAM on AM33xx and AM43xx SoCs. Also needed + for deep CPUIdle states on AM33xx SoCs. Allows for loading of the + firmware onto these remote processors. + If unsure say N. + config DA8XX_REMOTEPROC tristate "DA8xx/OMAP-L13x remoteproc support" depends on ARCH_DAVINCI_DA8XX diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index ac2ff75686d2..81b04d1e2e58 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -9,4 +9,5 @@ remoteproc-y += remoteproc_virtio.o remoteproc-y += remoteproc_elf_loader.o obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_STE_MODEM_RPROC) += ste_modem_rproc.o +obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c new file mode 100644 index 000000000000..edf81819cce1 --- /dev/null +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -0,0 +1,257 @@ +/* + * TI AMx3 Wakeup M3 Remote Processor driver + * + * Copyright (C) 2014-2015 Texas Instruments, Inc. + * + * Dave Gerlach + * Suman Anna + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "remoteproc_internal.h" + +#define WKUPM3_MEM_MAX 2 + +/** + * struct wkup_m3_mem - WkupM3 internal memory structure + * @cpu_addr: MPU virtual address of the memory region + * @bus_addr: Bus address used to access the memory region + * @dev_addr: Device address from Wakeup M3 view + * @size: Size of the memory region + */ +struct wkup_m3_mem { + void __iomem *cpu_addr; + phys_addr_t bus_addr; + u32 dev_addr; + size_t size; +}; + +/** + * struct wkup_m3_rproc - WkupM3 remote processor state + * @rproc: rproc handle + * @pdev: pointer to platform device + * @mem: WkupM3 memory information + */ +struct wkup_m3_rproc { + struct rproc *rproc; + struct platform_device *pdev; + struct wkup_m3_mem mem[WKUPM3_MEM_MAX]; +}; + +static int wkup_m3_rproc_start(struct rproc *rproc) +{ + struct wkup_m3_rproc *wkupm3 = rproc->priv; + struct platform_device *pdev = wkupm3->pdev; + struct device *dev = &pdev->dev; + struct wkup_m3_platform_data *pdata = dev_get_platdata(dev); + + if (pdata->deassert_reset(pdev, pdata->reset_name)) { + dev_err(dev, "Unable to reset wkup_m3!\n"); + return -ENODEV; + } + + return 0; +} + +static int wkup_m3_rproc_stop(struct rproc *rproc) +{ + struct wkup_m3_rproc *wkupm3 = rproc->priv; + struct platform_device *pdev = wkupm3->pdev; + struct device *dev = &pdev->dev; + struct wkup_m3_platform_data *pdata = dev_get_platdata(dev); + + if (pdata->assert_reset(pdev, pdata->reset_name)) { + dev_err(dev, "Unable to assert reset of wkup_m3!\n"); + return -ENODEV; + } + + return 0; +} + +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len) +{ + struct wkup_m3_rproc *wkupm3 = rproc->priv; + void *va = NULL; + int i; + u32 offset; + + if (len <= 0) + return NULL; + + for (i = 0; i < WKUPM3_MEM_MAX; i++) { + if (da >= wkupm3->mem[i].dev_addr && da + len <= + wkupm3->mem[i].dev_addr + wkupm3->mem[i].size) { + offset = da - wkupm3->mem[i].dev_addr; + /* __force to make sparse happy with type conversion */ + va = (__force void *)(wkupm3->mem[i].cpu_addr + offset); + break; + } + } + + return va; +} + +static struct rproc_ops wkup_m3_rproc_ops = { + .start = wkup_m3_rproc_start, + .stop = wkup_m3_rproc_stop, + .da_to_va = wkup_m3_rproc_da_to_va, +}; + +static const struct of_device_id wkup_m3_rproc_of_match[] = { + { .compatible = "ti,am3352-wkup-m3", }, + { .compatible = "ti,am4372-wkup-m3", }, + {}, +}; + +static int wkup_m3_rproc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wkup_m3_platform_data *pdata = dev->platform_data; + /* umem always needs to be processed first */ + const char *mem_names[WKUPM3_MEM_MAX] = { "umem", "dmem" }; + struct wkup_m3_rproc *wkupm3; + const char *fw_name; + struct rproc *rproc; + struct resource *res; + const __be32 *addrp; + u32 l4_offset = 0; + u64 size; + int ret; + int i; + + if (!(pdata && pdata->deassert_reset && pdata->assert_reset && + pdata->reset_name)) { + dev_err(dev, "Platform data missing!\n"); + return -ENODEV; + } + + ret = of_property_read_string(dev->of_node, "ti,pm-firmware", + &fw_name); + if (ret) { + dev_err(dev, "No firmware filename given\n"); + return -ENODEV; + } + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); + goto err; + } + + rproc = rproc_alloc(dev, "wkup_m3", &wkup_m3_rproc_ops, + fw_name, sizeof(*wkupm3)); + if (!rproc) { + ret = -ENOMEM; + goto err; + } + + wkupm3 = rproc->priv; + wkupm3->rproc = rproc; + wkupm3->pdev = pdev; + + for (i = 0; i < ARRAY_SIZE(mem_names); i++) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + mem_names[i]); + wkupm3->mem[i].cpu_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(wkupm3->mem[i].cpu_addr)) { + dev_err(&pdev->dev, "devm_ioremap_resource failed for resource %d\n", + i); + ret = PTR_ERR(wkupm3->mem[i].cpu_addr); + goto err; + } + wkupm3->mem[i].bus_addr = res->start; + wkupm3->mem[i].size = resource_size(res); + addrp = of_get_address(dev->of_node, i, &size, NULL); + /* + * The wkupm3 has umem at address 0 in its view, so the device + * addresses for each memory region is computed as a relative + * offset of the bus address for umem, and therefore needs to be + * processed first. + */ + if (!strcmp(mem_names[i], "umem")) + l4_offset = be32_to_cpu(*addrp); + wkupm3->mem[i].dev_addr = be32_to_cpu(*addrp) - l4_offset; + } + + dev_set_drvdata(dev, rproc); + + ret = rproc_add(rproc); + if (ret) { + dev_err(dev, "rproc_add failed\n"); + goto err_put_rproc; + } + + return 0; + +err_put_rproc: + rproc_put(rproc); +err: + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + return ret; +} + +static int wkup_m3_rproc_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + + rproc_del(rproc); + rproc_put(rproc); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int wkup_m3_rpm_suspend(struct device *dev) +{ + return -EBUSY; +} + +static int wkup_m3_rpm_resume(struct device *dev) +{ + return 0; +} +#endif + +static const struct dev_pm_ops wkup_m3_rproc_pm_ops = { + SET_RUNTIME_PM_OPS(wkup_m3_rpm_suspend, wkup_m3_rpm_resume, NULL) +}; + +static struct platform_driver wkup_m3_rproc_driver = { + .probe = wkup_m3_rproc_probe, + .remove = wkup_m3_rproc_remove, + .driver = { + .name = "wkup_m3_rproc", + .of_match_table = wkup_m3_rproc_of_match, + .pm = &wkup_m3_rproc_pm_ops, + }, +}; + +module_platform_driver(wkup_m3_rproc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI Wakeup M3 remote processor control driver"); +MODULE_AUTHOR("Dave Gerlach "); diff --git a/include/linux/platform_data/wkup_m3.h b/include/linux/platform_data/wkup_m3.h new file mode 100644 index 000000000000..3f1d77effd71 --- /dev/null +++ b/include/linux/platform_data/wkup_m3.h @@ -0,0 +1,30 @@ +/* + * TI Wakeup M3 remote processor platform data + * + * Copyright (C) 2014-2015 Texas Instruments, Inc. + * + * Dave Gerlach + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_PLATFORM_DATA_WKUP_M3_H +#define _LINUX_PLATFORM_DATA_WKUP_M3_H + +struct platform_device; + +struct wkup_m3_platform_data { + const char *reset_name; + + int (*assert_reset)(struct platform_device *pdev, const char *name); + int (*deassert_reset)(struct platform_device *pdev, const char *name); +}; + +#endif /* _LINUX_PLATFORM_DATA_WKUP_M3_H */ -- cgit v1.2.3 From 4bacc9c9234c7c8eec44f5ed4e960d9f96fa0f01 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 18 Jun 2015 14:32:31 +0100 Subject: overlayfs: Make f_path always point to the overlay and f_inode to the underlay Make file->f_path always point to the overlay dentry so that the path in /proc/pid/fd is correct and to ensure that label-based LSMs have access to the overlay as well as the underlay (path-based LSMs probably don't need it). Using my union testsuite to set things up, before the patch I see: [root@andromeda union-testsuite]# bash 5 /a/foo107 [root@andromeda union-testsuite]# stat /mnt/a/foo107 ... Device: 23h/35d Inode: 13381 Links: 1 ... [root@andromeda union-testsuite]# stat -L /proc/$$/fd/5 ... Device: 23h/35d Inode: 13381 Links: 1 ... After the patch: [root@andromeda union-testsuite]# bash 5 /mnt/a/foo107 [root@andromeda union-testsuite]# stat /mnt/a/foo107 ... Device: 23h/35d Inode: 40346 Links: 1 ... [root@andromeda union-testsuite]# stat -L /proc/$$/fd/5 ... Device: 23h/35d Inode: 40346 Links: 1 ... Note the change in where /proc/$$/fd/5 points to in the ls command. It was pointing to /a/foo107 (which doesn't exist) and now points to /mnt/a/foo107 (which is correct). The inode accessed, however, is the lower layer. The union layer is on device 25h/37d and the upper layer on 24h/36d. Signed-off-by: David Howells Signed-off-by: Al Viro --- fs/dcache.c | 5 ++++- fs/internal.h | 1 + fs/open.c | 49 +++++++++++++++++++++++++----------------------- fs/overlayfs/inode.c | 14 ++++++-------- fs/overlayfs/overlayfs.h | 1 + fs/overlayfs/super.c | 1 + include/linux/dcache.h | 2 ++ include/linux/fs.h | 2 -- 8 files changed, 41 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/fs/dcache.c b/fs/dcache.c index 37b5afdaf698..c4ce35110704 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1673,7 +1673,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) DCACHE_OP_COMPARE | DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE | - DCACHE_OP_DELETE )); + DCACHE_OP_DELETE | + DCACHE_OP_SELECT_INODE)); dentry->d_op = op; if (!op) return; @@ -1689,6 +1690,8 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) dentry->d_flags |= DCACHE_OP_DELETE; if (op->d_prune) dentry->d_flags |= DCACHE_OP_PRUNE; + if (op->d_select_inode) + dentry->d_flags |= DCACHE_OP_SELECT_INODE; } EXPORT_SYMBOL(d_set_d_op); diff --git a/fs/internal.h b/fs/internal.h index 01dce1d1476b..4d5af583ab03 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -107,6 +107,7 @@ extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, extern long do_handle_open(int mountdirfd, struct file_handle __user *ufh, int open_flag); extern int open_check_o_direct(struct file *f); +extern int vfs_open(const struct path *, struct file *, const struct cred *); /* * inode.c diff --git a/fs/open.c b/fs/open.c index e0250bdcc440..b1c5823b7f11 100644 --- a/fs/open.c +++ b/fs/open.c @@ -678,18 +678,18 @@ int open_check_o_direct(struct file *f) } static int do_dentry_open(struct file *f, + struct inode *inode, int (*open)(struct inode *, struct file *), const struct cred *cred) { static const struct file_operations empty_fops = {}; - struct inode *inode; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; path_get(&f->f_path); - inode = f->f_inode = f->f_path.dentry->d_inode; + f->f_inode = inode; f->f_mapping = inode->i_mapping; if (unlikely(f->f_flags & O_PATH)) { @@ -793,7 +793,8 @@ int finish_open(struct file *file, struct dentry *dentry, BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ file->f_path.dentry = dentry; - error = do_dentry_open(file, open, current_cred()); + error = do_dentry_open(file, d_backing_inode(dentry), open, + current_cred()); if (!error) *opened |= FILE_OPENED; @@ -822,6 +823,28 @@ int finish_no_open(struct file *file, struct dentry *dentry) } EXPORT_SYMBOL(finish_no_open); +/** + * vfs_open - open the file at the given path + * @path: path to open + * @file: newly allocated file with f_flag initialized + * @cred: credentials to use + */ +int vfs_open(const struct path *path, struct file *file, + const struct cred *cred) +{ + struct dentry *dentry = path->dentry; + struct inode *inode = dentry->d_inode; + + file->f_path = *path; + if (dentry->d_flags & DCACHE_OP_SELECT_INODE) { + inode = dentry->d_op->d_select_inode(dentry, file->f_flags); + if (IS_ERR(inode)) + return PTR_ERR(inode); + } + + return do_dentry_open(file, inode, NULL, cred); +} + struct file *dentry_open(const struct path *path, int flags, const struct cred *cred) { @@ -853,26 +876,6 @@ struct file *dentry_open(const struct path *path, int flags, } EXPORT_SYMBOL(dentry_open); -/** - * vfs_open - open the file at the given path - * @path: path to open - * @filp: newly allocated file with f_flag initialized - * @cred: credentials to use - */ -int vfs_open(const struct path *path, struct file *filp, - const struct cred *cred) -{ - struct inode *inode = path->dentry->d_inode; - - if (inode->i_op->dentry_open) - return inode->i_op->dentry_open(path->dentry, filp, cred); - else { - filp->f_path = *path; - return do_dentry_open(filp, NULL, cred); - } -} -EXPORT_SYMBOL(vfs_open); - static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) { int lookup_flags = 0; diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 21079d1ca2aa..f140e3dbfb7b 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -337,31 +337,30 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, return true; } -static int ovl_dentry_open(struct dentry *dentry, struct file *file, - const struct cred *cred) +struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) { int err; struct path realpath; enum ovl_path_type type; type = ovl_path_real(dentry, &realpath); - if (ovl_open_need_copy_up(file->f_flags, type, realpath.dentry)) { + if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { err = ovl_want_write(dentry); if (err) - return err; + return ERR_PTR(err); - if (file->f_flags & O_TRUNC) + if (file_flags & O_TRUNC) err = ovl_copy_up_last(dentry, NULL, true); else err = ovl_copy_up(dentry); ovl_drop_write(dentry); if (err) - return err; + return ERR_PTR(err); ovl_path_upper(dentry, &realpath); } - return vfs_open(&realpath, file, cred); + return d_backing_inode(realpath.dentry); } static const struct inode_operations ovl_file_inode_operations = { @@ -372,7 +371,6 @@ static const struct inode_operations ovl_file_inode_operations = { .getxattr = ovl_getxattr, .listxattr = ovl_listxattr, .removexattr = ovl_removexattr, - .dentry_open = ovl_dentry_open, }; static const struct inode_operations ovl_symlink_inode_operations = { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 17ac5afc9ffb..ea5a40b06e3a 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -173,6 +173,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, const char *name, void *value, size_t size); ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); int ovl_removexattr(struct dentry *dentry, const char *name); +struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags); struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, struct ovl_entry *oe); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5f0d1993e6e3..84c5e27fbfd9 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -275,6 +275,7 @@ static void ovl_dentry_release(struct dentry *dentry) static const struct dentry_operations ovl_dentry_operations = { .d_release = ovl_dentry_release, + .d_select_inode = ovl_d_select_inode, }; static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) diff --git a/include/linux/dcache.h b/include/linux/dcache.h index df334cbacc6d..167ec0934049 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -160,6 +160,7 @@ struct dentry_operations { char *(*d_dname)(struct dentry *, char *, int); struct vfsmount *(*d_automount)(struct path *); int (*d_manage)(struct dentry *, bool); + struct inode *(*d_select_inode)(struct dentry *, unsigned); } ____cacheline_aligned; /* @@ -225,6 +226,7 @@ struct dentry_operations { #define DCACHE_MAY_FREE 0x00800000 #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ +#define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ extern seqlock_t rename_lock; diff --git a/include/linux/fs.h b/include/linux/fs.h index b577e801b4af..2bd77e10e8e5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1641,7 +1641,6 @@ struct inode_operations { int (*set_acl)(struct inode *, struct posix_acl *, int); /* WARNING: probably going away soon, do not use! */ - int (*dentry_open)(struct dentry *, struct file *, const struct cred *); } ____cacheline_aligned; ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, @@ -2194,7 +2193,6 @@ extern struct file *file_open_name(struct filename *, int, umode_t); extern struct file *filp_open(const char *, int, umode_t); extern struct file *file_open_root(struct dentry *, struct vfsmount *, const char *, int); -extern int vfs_open(const struct path *, struct file *, const struct cred *); extern struct file * dentry_open(const struct path *, int, const struct cred *); extern int filp_close(struct file *, fl_owner_t id); -- cgit v1.2.3 From 7a971b1b3055f0e76ff09b8fd0dd809ea3b48279 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:10:58 +0200 Subject: target: replace se_cmd->execute_rw with a protocol_data field Instead of leaking this SBC read/write implementation detail just add an opaqueue protocol specific pointer to struct se_cmd that we can assign the sbc_ops vector to. Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 20 +++++++------------- include/target/target_core_base.h | 3 +-- 2 files changed, 8 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 31b2ae356120..287843e19275 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -381,7 +381,9 @@ out: static sense_reason_t sbc_execute_rw(struct se_cmd *cmd) { - return cmd->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents, + struct sbc_ops *ops = cmd->protocol_data; + + return ops->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents, cmd->data_direction); } @@ -560,6 +562,7 @@ out: static sense_reason_t sbc_compare_and_write(struct se_cmd *cmd) { + struct sbc_ops *ops = cmd->protocol_data; struct se_device *dev = cmd->se_dev; sense_reason_t ret; int rc; @@ -579,7 +582,7 @@ sbc_compare_and_write(struct se_cmd *cmd) */ cmd->data_length = cmd->t_task_nolb * dev->dev_attrib.block_size; - ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents, + ret = ops->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents, DMA_FROM_DEVICE); if (ret) { cmd->transport_complete_callback = NULL; @@ -766,12 +769,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) u32 sectors = 0; sense_reason_t ret; + cmd->protocol_data = ops; + switch (cdb[0]) { case READ_6: sectors = transport_get_sectors_6(cdb); cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case READ_10: @@ -786,7 +790,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case READ_12: @@ -801,7 +804,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case READ_16: @@ -816,14 +818,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_6: sectors = transport_get_sectors_6(cdb); cmd->t_task_lba = transport_lba_21(cdb); cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_10: @@ -839,7 +839,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_12: @@ -854,7 +853,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case WRITE_16: @@ -869,7 +867,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return ret; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; break; case XDWRITEREAD_10: @@ -887,7 +884,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) /* * Setup BIDI XOR callback to be run after I/O completion. */ - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; break; @@ -911,7 +907,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) * Setup BIDI XOR callback to be run during after I/O * completion. */ - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_execute_rw; cmd->transport_complete_callback = &xdreadwrite_callback; break; @@ -955,7 +950,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) cmd->t_task_lba = get_unaligned_be64(&cdb[2]); cmd->t_task_nolb = sectors; cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB | SCF_COMPARE_AND_WRITE; - cmd->execute_rw = ops->execute_rw; cmd->execute_cmd = sbc_compare_and_write; cmd->transport_complete_callback = compare_and_write_callback; break; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 8a4f861f12b7..273818403a3e 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -490,9 +490,8 @@ struct se_cmd { struct kref cmd_kref; const struct target_core_fabric_ops *se_tfo; sense_reason_t (*execute_cmd)(struct se_cmd *); - sense_reason_t (*execute_rw)(struct se_cmd *, struct scatterlist *, - u32, enum dma_data_direction); sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool); + void *protocol_data; unsigned char *t_task_cdb; unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE]; -- cgit v1.2.3 From 62e4694256dd3cbe301ebc0da799df8779b97014 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:10:59 +0200 Subject: target: simplify UNMAP handling Move a little more processing into the core code, and lift the previous do_unmap callback into the sbc_ops structure. Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 17 +++-------------- drivers/target/target_core_iblock.c | 16 +++------------- drivers/target/target_core_sbc.c | 14 ++++++-------- include/target/target_core_backend.h | 7 ++----- 4 files changed, 14 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 238e3a256d04..ced8c4fdc23d 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -475,9 +475,9 @@ fd_do_prot_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) } static sense_reason_t -fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) +fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) { - struct file *file = priv; + struct file *file = FD_DEV(cmd->se_dev)->fd_file; struct inode *inode = file->f_mapping->host; int ret; @@ -521,9 +521,6 @@ fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) static sense_reason_t fd_execute_write_same_unmap(struct se_cmd *cmd) { - struct se_device *se_dev = cmd->se_dev; - struct fd_dev *fd_dev = FD_DEV(se_dev); - struct file *file = fd_dev->fd_file; sector_t lba = cmd->t_task_lba; sector_t nolb = sbc_get_write_same_sectors(cmd); sense_reason_t ret; @@ -533,7 +530,7 @@ fd_execute_write_same_unmap(struct se_cmd *cmd) return 0; } - ret = fd_do_unmap(cmd, file, lba, nolb); + ret = fd_execute_unmap(cmd, lba, nolb); if (ret) return ret; @@ -541,14 +538,6 @@ fd_execute_write_same_unmap(struct se_cmd *cmd) return 0; } -static sense_reason_t -fd_execute_unmap(struct se_cmd *cmd) -{ - struct file *file = FD_DEV(cmd->se_dev)->fd_file; - - return sbc_execute_unmap(cmd, fd_do_unmap, file); -} - static sense_reason_t fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index ae8ad2da6632..0a2308891c81 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -416,10 +416,9 @@ iblock_execute_sync_cache(struct se_cmd *cmd) } static sense_reason_t -iblock_do_unmap(struct se_cmd *cmd, void *priv, - sector_t lba, sector_t nolb) +iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) { - struct block_device *bdev = priv; + struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; int ret; ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); @@ -431,23 +430,14 @@ iblock_do_unmap(struct se_cmd *cmd, void *priv, return 0; } -static sense_reason_t -iblock_execute_unmap(struct se_cmd *cmd) -{ - struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; - - return sbc_execute_unmap(cmd, iblock_do_unmap, bdev); -} - static sense_reason_t iblock_execute_write_same_unmap(struct se_cmd *cmd) { - struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; sector_t lba = cmd->t_task_lba; sector_t nolb = sbc_get_write_same_sectors(cmd); sense_reason_t ret; - ret = iblock_do_unmap(cmd, bdev, lba, nolb); + ret = iblock_execute_unmap(cmd, lba, nolb); if (ret) return ret; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 287843e19275..c16a66698725 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -38,6 +38,7 @@ static sense_reason_t sbc_check_prot(struct se_device *, struct se_cmd *, unsigned char *, u32, bool); +static sense_reason_t sbc_execute_unmap(struct se_cmd *cmd); static sense_reason_t sbc_emulate_readcapacity(struct se_cmd *cmd) @@ -999,7 +1000,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) return TCM_UNSUPPORTED_SCSI_OPCODE; } size = get_unaligned_be16(&cdb[7]); - cmd->execute_cmd = ops->execute_unmap; + cmd->execute_cmd = sbc_execute_unmap; break; case WRITE_SAME_16: sectors = transport_get_sectors_16(cdb); @@ -1087,12 +1088,10 @@ u32 sbc_get_device_type(struct se_device *dev) } EXPORT_SYMBOL(sbc_get_device_type); -sense_reason_t -sbc_execute_unmap(struct se_cmd *cmd, - sense_reason_t (*do_unmap_fn)(struct se_cmd *, void *, - sector_t, sector_t), - void *priv) +static sense_reason_t +sbc_execute_unmap(struct se_cmd *cmd) { + struct sbc_ops *ops = cmd->protocol_data; struct se_device *dev = cmd->se_dev; unsigned char *buf, *ptr = NULL; sector_t lba; @@ -1156,7 +1155,7 @@ sbc_execute_unmap(struct se_cmd *cmd, goto err; } - ret = do_unmap_fn(cmd, priv, lba, range); + ret = ops->execute_unmap(cmd, lba, range); if (ret) goto err; @@ -1170,7 +1169,6 @@ err: target_complete_cmd(cmd, GOOD); return ret; } -EXPORT_SYMBOL(sbc_execute_unmap); void sbc_dif_generate(struct se_cmd *cmd) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 566c7d27f6d0..ff399369a21a 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -50,7 +50,8 @@ struct sbc_ops { sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd); sense_reason_t (*execute_write_same)(struct se_cmd *cmd); sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd); - sense_reason_t (*execute_unmap)(struct se_cmd *cmd); + sense_reason_t (*execute_unmap)(struct se_cmd *cmd, + sector_t lba, sector_t nolb); }; int transport_backend_register(const struct target_backend_ops *); @@ -68,10 +69,6 @@ sense_reason_t sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops); u32 sbc_get_device_rev(struct se_device *dev); u32 sbc_get_device_type(struct se_device *dev); sector_t sbc_get_write_same_sectors(struct se_cmd *cmd); -sense_reason_t sbc_execute_unmap(struct se_cmd *cmd, - sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv, - sector_t lba, sector_t nolb), - void *priv); void sbc_dif_generate(struct se_cmd *); sense_reason_t sbc_dif_verify(struct se_cmd *, sector_t, unsigned int, unsigned int, struct scatterlist *, int); -- cgit v1.2.3 From b753d643555e548163adfa2de9d75e0257e4b356 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:11:00 +0200 Subject: target: implement WRITE_SAME with UNMAP bit using ->execute_unmap Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 21 --------------------- drivers/target/target_core_iblock.c | 16 ---------------- drivers/target/target_core_sbc.c | 21 +++++++++++++++++++-- include/target/target_core_backend.h | 1 - 4 files changed, 19 insertions(+), 40 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index ced8c4fdc23d..f5da2c1891b5 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -518,26 +518,6 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) return 0; } -static sense_reason_t -fd_execute_write_same_unmap(struct se_cmd *cmd) -{ - sector_t lba = cmd->t_task_lba; - sector_t nolb = sbc_get_write_same_sectors(cmd); - sense_reason_t ret; - - if (!nolb) { - target_complete_cmd(cmd, SAM_STAT_GOOD); - return 0; - } - - ret = fd_execute_unmap(cmd, lba, nolb); - if (ret) - return ret; - - target_complete_cmd(cmd, GOOD); - return 0; -} - static sense_reason_t fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) @@ -827,7 +807,6 @@ static struct sbc_ops fd_sbc_ops = { .execute_rw = fd_execute_rw, .execute_sync_cache = fd_execute_sync_cache, .execute_write_same = fd_execute_write_same, - .execute_write_same_unmap = fd_execute_write_same_unmap, .execute_unmap = fd_execute_unmap, }; diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 0a2308891c81..a869022b136e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -430,21 +430,6 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) return 0; } -static sense_reason_t -iblock_execute_write_same_unmap(struct se_cmd *cmd) -{ - sector_t lba = cmd->t_task_lba; - sector_t nolb = sbc_get_write_same_sectors(cmd); - sense_reason_t ret; - - ret = iblock_execute_unmap(cmd, lba, nolb); - if (ret) - return ret; - - target_complete_cmd(cmd, GOOD); - return 0; -} - static sense_reason_t iblock_execute_write_same(struct se_cmd *cmd) { @@ -836,7 +821,6 @@ static struct sbc_ops iblock_sbc_ops = { .execute_rw = iblock_execute_rw, .execute_sync_cache = iblock_execute_sync_cache, .execute_write_same = iblock_execute_write_same, - .execute_write_same_unmap = iblock_execute_write_same_unmap, .execute_unmap = iblock_execute_unmap, }; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index c16a66698725..9a5e7d094a5d 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -177,6 +177,23 @@ sector_t sbc_get_write_same_sectors(struct se_cmd *cmd) } EXPORT_SYMBOL(sbc_get_write_same_sectors); +static sense_reason_t +sbc_execute_write_same_unmap(struct se_cmd *cmd) +{ + struct sbc_ops *ops = cmd->protocol_data; + sector_t nolb = sbc_get_write_same_sectors(cmd); + sense_reason_t ret; + + if (nolb) { + ret = ops->execute_unmap(cmd, cmd->t_task_lba, nolb); + if (ret) + return ret; + } + + target_complete_cmd(cmd, GOOD); + return 0; +} + static sense_reason_t sbc_emulate_noop(struct se_cmd *cmd) { @@ -300,7 +317,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o * translated into block discard requests within backend code. */ if (flags[0] & 0x08) { - if (!ops->execute_write_same_unmap) + if (!ops->execute_unmap) return TCM_UNSUPPORTED_SCSI_OPCODE; if (!dev->dev_attrib.emulate_tpws) { @@ -308,7 +325,7 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o " has emulate_tpws disabled\n"); return TCM_UNSUPPORTED_SCSI_OPCODE; } - cmd->execute_cmd = ops->execute_write_same_unmap; + cmd->execute_cmd = sbc_execute_write_same_unmap; return 0; } if (!ops->execute_write_same) diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index ff399369a21a..1e5c8f949bae 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -49,7 +49,6 @@ struct sbc_ops { u32, enum dma_data_direction); sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd); sense_reason_t (*execute_write_same)(struct se_cmd *cmd); - sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd); sense_reason_t (*execute_unmap)(struct se_cmd *cmd, sector_t lba, sector_t nolb); }; -- cgit v1.2.3 From ce8dd25d0ebb1d868802e1d1c770f27f2249fae4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:14:39 +0200 Subject: target: consolidate version defines Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 6 +++--- drivers/target/target_core_file.c | 2 +- drivers/target/target_core_iblock.c | 2 +- drivers/target/target_core_pscsi.c | 2 +- drivers/target/target_core_rd.c | 2 +- include/target/target_core_base.h | 3 +-- include/target/target_core_configfs.h | 1 - 7 files changed, 8 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 68addbc7eb7b..6003921a1c56 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -103,7 +103,7 @@ static ssize_t target_core_attr_show(struct config_item *item, char *page) { return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s" - " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION, + " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine); } @@ -3235,7 +3235,7 @@ static ssize_t target_core_hba_show_attr_hba_info( { return sprintf(page, "HBA Index: %d plugin: %s version: %s\n", hba->hba_id, hba->backend->ops->name, - TARGET_CORE_CONFIGFS_VERSION); + TARGET_CORE_VERSION); } SE_HBA_ATTR_RO(hba_info); @@ -3507,7 +3507,7 @@ static int __init target_core_init_configfs(void) goto out_global; } pr_debug("TARGET_CORE[0]: Initialized ConfigFS Fabric" - " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s" + " Infrastructure: "TARGET_CORE_VERSION" on %s/%s" " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine); /* * Register built-in RAMDISK subsystem logic for virtual LUN 0 diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index f5da2c1891b5..7a0ef95b1407 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -61,7 +61,7 @@ static int fd_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic" " Target Core Stack %s\n", hba->hba_id, FD_VERSION, - TARGET_CORE_MOD_VERSION); + TARGET_CORE_VERSION); pr_debug("CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic\n", hba->hba_id, fd_host->fd_host_id); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index a869022b136e..e37db742fdaf 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -57,7 +57,7 @@ static int iblock_attach_hba(struct se_hba *hba, u32 host_id) { pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, - IBLOCK_VERSION, TARGET_CORE_MOD_VERSION); + IBLOCK_VERSION, TARGET_CORE_VERSION); return 0; } diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index c673980ded04..f757178ed414 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -80,7 +80,7 @@ static int pscsi_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM SCSI HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, - PSCSI_VERSION, TARGET_CORE_MOD_VERSION); + PSCSI_VERSION, TARGET_CORE_VERSION); pr_debug("CORE_HBA[%d] - Attached SCSI HBA to Generic\n", hba->hba_id); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index e98432705f39..723c97a25cbc 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -58,7 +58,7 @@ static int rd_attach_hba(struct se_hba *hba, u32 host_id) pr_debug("CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on" " Generic Target Core Stack %s\n", hba->hba_id, - RD_HBA_VERSION, TARGET_CORE_MOD_VERSION); + RD_HBA_VERSION, TARGET_CORE_VERSION); return 0; } diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 273818403a3e..a35303302df3 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -10,8 +10,7 @@ #include #include -#define TARGET_CORE_MOD_VERSION "v4.1.0" -#define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION +#define TARGET_CORE_VERSION "v4.1.0" /* * By default we use 32-byte CDBs in TCM Core and subsystem plugin code. diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index abd063b8b301..4012ed22d783 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -1,4 +1,3 @@ -#define TARGET_CORE_CONFIGFS_VERSION TARGET_CORE_MOD_VERSION #define TARGET_CORE_CONFIG_ROOT "/sys/kernel/config" -- cgit v1.2.3 From 1315c7c7bbea6e0aba49a867400e7b8ccb6a5d16 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:14:40 +0200 Subject: target: remove unused TARGET_CORE_CONFIG_ROOT define Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- include/target/target_core_configfs.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 4012ed22d783..d19dbeeab930 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -1,6 +1,4 @@ -#define TARGET_CORE_CONFIG_ROOT "/sys/kernel/config" - #define TARGET_CORE_NAME_MAX_LEN 64 #define TARGET_FABRIC_NAME_SIZE 32 -- cgit v1.2.3 From 6de2ce5b8cb6ff3562de34ea2584b0e501373f56 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Jun 2015 15:14:41 +0200 Subject: target: remove target_core_configfs.h The remaining defintions are private to the target core and can be merged into target_core_internal.h. Signed-off-by: Christoph Hellwig Reviewed-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_configfs.c | 1 - drivers/target/target_core_fabric_configfs.c | 1 - drivers/target/target_core_internal.h | 34 ++++++++++++++++++++++++++++ drivers/target/target_core_tpg.c | 1 - include/target/target_core_configfs.h | 34 ---------------------------- 5 files changed, 34 insertions(+), 37 deletions(-) delete mode 100644 include/target/target_core_configfs.h (limited to 'include') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 6003921a1c56..0b0de3647478 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include "target_core_internal.h" diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 6cfee595f3f2..48a36989c1a6 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "target_core_internal.h" diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 511178969df3..99c24acfe676 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -1,6 +1,9 @@ #ifndef TARGET_CORE_INTERNAL_H #define TARGET_CORE_INTERNAL_H +#define TARGET_CORE_NAME_MAX_LEN 64 +#define TARGET_FABRIC_NAME_SIZE 32 + struct target_backend { struct list_head list; @@ -14,6 +17,37 @@ struct target_backend { struct config_item_type tb_dev_stat_cit; }; +struct target_fabric_configfs { + atomic_t tf_access_cnt; + struct list_head tf_list; + struct config_group tf_group; + struct config_group tf_disc_group; + struct config_group *tf_default_groups[2]; + const struct target_core_fabric_ops *tf_ops; + + struct config_item_type tf_discovery_cit; + struct config_item_type tf_wwn_cit; + struct config_item_type tf_wwn_fabric_stats_cit; + struct config_item_type tf_tpg_cit; + struct config_item_type tf_tpg_base_cit; + struct config_item_type tf_tpg_lun_cit; + struct config_item_type tf_tpg_port_cit; + struct config_item_type tf_tpg_port_stat_cit; + struct config_item_type tf_tpg_np_cit; + struct config_item_type tf_tpg_np_base_cit; + struct config_item_type tf_tpg_attrib_cit; + struct config_item_type tf_tpg_auth_cit; + struct config_item_type tf_tpg_param_cit; + struct config_item_type tf_tpg_nacl_cit; + struct config_item_type tf_tpg_nacl_base_cit; + struct config_item_type tf_tpg_nacl_attrib_cit; + struct config_item_type tf_tpg_nacl_auth_cit; + struct config_item_type tf_tpg_nacl_param_cit; + struct config_item_type tf_tpg_nacl_stat_cit; + struct config_item_type tf_tpg_mappedlun_cit; + struct config_item_type tf_tpg_mappedlun_stat_cit; +}; + /* target_core_alua.c */ extern struct t10_alua_lu_gp *default_lu_gp; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index aa39bc89227b..10321a8ffbb0 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -37,7 +37,6 @@ #include #include -#include #include #include "target_core_internal.h" diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h deleted file mode 100644 index d19dbeeab930..000000000000 --- a/include/target/target_core_configfs.h +++ /dev/null @@ -1,34 +0,0 @@ - -#define TARGET_CORE_NAME_MAX_LEN 64 -#define TARGET_FABRIC_NAME_SIZE 32 - -struct target_fabric_configfs { - atomic_t tf_access_cnt; - struct list_head tf_list; - struct config_group tf_group; - struct config_group tf_disc_group; - struct config_group *tf_default_groups[2]; - const struct target_core_fabric_ops *tf_ops; - - struct config_item_type tf_discovery_cit; - struct config_item_type tf_wwn_cit; - struct config_item_type tf_wwn_fabric_stats_cit; - struct config_item_type tf_tpg_cit; - struct config_item_type tf_tpg_base_cit; - struct config_item_type tf_tpg_lun_cit; - struct config_item_type tf_tpg_port_cit; - struct config_item_type tf_tpg_port_stat_cit; - struct config_item_type tf_tpg_np_cit; - struct config_item_type tf_tpg_np_base_cit; - struct config_item_type tf_tpg_attrib_cit; - struct config_item_type tf_tpg_auth_cit; - struct config_item_type tf_tpg_param_cit; - struct config_item_type tf_tpg_nacl_cit; - struct config_item_type tf_tpg_nacl_base_cit; - struct config_item_type tf_tpg_nacl_attrib_cit; - struct config_item_type tf_tpg_nacl_auth_cit; - struct config_item_type tf_tpg_nacl_param_cit; - struct config_item_type tf_tpg_nacl_stat_cit; - struct config_item_type tf_tpg_mappedlun_cit; - struct config_item_type tf_tpg_mappedlun_stat_cit; -}; -- cgit v1.2.3 From 2ec1e9e20701f37a06562966dbd37e7dd072fcb8 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 23 Jun 2015 00:45:14 -0700 Subject: target: Bump core version to v5.0 Signed-off-by: Nicholas Bellinger --- include/target/target_core_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index a35303302df3..0b9a331e5492 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -10,7 +10,7 @@ #include #include -#define TARGET_CORE_VERSION "v4.1.0" +#define TARGET_CORE_VERSION "v5.0" /* * By default we use 32-byte CDBs in TCM Core and subsystem plugin code. -- cgit v1.2.3 From 52c1d8038594ffd82a6cf88d3dc0ca68d8179a36 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 19 Jun 2015 11:38:16 +0800 Subject: ACPICA: Linuxize: Reduce divergences for 20150616 release This patch reduces source code differences between the Linux kernel and the ACPICA upstream so that the linuxized ACPICA 20150616 release can be applied with reduced human intervention. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsobject.c | 2 +- drivers/acpi/acpica/hwxfsleep.c | 2 -- drivers/acpi/acpica/rscreate.c | 2 +- drivers/acpi/acpica/rsutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 1 + include/acpi/platform/acenv.h | 1 - 6 files changed, 4 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 8a7b07b6adc8..4a4b2f343713 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -751,7 +751,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, obj_desc->string.pointer = op->common.value.string; obj_desc->string.length = - (u32) ACPI_STRLEN(op->common.value.string); + (u32)ACPI_STRLEN(op->common.value.string); /* * The string is contained in the ACPI table, don't ever try diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 3b3767698827..82e310b94ae4 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -138,7 +138,6 @@ acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) { ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - /* Determine if the 64-bit vector actually exists */ if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { @@ -154,7 +153,6 @@ acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) #endif - /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_s4bios diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 15434e4c9b34..f30f35e6ff2a 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -353,7 +353,7 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* +1 to include null terminator */ user_prt->length += - (u32) ACPI_STRLEN(user_prt->source) + 1; + (u32)ACPI_STRLEN(user_prt->source) + 1; break; case ACPI_TYPE_STRING: diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index ece3cd60cc6a..90417de38dab 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -367,7 +367,7 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, (u32) ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; - total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); + total_length = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); ACPI_MEMSET(resource_source->string_ptr, 0, total_length); diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 60e94f87f27a..54b9f7957ff1 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -242,6 +242,7 @@ acpi_get_table_header(char *signature, if (!header) { return (AE_NO_MEMORY); } + ACPI_MEMCPY(out_table_header, header, sizeof(struct acpi_table_header)); acpi_os_unmap_memory(header, diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 073997d729e9..1e84e62b448d 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -359,7 +359,6 @@ #define ACPI_MEMCMP(s1,s2,n) memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (acpi_size)(n)) - #define ACPI_TOUPPER(i) toupper((int) (i)) #define ACPI_TOLOWER(i) tolower((int) (i)) #define ACPI_IS_XDIGIT(i) isxdigit((int) (i)) -- cgit v1.2.3 From 9bf39ab2adafd7cf8740859cb49e7b7952813a5d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 19 Jun 2015 10:29:13 +0200 Subject: vfs: add file_path() helper Turn d_path(&file->f_path, ...); into file_path(file, ...); Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- arch/arc/kernel/troubleshoot.c | 10 +++------- arch/blackfin/kernel/trace.c | 2 +- arch/tile/kernel/stack.c | 2 +- arch/tile/mm/elf.c | 2 +- drivers/block/loop.c | 2 +- drivers/md/bitmap.c | 2 +- drivers/md/md.c | 2 +- drivers/usb/gadget/function/f_mass_storage.c | 2 +- drivers/usb/gadget/function/storage_common.c | 2 +- fs/binfmt_elf.c | 4 ++-- fs/coredump.c | 2 +- fs/ext4/super.c | 2 +- fs/open.c | 6 ++++++ include/linux/fs.h | 2 ++ kernel/events/core.c | 2 +- mm/memory.c | 2 +- 16 files changed, 25 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c index e00a01879025..9f80c5adcb68 100644 --- a/arch/arc/kernel/troubleshoot.c +++ b/arch/arc/kernel/troubleshoot.c @@ -67,15 +67,12 @@ static void print_task_path_n_nm(struct task_struct *tsk, char *buf) mmput(mm); if (exe_file) { - path = exe_file->f_path; - path_get(&exe_file->f_path); + path_nm = file_path(exe_file, buf, 255); fput(exe_file); - path_nm = d_path(&path, buf, 255); - path_put(&path); } done: - pr_info("Path: %s\n", path_nm); + pr_info("Path: %s\n", !IS_ERR(path_nm) ? path_nm : "?"); } static void show_faulting_vma(unsigned long address, char *buf) @@ -99,8 +96,7 @@ static void show_faulting_vma(unsigned long address, char *buf) if (vma && (vma->vm_start <= address)) { struct file *file = vma->vm_file; if (file) { - struct path *path = &file->f_path; - nm = d_path(path, buf, PAGE_SIZE - 1); + nm = file_path(file, buf, PAGE_SIZE - 1); inode = file_inode(vma->vm_file); dev = inode->i_sb->s_dev; ino = inode->i_ino; diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c index c36efa0c7163..719dd796c12c 100644 --- a/arch/blackfin/kernel/trace.c +++ b/arch/blackfin/kernel/trace.c @@ -136,7 +136,7 @@ void decode_address(char *buf, unsigned long address) struct file *file = vma->vm_file; if (file) { - char *d_name = d_path(&file->f_path, _tmpbuf, + char *d_name = file_path(file, _tmpbuf, sizeof(_tmpbuf)); if (!IS_ERR(d_name)) name = d_name; diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index c42dce50acd8..8d62cf12c2c0 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c @@ -334,7 +334,7 @@ static void describe_addr(struct KBacktraceIterator *kbt, } if (vma->vm_file) { - p = d_path(&vma->vm_file->f_path, buf, bufsize); + p = file_path(vma->vm_file, buf, bufsize); if (IS_ERR(p)) p = "?"; name = kbasename(p); diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c index f7ddae3725a4..6225cc998db1 100644 --- a/arch/tile/mm/elf.c +++ b/arch/tile/mm/elf.c @@ -56,7 +56,7 @@ static int notify_exec(struct mm_struct *mm) if (exe_file == NULL) goto done_free; - path = d_path(&exe_file->f_path, buf, PAGE_SIZE); + path = file_path(exe_file, buf, PAGE_SIZE); if (IS_ERR(path)) goto done_put; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index d7173cb1ea76..0d8ad59413cd 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -568,7 +568,7 @@ static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) spin_lock_irq(&lo->lo_lock); if (lo->lo_backing_file) - p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1); + p = file_path(lo->lo_backing_file, buf, PAGE_SIZE - 1); spin_unlock_irq(&lo->lo_lock); if (IS_ERR_OR_NULL(p)) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2bc56e2a3526..dda33d648354 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -834,7 +834,7 @@ static void bitmap_file_kick(struct bitmap *bitmap) if (bitmap->storage.file) { path = kmalloc(PAGE_SIZE, GFP_KERNEL); if (path) - ptr = d_path(&bitmap->storage.file->f_path, + ptr = file_path(bitmap->storage.file, path, PAGE_SIZE); printk(KERN_ALERT diff --git a/drivers/md/md.c b/drivers/md/md.c index 593a02476c78..e67f3ac137bf 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5741,7 +5741,7 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg) /* bitmap disabled, zero the first byte and copy out */ if (!mddev->bitmap_info.file) file->pathname[0] = '\0'; - else if ((ptr = d_path(&mddev->bitmap_info.file->f_path, + else if ((ptr = file_path(mddev->bitmap_info.file, file->pathname, sizeof(file->pathname))), IS_ERR(ptr)) err = PTR_ERR(ptr); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 3cc109f3c9c8..d2259c663996 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2936,7 +2936,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, if (fsg_lun_is_open(lun)) { p = "(error)"; if (pathbuf) { - p = d_path(&lun->filp->f_path, pathbuf, PATH_MAX); + p = file_path(lun->filp, pathbuf, PATH_MAX); if (IS_ERR(p)) p = "(error)"; } diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index 648f9e489b39..d62683017cf3 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -341,7 +341,7 @@ ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, down_read(filesem); if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */ - p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); + p = file_path(curlun->filp, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 241ef68d2893..5046b6247103 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1530,7 +1530,7 @@ static int fill_files_note(struct memelfnote *note) file = vma->vm_file; if (!file) continue; - filename = d_path(&file->f_path, name_curpos, remaining); + filename = file_path(file, name_curpos, remaining); if (IS_ERR(filename)) { if (PTR_ERR(filename) == -ENAMETOOLONG) { vfree(data); @@ -1540,7 +1540,7 @@ static int fill_files_note(struct memelfnote *note) continue; } - /* d_path() fills at the end, move name down */ + /* file_path() fills at the end, move name down */ /* n = strlen(filename) + 1: */ n = (name_curpos + remaining) - filename; remaining = filename - name_curpos; diff --git a/fs/coredump.c b/fs/coredump.c index bbbe139ab280..5b771b36cc6e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -138,7 +138,7 @@ static int cn_print_exe_file(struct core_name *cn) goto put_exe_file; } - path = d_path(&exe_file->f_path, pathbuf, PATH_MAX); + path = file_path(exe_file, pathbuf, PATH_MAX); if (IS_ERR(path)) { ret = PTR_ERR(path); goto free_buf; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f06d0589ddba..0ae853d2e1f1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -449,7 +449,7 @@ void __ext4_error_file(struct file *file, const char *function, es = EXT4_SB(inode->i_sb)->s_es; es->s_last_error_ino = cpu_to_le32(inode->i_ino); if (ext4_error_ratelimit(inode->i_sb)) { - path = d_path(&(file->f_path), pathname, sizeof(pathname)); + path = file_path(file, pathname, sizeof(pathname)); if (IS_ERR(path)) path = "(unknown)"; va_start(args, fmt); diff --git a/fs/open.c b/fs/open.c index b1c5823b7f11..1dbc79358d59 100644 --- a/fs/open.c +++ b/fs/open.c @@ -823,6 +823,12 @@ int finish_no_open(struct file *file, struct dentry *dentry) } EXPORT_SYMBOL(finish_no_open); +char *file_path(struct file *filp, char *buf, int buflen) +{ + return d_path(&filp->f_path, buf, buflen); +} +EXPORT_SYMBOL(file_path); + /** * vfs_open - open the file at the given path * @path: path to open diff --git a/include/linux/fs.h b/include/linux/fs.h index 2bd77e10e8e5..2c135ad741a9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2500,6 +2500,8 @@ extern struct file * open_exec(const char *); extern int is_subdir(struct dentry *, struct dentry *); extern int path_is_under(struct path *, struct path *); +extern char *file_path(struct file *, char *, int); + #include /* needed for stackable file system support */ diff --git a/kernel/events/core.c b/kernel/events/core.c index 81aa3a4ece9f..5c964e845483 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5791,7 +5791,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) * need to add enough zero bytes after the string to handle * the 64bit alignment we do later. */ - name = d_path(&file->f_path, buf, PATH_MAX - sizeof(u64)); + name = file_path(file, buf, PATH_MAX - sizeof(u64)); if (IS_ERR(name)) { name = "//toolong"; goto cpy_name; diff --git a/mm/memory.c b/mm/memory.c index 22e037e3364e..28c10da1efbc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3724,7 +3724,7 @@ void print_vma_addr(char *prefix, unsigned long ip) if (buf) { char *p; - p = d_path(&f->f_path, buf, PAGE_SIZE); + p = file_path(f, buf, PAGE_SIZE); if (IS_ERR(p)) p = "?"; printk("%s%s[%lx+%lx]", prefix, kbasename(p), -- cgit v1.2.3 From 2726d56620ce71f40dd583d51391b86e1ab8cc57 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 19 Jun 2015 10:30:28 +0200 Subject: vfs: add seq_file_path() helper Turn seq_path(..., &file->f_path, ...); into seq_file_path(..., file, ...); Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro --- drivers/md/bitmap.c | 2 +- fs/proc/nommu.c | 2 +- fs/proc/task_mmu.c | 4 ++-- fs/proc/task_nommu.c | 2 +- fs/seq_file.c | 14 ++++++++++++++ include/linux/seq_file.h | 1 + mm/swapfile.c | 2 +- 7 files changed, 21 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index dda33d648354..3813fdfee4be 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1922,7 +1922,7 @@ void bitmap_status(struct seq_file *seq, struct bitmap *bitmap) chunk_kb ? "KB" : "B"); if (bitmap->storage.file) { seq_printf(seq, ", file: "); - seq_path(seq, &bitmap->storage.file->f_path, " \t\n"); + seq_file_path(seq, bitmap->storage.file, " \t\n"); } seq_printf(seq, "\n"); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index d4a35746cab9..f8595e8b5cd0 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -64,7 +64,7 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) if (file) { seq_pad(m, ' '); - seq_path(m, &file->f_path, ""); + seq_file_path(m, file, ""); } seq_putc(m, '\n'); diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6dee68d013ff..ca1e091881d4 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -310,7 +310,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) */ if (file) { seq_pad(m, ' '); - seq_path(m, &file->f_path, "\n"); + seq_file_path(m, file, "\n"); goto done; } @@ -1509,7 +1509,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) if (file) { seq_puts(m, " file="); - seq_path(m, &file->f_path, "\n\t= "); + seq_file_path(m, file, "\n\t= "); } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { seq_puts(m, " heap"); } else { diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 599ec2e20104..e0d64c92e4f6 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -180,7 +180,7 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, if (file) { seq_pad(m, ' '); - seq_path(m, &file->f_path, ""); + seq_file_path(m, file, ""); } else if (mm) { pid_t tid = pid_of_stack(priv, vma, is_pid); diff --git a/fs/seq_file.c b/fs/seq_file.c index 555f82155be8..d8a0545ad7ea 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -487,6 +487,20 @@ int seq_path(struct seq_file *m, const struct path *path, const char *esc) } EXPORT_SYMBOL(seq_path); +/** + * seq_file_path - seq_file interface to print a pathname of a file + * @m: the seq_file handle + * @file: the struct file to print + * @esc: set of characters to escape in the output + * + * return the absolute path to the file. + */ +int seq_file_path(struct seq_file *m, struct file *file, const char *esc) +{ + return seq_path(m, &file->f_path, esc); +} +EXPORT_SYMBOL(seq_file_path); + /* * Same as seq_path, but relative to supplied root. */ diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index afbb1fd77c77..912a7c482649 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -123,6 +123,7 @@ __printf(2, 3) int seq_printf(struct seq_file *, const char *, ...); __printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args); int seq_path(struct seq_file *, const struct path *, const char *); +int seq_file_path(struct seq_file *, struct file *, const char *); int seq_dentry(struct seq_file *, struct dentry *, const char *); int seq_path_root(struct seq_file *m, const struct path *path, const struct path *root, const char *esc); diff --git a/mm/swapfile.c b/mm/swapfile.c index a7e72103f23b..41e4581af7c5 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2032,7 +2032,7 @@ static int swap_show(struct seq_file *swap, void *v) } file = si->swap_file; - len = seq_path(swap, &file->f_path, " \t\n\\"); + len = seq_file_path(swap, file, " \t\n\\"); seq_printf(swap, "%*s%s\t%u\t%u\t%d\n", len < 40 ? 40 - len : 1, " ", S_ISBLK(file_inode(file)->i_mode) ? -- cgit v1.2.3 From 5fa8e0a1c6a762857ae67d1628c58b9a02362003 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 21 May 2015 16:05:53 +0200 Subject: fs: Rename file_remove_suid() to file_remove_privs() file_remove_suid() is a misnomer since it removes also file capabilities stored in xattrs and sets S_NOSEC flag. Also should_remove_suid() tells something else than whether file_remove_suid() call is necessary which leads to bugs. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/btrfs/file.c | 2 +- fs/ceph/file.c | 2 +- fs/fuse/file.c | 2 +- fs/inode.c | 13 ++++++++----- fs/ntfs/file.c | 2 +- fs/xfs/xfs_file.c | 2 +- include/linux/fs.h | 2 +- mm/filemap.c | 2 +- 8 files changed, 15 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index b072e17479aa..86f97282779a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1748,7 +1748,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, } current->backing_dev_info = inode_to_bdi(inode); - err = file_remove_suid(file); + err = file_remove_privs(file); if (err) { mutex_unlock(&inode->i_mutex); goto out; diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 3b6b522b4b31..e55fe32c6224 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -959,7 +959,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) pos = iocb->ki_pos; count = iov_iter_count(from); - err = file_remove_suid(file); + err = file_remove_privs(file); if (err) goto out; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 5ef05b5c4cff..1344647965dc 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1169,7 +1169,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (err <= 0) goto out; - err = file_remove_suid(file); + err = file_remove_privs(file); if (err) goto out; diff --git a/fs/inode.c b/fs/inode.c index 07f4cb5eab4b..849210c155dc 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1685,7 +1685,11 @@ static int __remove_suid(struct dentry *dentry, int kill) return notify_change(dentry, &newattrs, NULL); } -int file_remove_suid(struct file *file) +/* + * Remove special file priviledges (suid, capabilities) when file is written + * to or truncated. + */ +int file_remove_privs(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct inode *inode = d_inode(dentry); @@ -1711,7 +1715,7 @@ int file_remove_suid(struct file *file) return error; } -EXPORT_SYMBOL(file_remove_suid); +EXPORT_SYMBOL(file_remove_privs); /** * file_update_time - update mtime and ctime time @@ -1966,9 +1970,8 @@ EXPORT_SYMBOL(inode_dio_wait); * inode is being instantiated). The reason for the cmpxchg() loop * --- which wouldn't be necessary if all code paths which modify * i_flags actually followed this rule, is that there is at least one - * code path which doesn't today --- for example, - * __generic_file_aio_write() calls file_remove_suid() without holding - * i_mutex --- so we use cmpxchg() out of an abundance of caution. + * code path which doesn't today so we use cmpxchg() out of an abundance + * of caution. * * In the long run, i_mutex is overkill, and we should probably look * at using the i_lock spinlock to protect i_flags, and then make sure diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 7bb487e663b4..182bb93aa79c 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -382,7 +382,7 @@ static ssize_t ntfs_prepare_file_for_write(struct kiocb *iocb, base_ni = ni; if (NInoAttr(ni)) base_ni = ni->ext.base_ntfs_ino; - err = file_remove_suid(file); + err = file_remove_privs(file); if (unlikely(err)) goto out; /* diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 8121e75352ee..f3e4fbb59985 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -623,7 +623,7 @@ restart: * setgid bits if the process is not being run by root. This keeps * people from modifying setuid and setgid binaries. */ - return file_remove_suid(file); + return file_remove_privs(file); } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 2c135ad741a9..641e68d850cf 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2553,7 +2553,7 @@ extern struct inode *new_inode_pseudo(struct super_block *sb); extern struct inode *new_inode(struct super_block *sb); extern void free_inode_nonrcu(struct inode *inode); extern int should_remove_suid(struct dentry *); -extern int file_remove_suid(struct file *); +extern int file_remove_privs(struct file *); extern void __insert_inode_hash(struct inode *, unsigned long hashval); static inline void insert_inode_hash(struct inode *inode) diff --git a/mm/filemap.c b/mm/filemap.c index 6bf5e42d560a..f851e36802d5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2536,7 +2536,7 @@ ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) /* We can write back this queue in page reclaim */ current->backing_dev_info = inode_to_bdi(inode); - err = file_remove_suid(file); + err = file_remove_privs(file); if (err) goto out; -- cgit v1.2.3 From dbfae0cdcd87602737101d4417811f4323156b54 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 21 May 2015 16:05:54 +0200 Subject: fs: Provide function telling whether file_remove_privs() will do anything Provide function telling whether file_remove_privs() will do anything. Currently we only have should_remove_suid() and that does something slightly different. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/inode.c | 44 ++++++++++++++++++++++++++++++++------------ include/linux/fs.h | 1 + 2 files changed, 33 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/fs/inode.c b/fs/inode.c index 849210c155dc..8c2dd74455c9 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1673,7 +1673,32 @@ int should_remove_suid(struct dentry *dentry) } EXPORT_SYMBOL(should_remove_suid); -static int __remove_suid(struct dentry *dentry, int kill) +/* + * Return mask of changes for notify_change() that need to be done as a + * response to write or truncate. Return 0 if nothing has to be changed. + * Negative value on error (change should be denied). + */ +int file_needs_remove_privs(struct file *file) +{ + struct dentry *dentry = file->f_path.dentry; + struct inode *inode = d_inode(dentry); + int mask = 0; + int ret; + + if (IS_NOSEC(inode)) + return 0; + + mask = should_remove_suid(dentry); + ret = security_inode_need_killpriv(dentry); + if (ret < 0) + return ret; + if (ret) + mask |= ATTR_KILL_PRIV; + return mask; +} +EXPORT_SYMBOL(file_needs_remove_privs); + +static int __remove_privs(struct dentry *dentry, int kill) { struct iattr newattrs; @@ -1693,23 +1718,18 @@ int file_remove_privs(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct inode *inode = d_inode(dentry); - int killsuid; - int killpriv; + int kill; int error = 0; /* Fast path for nothing security related */ if (IS_NOSEC(inode)) return 0; - killsuid = should_remove_suid(dentry); - killpriv = security_inode_need_killpriv(dentry); - - if (killpriv < 0) - return killpriv; - if (killpriv) - error = security_inode_killpriv(dentry); - if (!error && killsuid) - error = __remove_suid(dentry, killsuid); + kill = file_needs_remove_privs(file); + if (kill < 0) + return kill; + if (kill) + error = __remove_privs(dentry, kill); if (!error) inode_has_no_xattr(inode); diff --git a/include/linux/fs.h b/include/linux/fs.h index 641e68d850cf..ee60e8ab210f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2554,6 +2554,7 @@ extern struct inode *new_inode(struct super_block *sb); extern void free_inode_nonrcu(struct inode *inode); extern int should_remove_suid(struct dentry *); extern int file_remove_privs(struct file *); +extern int file_needs_remove_privs(struct file *file); extern void __insert_inode_hash(struct inode *, unsigned long hashval); static inline void insert_inode_hash(struct inode *inode) -- cgit v1.2.3 From 45f147a1bc97c743c6101a8d2741c69a51f583e4 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 21 May 2015 16:05:55 +0200 Subject: fs: Call security_ops->inode_killpriv on truncate Comment in include/linux/security.h says that ->inode_killpriv() should be called when setuid bit is being removed and that similar security labels (in fact this applies only to file capabilities) should be removed at this time as well. However we don't call ->inode_killpriv() when we remove suid bit on truncate. We fix the problem by calling ->inode_need_killpriv() and subsequently ->inode_killpriv() on truncate the same way as we do it on file write. After this patch there's only one user of should_remove_suid() - ocfs2 - and indeed it's buggy because it doesn't call ->inode_killpriv() on write. However fixing it is difficult because of special locking constraints. Signed-off-by: Jan Kara Signed-off-by: Al Viro --- fs/inode.c | 5 ++--- fs/open.c | 6 ++++-- include/linux/fs.h | 6 +++++- 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/fs/inode.c b/fs/inode.c index 8c2dd74455c9..0401d2c6d087 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1678,9 +1678,8 @@ EXPORT_SYMBOL(should_remove_suid); * response to write or truncate. Return 0 if nothing has to be changed. * Negative value on error (change should be denied). */ -int file_needs_remove_privs(struct file *file) +int dentry_needs_remove_privs(struct dentry *dentry) { - struct dentry *dentry = file->f_path.dentry; struct inode *inode = d_inode(dentry); int mask = 0; int ret; @@ -1696,7 +1695,7 @@ int file_needs_remove_privs(struct file *file) mask |= ATTR_KILL_PRIV; return mask; } -EXPORT_SYMBOL(file_needs_remove_privs); +EXPORT_SYMBOL(dentry_needs_remove_privs); static int __remove_privs(struct dentry *dentry, int kill) { diff --git a/fs/open.c b/fs/open.c index 1dbc79358d59..e33dab287fa0 100644 --- a/fs/open.c +++ b/fs/open.c @@ -51,8 +51,10 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, newattrs.ia_valid |= ATTR_FILE; } - /* Remove suid/sgid on truncate too */ - ret = should_remove_suid(dentry); + /* Remove suid, sgid, and file capabilities on truncate too */ + ret = dentry_needs_remove_privs(dentry); + if (ret < 0) + return ret; if (ret) newattrs.ia_valid |= ret | ATTR_FORCE; diff --git a/include/linux/fs.h b/include/linux/fs.h index ee60e8ab210f..1e658b11c265 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2554,7 +2554,11 @@ extern struct inode *new_inode(struct super_block *sb); extern void free_inode_nonrcu(struct inode *inode); extern int should_remove_suid(struct dentry *); extern int file_remove_privs(struct file *); -extern int file_needs_remove_privs(struct file *file); +extern int dentry_needs_remove_privs(struct dentry *dentry); +static inline int file_needs_remove_privs(struct file *file) +{ + return dentry_needs_remove_privs(file->f_path.dentry); +} extern void __insert_inode_hash(struct inode *, unsigned long hashval); static inline void insert_inode_hash(struct inode *inode) -- cgit v1.2.3 From b57c2cb9ea1a02c2ae08e16de8c20cc13ffbf85a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 24 May 2015 17:19:41 +0200 Subject: pagemap.h: move dir_pages() over there That function was declared in a lot of filesystems to calculate directory pages. Signed-off-by: Fabian Frederick Signed-off-by: Al Viro --- fs/exofs/dir.c | 6 ------ fs/ext2/dir.c | 5 ----- fs/freevxfs/vxfs_lookup.c | 7 ------- fs/minix/dir.c | 5 ----- fs/nilfs2/dir.c | 5 ----- fs/qnx6/dir.c | 5 ----- fs/sysv/dir.c | 5 ----- include/linux/pagemap.h | 6 ++++++ 8 files changed, 6 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index 4deb0b05b011..e5bb2abf77f9 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c @@ -44,12 +44,6 @@ static inline void exofs_put_page(struct page *page) page_cache_release(page); } -/* Accesses dir's inode->i_size must be called under inode lock */ -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; -} - static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr) { loff_t last_byte = inode->i_size; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 796b491e6978..0c6638b40f21 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -70,11 +70,6 @@ static inline void ext2_put_page(struct page *page) page_cache_release(page); } -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - /* * Return the offset into page `page_nr' of the last valid * byte in that page, plus one. diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c index 99c7f0a37af4..484b32d3234a 100644 --- a/fs/freevxfs/vxfs_lookup.c +++ b/fs/freevxfs/vxfs_lookup.c @@ -61,13 +61,6 @@ const struct file_operations vxfs_dir_operations = { .iterate = vxfs_readdir, }; - -static inline u_long -dir_pages(struct inode *inode) -{ - return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; -} - static inline u_long dir_blocks(struct inode *ip) { diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 118e4e7bc935..d19ac258105a 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -45,11 +45,6 @@ minix_last_byte(struct inode *inode, unsigned long page_nr) return last_byte; } -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len) { struct address_space *mapping = page->mapping; diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 0ee0bed3649b..6b8b92b19cec 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -61,11 +61,6 @@ static inline void nilfs_put_page(struct page *page) page_cache_release(page); } -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - /* * Return the offset into page `page_nr' of the last valid * byte in that page, plus one. diff --git a/fs/qnx6/dir.c b/fs/qnx6/dir.c index 8d64bb5366bf..e1f37278cf97 100644 --- a/fs/qnx6/dir.c +++ b/fs/qnx6/dir.c @@ -32,11 +32,6 @@ static struct page *qnx6_get_page(struct inode *dir, unsigned long n) return page; } -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - static unsigned last_entry(struct inode *inode, unsigned long page_nr) { unsigned long last_byte = inode->i_size; diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 8f3555f00c54..63c1bcb224ee 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -33,11 +33,6 @@ static inline void dir_put_page(struct page *page) page_cache_release(page); } -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - static int dir_commit_chunk(struct page *page, loff_t pos, unsigned len) { struct address_space *mapping = page->mapping; diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 4b3736f7065c..808942d31062 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -670,4 +670,10 @@ static inline int add_to_page_cache(struct page *page, return error; } +static inline unsigned long dir_pages(struct inode *inode) +{ + return (unsigned long)(inode->i_size + PAGE_CACHE_SIZE - 1) >> + PAGE_CACHE_SHIFT; +} + #endif /* _LINUX_PAGEMAP_H */ -- cgit v1.2.3 From dc3f4198eac14e52a98dfc79cd84b45e280f59cd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 18 May 2015 10:10:34 -0400 Subject: make simple_positive() public Signed-off-by: Al Viro --- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/s390/hypfs/inode.c | 7 +------ drivers/block/drbd/drbd_debugfs.c | 10 +--------- drivers/infiniband/hw/ipath/ipath_fs.c | 2 +- drivers/infiniband/hw/qib/qib_fs.c | 2 +- fs/autofs4/autofs_i.h | 5 ----- fs/ceph/dir.c | 2 +- fs/configfs/inode.c | 2 +- fs/debugfs/inode.c | 11 +++-------- fs/libfs.c | 5 ----- fs/nfs/dir.c | 2 +- fs/tracefs/inode.c | 11 +++-------- include/linux/dcache.h | 5 +++++ security/inode.c | 19 ++++++------------- 14 files changed, 25 insertions(+), 60 deletions(-) (limited to 'include') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 1ba6307be4db..11634fa7ab3c 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -166,7 +166,7 @@ static void spufs_prune_dir(struct dentry *dir) mutex_lock(&d_inode(dir)->i_mutex); list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { spin_lock(&dentry->d_lock); - if (!(d_unhashed(dentry)) && d_really_is_positive(dentry)) { + if (simple_positive(dentry)) { dget_dlock(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index d3f896a35b98..8ffad5437232 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -62,18 +62,13 @@ static void hypfs_add_dentry(struct dentry *dentry) hypfs_last_dentry = dentry; } -static inline int hypfs_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - static void hypfs_remove(struct dentry *dentry) { struct dentry *parent; parent = dentry->d_parent; mutex_lock(&d_inode(parent)->i_mutex); - if (hypfs_positive(dentry)) { + if (simple_positive(dentry)) { if (d_is_dir(dentry)) simple_rmdir(d_inode(parent), dentry); else diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c index a6ee3d750c30..6b88a35fb048 100644 --- a/drivers/block/drbd/drbd_debugfs.c +++ b/drivers/block/drbd/drbd_debugfs.c @@ -419,14 +419,6 @@ static int in_flight_summary_show(struct seq_file *m, void *pos) return 0; } -/* simple_positive(file->f_path.dentry) respectively debugfs_positive(), - * but neither is "reachable" from here. - * So we have our own inline version of it above. :-( */ -static inline int debugfs_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - /* make sure at *open* time that the respective object won't go away. */ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *), void *data, struct kref *kref, @@ -444,7 +436,7 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo /* serialize with d_delete() */ mutex_lock(&d_inode(parent)->i_mutex); /* Make sure the object is still alive */ - if (debugfs_positive(file->f_path.dentry) + if (simple_positive(file->f_path.dentry) && kref_get_unless_zero(kref)) ret = 0; mutex_unlock(&d_inode(parent)->i_mutex); diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 1ca8e32a9592..25422a3a7238 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -277,7 +277,7 @@ static int remove_file(struct dentry *parent, char *name) } spin_lock(&tmp->d_lock); - if (!d_unhashed(tmp) && d_really_is_positive(tmp)) { + if (simple_positive(tmp)) { dget_dlock(tmp); __d_drop(tmp); spin_unlock(&tmp->d_lock); diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index bdd5d3857203..13ef22bd9459 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -455,7 +455,7 @@ static int remove_file(struct dentry *parent, char *name) } spin_lock(&tmp->d_lock); - if (!d_unhashed(tmp) && d_really_is_positive(tmp)) { + if (simple_positive(tmp)) { __d_drop(tmp); spin_unlock(&tmp->d_lock); simple_unlink(d_inode(parent), tmp); diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 5b700ef1e59d..c37149b929be 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -238,11 +238,6 @@ static inline u64 autofs4_get_ino(struct autofs_sb_info *sbi) return d_inode(sbi->sb->s_root)->i_ino; } -static inline int simple_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - static inline void __autofs4_add_expiring(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 4248307fea90..edbb8da02a6a 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -161,7 +161,7 @@ more: } spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); if (di->lease_shared_gen == shared_gen && - !d_unhashed(dentry) && d_really_is_positive(dentry) && + simple_positive(dentry) && ceph_snap(d_inode(dentry)) != CEPH_SNAPDIR && ceph_ino(d_inode(dentry)) != CEPH_INO_CEPH && fpos_cmp(ctx->pos, di->offset) <= 0) diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 8d89f5fd0331..eae87575e681 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -236,7 +236,7 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) if (dentry) { spin_lock(&dentry->d_lock); - if (!d_unhashed(dentry) && d_really_is_positive(dentry)) { + if (simple_positive(dentry)) { dget_dlock(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 7eaec88ea970..ef86ad6bdc3e 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -44,11 +44,6 @@ static struct inode *debugfs_get_inode(struct super_block *sb) return inode; } -static inline int debugfs_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - struct debugfs_mount_opts { kuid_t uid; kgid_t gid; @@ -522,7 +517,7 @@ static int __debugfs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; - if (debugfs_positive(dentry)) { + if (simple_positive(dentry)) { dget(dentry); if (d_is_dir(dentry)) ret = simple_rmdir(d_inode(parent), dentry); @@ -602,7 +597,7 @@ void debugfs_remove_recursive(struct dentry *dentry) */ spin_lock(&parent->d_lock); list_for_each_entry(child, &parent->d_subdirs, d_child) { - if (!debugfs_positive(child)) + if (!simple_positive(child)) continue; /* perhaps simple_empty(child) makes more sense */ @@ -623,7 +618,7 @@ void debugfs_remove_recursive(struct dentry *dentry) * from d_subdirs. When releasing the parent->d_lock we can * no longer trust that the next pointer is valid. * Restart the loop. We'll skip this one with the - * debugfs_positive() check. + * simple_positive() check. */ goto loop; } diff --git a/fs/libfs.c b/fs/libfs.c index 65e1feca8b98..4d9e6c118fe1 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -20,11 +20,6 @@ #include "internal.h" -static inline int simple_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b2c8b31b2be7..b9108f4254a7 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1771,7 +1771,7 @@ EXPORT_SYMBOL_GPL(nfs_mkdir); static void nfs_dentry_handle_enoent(struct dentry *dentry) { - if (d_really_is_positive(dentry) && !d_unhashed(dentry)) + if (simple_positive(dentry)) d_delete(dentry); } diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index d92bdf3b079a..6e8a1400d662 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -496,16 +496,11 @@ struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *pare return dentry; } -static inline int tracefs_positive(struct dentry *dentry) -{ - return dentry->d_inode && !d_unhashed(dentry); -} - static int __tracefs_remove(struct dentry *dentry, struct dentry *parent) { int ret = 0; - if (tracefs_positive(dentry)) { + if (simple_positive(dentry)) { if (dentry->d_inode) { dget(dentry); switch (dentry->d_inode->i_mode & S_IFMT) { @@ -582,7 +577,7 @@ void tracefs_remove_recursive(struct dentry *dentry) */ spin_lock(&parent->d_lock); list_for_each_entry(child, &parent->d_subdirs, d_child) { - if (!tracefs_positive(child)) + if (!simple_positive(child)) continue; /* perhaps simple_empty(child) makes more sense */ @@ -603,7 +598,7 @@ void tracefs_remove_recursive(struct dentry *dentry) * from d_subdirs. When releasing the parent->d_lock we can * no longer trust that the next pointer is valid. * Restart the loop. We'll skip this one with the - * tracefs_positive() check. + * simple_positive() check. */ goto loop; } diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 167ec0934049..d2d50249b7b2 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -507,6 +507,11 @@ static inline bool d_really_is_positive(const struct dentry *dentry) return dentry->d_inode != NULL; } +static inline int simple_positive(struct dentry *dentry) +{ + return d_really_is_positive(dentry) && !d_unhashed(dentry); +} + extern void d_set_fallthru(struct dentry *dentry); static inline bool d_is_fallthru(const struct dentry *dentry) diff --git a/security/inode.c b/security/inode.c index 91503b79c5f8..6df0d8dae1e0 100644 --- a/security/inode.c +++ b/security/inode.c @@ -25,11 +25,6 @@ static struct vfsmount *mount; static int mount_count; -static inline int positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - static int fill_super(struct super_block *sb, void *data, int silent) { static struct tree_descr files[] = {{""}}; @@ -201,14 +196,12 @@ void securityfs_remove(struct dentry *dentry) return; mutex_lock(&d_inode(parent)->i_mutex); - if (positive(dentry)) { - if (d_really_is_positive(dentry)) { - if (d_is_dir(dentry)) - simple_rmdir(d_inode(parent), dentry); - else - simple_unlink(d_inode(parent), dentry); - dput(dentry); - } + if (simple_positive(dentry)) { + if (d_is_dir(dentry)) + simple_rmdir(d_inode(parent), dentry); + else + simple_unlink(d_inode(parent), dentry); + dput(dentry); } mutex_unlock(&d_inode(parent)->i_mutex); simple_release_fs(&mount, &mount_count); -- cgit v1.2.3 From be3a5d233922d73f27002ce2767f6ec03c3f473d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 23 Jun 2015 19:51:55 +0800 Subject: NFSv.2/pnfs Add a LAYOUTSTATS rpc function Reviewed-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/nfs42.h | 9 +++- fs/nfs/nfs42proc.c | 27 +++++++++++ fs/nfs/nfs42xdr.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 4 +- fs/nfs/nfs4xdr.c | 1 + include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 43 +++++++++++++++++ 8 files changed, 205 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h index 7afb8947dfdf..ff66ae700b89 100644 --- a/fs/nfs/nfs42.h +++ b/fs/nfs/nfs42.h @@ -5,11 +5,18 @@ #ifndef __LINUX_FS_NFS_NFS4_2_H #define __LINUX_FS_NFS_NFS4_2_H +/* + * FIXME: four LAYOUTSTATS calls per compound at most! Do we need to support + * more? Need to consider not to pre-alloc too much for a compound. + */ +#define PNFS_LAYOUTSTATS_MAXDEV (4) + /* nfs4.2proc.c */ int nfs42_proc_allocate(struct file *, loff_t, loff_t); int nfs42_proc_deallocate(struct file *, loff_t, loff_t); loff_t nfs42_proc_llseek(struct file *, loff_t, int); - +int nfs42_proc_layoutstats_generic(struct nfs_server *, + struct nfs42_layoutstat_data *); /* nfs4.2xdr.h */ extern struct rpc_procinfo nfs4_2_procedures[]; diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 3a9e75235f30..ac929685350b 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -165,3 +165,30 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes); } + +static const struct rpc_call_ops nfs42_layoutstat_ops = { +}; + +int nfs42_proc_layoutstats_generic(struct nfs_server *server, + struct nfs42_layoutstat_data *data) +{ + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS], + .rpc_argp = &data->args, + .rpc_resp = &data->res, + }; + struct rpc_task_setup task_setup = { + .rpc_client = server->client, + .rpc_message = &msg, + .callback_ops = &nfs42_layoutstat_ops, + .callback_data = data, + .flags = RPC_TASK_ASYNC, + }; + struct rpc_task *task; + + nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); + task = rpc_run_task(&task_setup); + if (IS_ERR(task)) + return PTR_ERR(task); + return 0; +} diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index 1a25b27248f2..9aae0205ef11 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c @@ -4,6 +4,8 @@ #ifndef __LINUX_FS_NFS_NFS4_2XDR_H #define __LINUX_FS_NFS_NFS4_2XDR_H +#include "nfs42.h" + #define encode_fallocate_maxsz (encode_stateid_maxsz + \ 2 /* offset */ + \ 2 /* length */) @@ -22,6 +24,16 @@ 1 /* whence */ + \ 2 /* offset */ + \ 2 /* length */) +#define encode_io_info_maxsz 4 +#define encode_layoutstats_maxsz (op_decode_hdr_maxsz + \ + 2 /* offset */ + \ + 2 /* length */ + \ + encode_stateid_maxsz + \ + encode_io_info_maxsz + \ + encode_io_info_maxsz + \ + 1 /* opaque devaddr4 length */ + \ + XDR_QUADLEN(PNFS_LAYOUTSTATS_MAXSIZE)) +#define decode_layoutstats_maxsz (op_decode_hdr_maxsz) #define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ @@ -45,6 +57,14 @@ #define NFS4_dec_seek_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_seek_maxsz) +#define NFS4_enc_layoutstats_sz (compound_encode_hdr_maxsz + \ + encode_sequence_maxsz + \ + encode_putfh_maxsz + \ + PNFS_LAYOUTSTATS_MAXDEV * encode_layoutstats_maxsz) +#define NFS4_dec_layoutstats_sz (compound_decode_hdr_maxsz + \ + decode_sequence_maxsz + \ + decode_putfh_maxsz + \ + PNFS_LAYOUTSTATS_MAXDEV * decode_layoutstats_maxsz) static void encode_fallocate(struct xdr_stream *xdr, @@ -81,6 +101,33 @@ static void encode_seek(struct xdr_stream *xdr, encode_uint32(xdr, args->sa_what); } +static void encode_layoutstats(struct xdr_stream *xdr, + struct nfs42_layoutstat_args *args, + struct nfs42_layoutstat_devinfo *devinfo, + struct compound_hdr *hdr) +{ + __be32 *p; + + encode_op_hdr(xdr, OP_LAYOUTSTATS, decode_layoutstats_maxsz, hdr); + p = reserve_space(xdr, 8 + 8); + p = xdr_encode_hyper(p, devinfo->offset); + p = xdr_encode_hyper(p, devinfo->length); + encode_nfs4_stateid(xdr, &args->stateid); + p = reserve_space(xdr, 4*8 + NFS4_DEVICEID4_SIZE + 4); + p = xdr_encode_hyper(p, devinfo->read_count); + p = xdr_encode_hyper(p, devinfo->read_bytes); + p = xdr_encode_hyper(p, devinfo->write_count); + p = xdr_encode_hyper(p, devinfo->write_bytes); + p = xdr_encode_opaque_fixed(p, devinfo->dev_id.data, + NFS4_DEVICEID4_SIZE); + /* Encode layoutupdate4 */ + *p++ = cpu_to_be32(devinfo->layout_type); + if (devinfo->layoutstats_encode != NULL) + devinfo->layoutstats_encode(xdr, args, devinfo); + else + encode_uint32(xdr, 0); +} + /* * Encode ALLOCATE request */ @@ -137,6 +184,28 @@ static void nfs4_xdr_enc_seek(struct rpc_rqst *req, encode_nops(&hdr); } +/* + * Encode LAYOUTSTATS request + */ +static void nfs4_xdr_enc_layoutstats(struct rpc_rqst *req, + struct xdr_stream *xdr, + struct nfs42_layoutstat_args *args) +{ + int i; + + struct compound_hdr hdr = { + .minorversion = nfs4_xdr_minorversion(&args->seq_args), + }; + + encode_compound_hdr(xdr, req, &hdr); + encode_sequence(xdr, &args->seq_args, &hdr); + encode_putfh(xdr, args->fh, &hdr); + WARN_ON(args->num_dev > PNFS_LAYOUTSTATS_MAXDEV); + for (i = 0; i < args->num_dev; i++) + encode_layoutstats(xdr, args, &args->devinfo[i], &hdr); + encode_nops(&hdr); +} + static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res) { return decode_op_hdr(xdr, OP_ALLOCATE); @@ -169,6 +238,28 @@ out_overflow: return -EIO; } +static int decode_layoutstats(struct xdr_stream *xdr, + struct nfs42_layoutstat_res *res) +{ + int status; + __be32 *p; + + status = decode_op_hdr(xdr, OP_LAYOUTSTATS); + if (status) + return status; + + p = xdr_inline_decode(xdr, 4); + if (unlikely(!p)) + goto out_overflow; + + res->rpc_status = be32_to_cpup(p++); + return 0; + +out_overflow: + print_overflow_msg(__func__, xdr); + return -EIO; +} + /* * Decode ALLOCATE request */ @@ -246,4 +337,35 @@ static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp, out: return status; } + +/* + * Decode LAYOUTSTATS request + */ +static int nfs4_xdr_dec_layoutstats(struct rpc_rqst *rqstp, + struct xdr_stream *xdr, + struct nfs42_layoutstat_res *res) +{ + struct compound_hdr hdr; + int status, i; + + status = decode_compound_hdr(xdr, &hdr); + if (status) + goto out; + status = decode_sequence(xdr, &res->seq_res, rqstp); + if (status) + goto out; + status = decode_putfh(xdr); + if (status) + goto out; + WARN_ON(res->num_dev > PNFS_LAYOUTSTATS_MAXDEV); + for (i = 0; i < res->num_dev; i++) { + status = decode_layoutstats(xdr, res); + if (status) + goto out; + } +out: + res->rpc_status = status; + return status; +} + #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index fdef424b0cd3..ea3bee919a76 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -233,6 +233,7 @@ extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *, struct rpc_message *, struct nfs4_sequence_args *, struct nfs4_sequence_res *, int); +extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int); extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e9cd45f1d60f..643ce3a91b22 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -476,8 +476,8 @@ struct nfs4_call_sync_data { struct nfs4_sequence_res *seq_res; }; -static void nfs4_init_sequence(struct nfs4_sequence_args *args, - struct nfs4_sequence_res *res, int cache_reply) +void nfs4_init_sequence(struct nfs4_sequence_args *args, + struct nfs4_sequence_res *res, int cache_reply) { args->sa_slot = NULL; args->sa_cache_this = cache_reply; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index a07555d6968c..558cd65dbdb7 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -7431,6 +7431,7 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(SEEK, enc_seek, dec_seek), PROC(ALLOCATE, enc_allocate, dec_allocate), PROC(DEALLOCATE, enc_deallocate, dec_deallocate), + PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats), #endif /* CONFIG_NFS_V4_2 */ }; diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 32201c269890..b8e72aad919c 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -500,6 +500,7 @@ enum { NFSPROC4_CLNT_SEEK, NFSPROC4_CLNT_ALLOCATE, NFSPROC4_CLNT_DEALLOCATE, + NFSPROC4_CLNT_LAYOUTSTATS, }; /* nfs41 types */ diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index c959e7eb5bd4..7bbe50504211 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -316,6 +316,49 @@ struct nfs4_layoutreturn { int rpc_status; }; +#define PNFS_LAYOUTSTATS_MAXSIZE 256 + +struct nfs42_layoutstat_args; +struct nfs42_layoutstat_devinfo; +typedef void (*layoutstats_encode_t)(struct xdr_stream *, + struct nfs42_layoutstat_args *, + struct nfs42_layoutstat_devinfo *); + +/* Per file per deviceid layoutstats */ +struct nfs42_layoutstat_devinfo { + struct nfs4_deviceid dev_id; + __u64 offset; + __u64 length; + __u64 read_count; + __u64 read_bytes; + __u64 write_count; + __u64 write_bytes; + __u32 layout_type; + layoutstats_encode_t layoutstats_encode; + void *layout_private; +}; + +struct nfs42_layoutstat_args { + struct nfs4_sequence_args seq_args; + struct nfs_fh *fh; + struct inode *inode; + nfs4_stateid stateid; + int num_dev; + struct nfs42_layoutstat_devinfo *devinfo; +}; + +struct nfs42_layoutstat_res { + struct nfs4_sequence_res seq_res; + int num_dev; + int rpc_status; +}; + +struct nfs42_layoutstat_data { + struct inode *inode; + struct nfs42_layoutstat_args args; + struct nfs42_layoutstat_res res; +}; + struct stateowner_id { __u64 create_time; __u32 uniquifier; -- cgit v1.2.3 From 1bfe3b259ff2e579b2acb190f874397d53274497 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Tue, 23 Jun 2015 19:52:03 +0800 Subject: nfs42: serialize LAYOUTSTATS calls of the same file There is no need to report concurrently. Reviewed-by: Jeff Layton Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/nfs42proc.c | 3 +++ fs/nfs/pnfs.c | 7 +++++++ include/linux/nfs_fs.h | 1 + 3 files changed, 11 insertions(+) (limited to 'include') diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index ee0248340a42..06c74cd93875 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -204,6 +204,9 @@ nfs42_layoutstat_release(void *calldata) nfss->pnfs_curr_ld->cleanup_layoutstats(data); pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout); + smp_mb__before_atomic(); + clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags); + smp_mb__after_atomic(); nfs_iput_and_deactive(data->inode); kfree(data->args.devinfo); kfree(data); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 6279cff7df74..5b5224341bcd 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -2257,6 +2257,7 @@ pnfs_report_layoutstat(struct inode *inode) { struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; struct nfs_server *server = NFS_SERVER(inode); + struct nfs_inode *nfsi = NFS_I(inode); struct nfs42_layoutstat_data *data; struct pnfs_layout_hdr *hdr; int status = 0; @@ -2264,6 +2265,9 @@ pnfs_report_layoutstat(struct inode *inode) if (!pnfs_enabled_sb(server) || !ld->prepare_layoutstats) goto out; + if (test_and_set_bit(NFS_INO_LAYOUTSTATS, &nfsi->flags)) + goto out; + spin_lock(&inode->i_lock); if (!NFS_I(inode)->layout) { spin_unlock(&inode->i_lock); @@ -2296,6 +2300,9 @@ out_free: kfree(data); out_put: pnfs_put_layout_hdr(hdr); + smp_mb__before_atomic(); + clear_bit(NFS_INO_LAYOUTSTATS, &nfsi->flags); + smp_mb__after_atomic(); goto out; } EXPORT_SYMBOL_GPL(pnfs_report_layoutstat); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b95f914ce083..f91b5ade30c9 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -219,6 +219,7 @@ struct nfs_inode { #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ +#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ static inline struct nfs_inode *NFS_I(const struct inode *inode) { -- cgit v1.2.3 From 144cba1493fdd6e3e1980e439a31df877831ebcd Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 27 Apr 2015 11:09:54 +0800 Subject: libceph: allow setting osd_req_op's flags Signed-off-by: Yan, Zheng Reviewed-by: Alex Elder --- drivers/block/rbd.c | 4 ++-- fs/ceph/addr.c | 3 ++- fs/ceph/file.c | 2 +- include/linux/ceph/osd_client.h | 2 +- net/ceph/osd_client.c | 24 +++++++++++++++--------- 5 files changed, 21 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index ec6c5c6e1ac9..349115ae3bc2 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2376,7 +2376,7 @@ static void rbd_img_obj_request_fill(struct rbd_obj_request *obj_request, } if (opcode == CEPH_OSD_OP_DELETE) - osd_req_op_init(osd_request, num_ops, opcode); + osd_req_op_init(osd_request, num_ops, opcode, 0); else osd_req_op_extent_init(osd_request, num_ops, opcode, offset, length, 0, 0); @@ -2848,7 +2848,7 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request) goto out; stat_request->callback = rbd_img_obj_exists_callback; - osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT); + osd_req_op_init(stat_request->osd_req, 0, CEPH_OSD_OP_STAT, 0); osd_req_op_raw_data_in_pages(stat_request->osd_req, 0, pages, size, 0, false, false); rbd_osd_req_format_read(stat_request); diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index e162bcd105ee..feeaf3b65fa0 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -884,7 +884,8 @@ get_more_pages: } if (do_sync) - osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); + osd_req_op_init(req, 1, + CEPH_OSD_OP_STARTSYNC, 0); req->r_callback = writepages_finish; req->r_inode = inode; diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 3b6b522b4b31..777eb21d556f 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -614,7 +614,7 @@ ceph_sync_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos) break; } - osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC); + osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC, 0); n = iov_iter_get_pages_alloc(from, &pages, len, &start); if (unlikely(n < 0)) { diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 61b19c46bdb3..7506b485bb6d 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -249,7 +249,7 @@ extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg); extern void osd_req_op_init(struct ceph_osd_request *osd_req, - unsigned int which, u16 opcode); + unsigned int which, u16 opcode, u32 flags); extern void osd_req_op_raw_data_in_pages(struct ceph_osd_request *, unsigned int which, diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 72459b9df8a1..4cb4fab46e4f 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -453,7 +453,7 @@ __CEPH_FORALL_OSD_OPS(GENERATE_CASE) */ static struct ceph_osd_req_op * _osd_req_op_init(struct ceph_osd_request *osd_req, unsigned int which, - u16 opcode) + u16 opcode, u32 flags) { struct ceph_osd_req_op *op; @@ -463,14 +463,15 @@ _osd_req_op_init(struct ceph_osd_request *osd_req, unsigned int which, op = &osd_req->r_ops[which]; memset(op, 0, sizeof (*op)); op->op = opcode; + op->flags = flags; return op; } void osd_req_op_init(struct ceph_osd_request *osd_req, - unsigned int which, u16 opcode) + unsigned int which, u16 opcode, u32 flags) { - (void)_osd_req_op_init(osd_req, which, opcode); + (void)_osd_req_op_init(osd_req, which, opcode, flags); } EXPORT_SYMBOL(osd_req_op_init); @@ -479,7 +480,8 @@ void osd_req_op_extent_init(struct ceph_osd_request *osd_req, u64 offset, u64 length, u64 truncate_size, u32 truncate_seq) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); size_t payload_len = 0; BUG_ON(opcode != CEPH_OSD_OP_READ && opcode != CEPH_OSD_OP_WRITE && @@ -518,7 +520,8 @@ EXPORT_SYMBOL(osd_req_op_extent_update); void osd_req_op_cls_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, const char *class, const char *method) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); struct ceph_pagelist *pagelist; size_t payload_len = 0; size_t size; @@ -555,7 +558,8 @@ int osd_req_op_xattr_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, const char *name, const void *value, size_t size, u8 cmp_op, u8 cmp_mode) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); struct ceph_pagelist *pagelist; size_t payload_len; @@ -588,7 +592,8 @@ void osd_req_op_watch_init(struct ceph_osd_request *osd_req, unsigned int which, u16 opcode, u64 cookie, u64 version, int flag) { - struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode); + struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, + opcode, 0); BUG_ON(opcode != CEPH_OSD_OP_NOTIFY_ACK && opcode != CEPH_OSD_OP_WATCH); @@ -605,7 +610,8 @@ void osd_req_op_alloc_hint_init(struct ceph_osd_request *osd_req, u64 expected_write_size) { struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, - CEPH_OSD_OP_SETALLOCHINT); + CEPH_OSD_OP_SETALLOCHINT, + 0); op->alloc_hint.expected_object_size = expected_object_size; op->alloc_hint.expected_write_size = expected_write_size; @@ -789,7 +795,7 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc, } if (opcode == CEPH_OSD_OP_CREATE || opcode == CEPH_OSD_OP_DELETE) { - osd_req_op_init(req, which, opcode); + osd_req_op_init(req, which, opcode, 0); } else { u32 object_size = le32_to_cpu(layout->fl_object_size); u32 object_base = off - objoff; -- cgit v1.2.3 From d50c97b566c5bbf990eff472e9feaa58fdebdd33 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 15 May 2015 11:52:20 +0300 Subject: libceph: nuke time_sub() Unused since ceph got merged into mainline I guess. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- include/linux/ceph/libceph.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'include') diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 30f92cefaa72..85ae9a889a3f 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -93,15 +93,6 @@ enum { CEPH_MOUNT_SHUTDOWN, }; -/* - * subtract jiffies - */ -static inline unsigned long time_sub(unsigned long a, unsigned long b) -{ - BUG_ON(time_after(b, a)); - return (long)a - (long)b; -} - struct ceph_mds_client; /* -- cgit v1.2.3 From a319bf56a617354e62cf5f774d2ca4e1a8a3bff3 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 15 May 2015 12:02:17 +0300 Subject: libceph: store timeouts in jiffies, verify user input There are currently three libceph-level timeouts that the user can specify on mount: mount_timeout, osd_idle_ttl and osdkeepalive. All of these are in seconds and no checking is done on user input: negative values are accepted, we multiply them all by HZ which may or may not overflow, arbitrarily large jiffies then get added together, etc. There is also a bug in the way mount_timeout=0 is handled. It's supposed to mean "infinite timeout", but that's not how wait.h APIs treat it and so __ceph_open_session() for example will busy loop without much chance of being interrupted if none of ceph-mons are there. Fix all this by verifying user input, storing timeouts capped by msecs_to_jiffies() in jiffies and using the new ceph_timeout_jiffies() helper for all user-specified waits to handle infinite timeouts correctly. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 5 +++-- fs/ceph/dir.c | 4 ++-- fs/ceph/mds_client.c | 12 ++++++------ fs/ceph/mds_client.h | 2 +- fs/ceph/super.c | 2 +- include/linux/ceph/libceph.h | 17 +++++++++++------ net/ceph/ceph_common.c | 41 +++++++++++++++++++++++++++++++---------- net/ceph/mon_client.c | 11 +++++++++-- net/ceph/osd_client.c | 15 +++++++-------- 9 files changed, 71 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 349115ae3bc2..992683b6b299 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4963,8 +4963,8 @@ out_err: */ static int rbd_add_get_pool_id(struct rbd_client *rbdc, const char *pool_name) { + struct ceph_options *opts = rbdc->client->options; u64 newest_epoch; - unsigned long timeout = rbdc->client->options->mount_timeout * HZ; int tries = 0; int ret; @@ -4979,7 +4979,8 @@ again: if (rbdc->client->osdc.osdmap->epoch < newest_epoch) { ceph_monc_request_next_osdmap(&rbdc->client->monc); (void) ceph_monc_wait_osdmap(&rbdc->client->monc, - newest_epoch, timeout); + newest_epoch, + opts->mount_timeout); goto again; } else { /* the osdmap we have is new enough */ diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 4248307fea90..173dd4b58c71 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1259,8 +1259,8 @@ static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, inode, req->r_tid, last_tid); if (req->r_timeout) { unsigned long time_left = wait_for_completion_timeout( - &req->r_safe_completion, - req->r_timeout); + &req->r_safe_completion, + ceph_timeout_jiffies(req->r_timeout)); if (time_left > 0) ret = 0; else diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 69a36f40517f..0b0e0a9a81c0 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2268,7 +2268,8 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, dout("do_request waiting\n"); if (req->r_timeout) { err = (long)wait_for_completion_killable_timeout( - &req->r_completion, req->r_timeout); + &req->r_completion, + ceph_timeout_jiffies(req->r_timeout)); if (err == 0) err = -EIO; } else if (req->r_wait_for_completion) { @@ -3424,8 +3425,8 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc) */ static void wait_requests(struct ceph_mds_client *mdsc) { + struct ceph_options *opts = mdsc->fsc->client->options; struct ceph_mds_request *req; - struct ceph_fs_client *fsc = mdsc->fsc; mutex_lock(&mdsc->mutex); if (__get_oldest_req(mdsc)) { @@ -3433,7 +3434,7 @@ static void wait_requests(struct ceph_mds_client *mdsc) dout("wait_requests waiting for requests\n"); wait_for_completion_timeout(&mdsc->safe_umount_waiters, - fsc->client->options->mount_timeout * HZ); + ceph_timeout_jiffies(opts->mount_timeout)); /* tear down remaining requests */ mutex_lock(&mdsc->mutex); @@ -3556,10 +3557,9 @@ static bool done_closing_sessions(struct ceph_mds_client *mdsc) */ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) { + struct ceph_options *opts = mdsc->fsc->client->options; struct ceph_mds_session *session; int i; - struct ceph_fs_client *fsc = mdsc->fsc; - unsigned long timeout = fsc->client->options->mount_timeout * HZ; dout("close_sessions\n"); @@ -3580,7 +3580,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) dout("waiting for sessions to close\n"); wait_event_timeout(mdsc->session_close_wq, done_closing_sessions(mdsc), - timeout); + ceph_timeout_jiffies(opts->mount_timeout)); /* tear down remaining sessions */ mutex_lock(&mdsc->mutex); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 2ef799961ebb..509d6822e9b1 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -227,7 +227,7 @@ struct ceph_mds_request { int r_err; bool r_aborted; - unsigned long r_timeout; /* optional. jiffies */ + unsigned long r_timeout; /* optional. jiffies, 0 is "wait forever" */ unsigned long r_started; /* start time to measure timeout against */ unsigned long r_request_started; /* start time for mds request only, used to measure lease durations */ diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 9a5350030af8..edeb83c43112 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -742,7 +742,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, req->r_ino1.ino = CEPH_INO_ROOT; req->r_ino1.snap = CEPH_NOSNAP; req->r_started = started; - req->r_timeout = fsc->client->options->mount_timeout * HZ; + req->r_timeout = fsc->client->options->mount_timeout; req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE); req->r_num_caps = 2; err = ceph_mdsc_do_request(mdsc, NULL, req); diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 85ae9a889a3f..d73a569f9bf5 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -43,9 +43,9 @@ struct ceph_options { int flags; struct ceph_fsid fsid; struct ceph_entity_addr my_addr; - int mount_timeout; - int osd_idle_ttl; - int osd_keepalive_timeout; + unsigned long mount_timeout; /* jiffies */ + unsigned long osd_idle_ttl; /* jiffies */ + unsigned long osd_keepalive_timeout; /* jiffies */ /* * any type that can't be simply compared or doesn't need need @@ -63,9 +63,9 @@ struct ceph_options { /* * defaults */ -#define CEPH_MOUNT_TIMEOUT_DEFAULT 60 -#define CEPH_OSD_KEEPALIVE_DEFAULT 5 -#define CEPH_OSD_IDLE_TTL_DEFAULT 60 +#define CEPH_MOUNT_TIMEOUT_DEFAULT msecs_to_jiffies(60 * 1000) +#define CEPH_OSD_KEEPALIVE_DEFAULT msecs_to_jiffies(5 * 1000) +#define CEPH_OSD_IDLE_TTL_DEFAULT msecs_to_jiffies(60 * 1000) #define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024) #define CEPH_MSG_MAX_MIDDLE_LEN (16*1024*1024) @@ -93,6 +93,11 @@ enum { CEPH_MOUNT_SHUTDOWN, }; +static inline unsigned long ceph_timeout_jiffies(unsigned long timeout) +{ + return timeout ?: MAX_SCHEDULE_TIMEOUT; +} + struct ceph_mds_client; /* diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index 79e8f71aef5b..a80e91c2c9a3 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -352,8 +352,8 @@ ceph_parse_options(char *options, const char *dev_name, /* start with defaults */ opt->flags = CEPH_OPT_DEFAULT; opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; - opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */ - opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */ + opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; + opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* get mon ip(s) */ /* ip1[:port1][,ip2[:port2]...] */ @@ -439,13 +439,32 @@ ceph_parse_options(char *options, const char *dev_name, pr_warn("ignoring deprecated osdtimeout option\n"); break; case Opt_osdkeepalivetimeout: - opt->osd_keepalive_timeout = intval; + /* 0 isn't well defined right now, reject it */ + if (intval < 1 || intval > INT_MAX / 1000) { + pr_err("osdkeepalive out of range\n"); + err = -EINVAL; + goto out; + } + opt->osd_keepalive_timeout = + msecs_to_jiffies(intval * 1000); break; case Opt_osd_idle_ttl: - opt->osd_idle_ttl = intval; + /* 0 isn't well defined right now, reject it */ + if (intval < 1 || intval > INT_MAX / 1000) { + pr_err("osd_idle_ttl out of range\n"); + err = -EINVAL; + goto out; + } + opt->osd_idle_ttl = msecs_to_jiffies(intval * 1000); break; case Opt_mount_timeout: - opt->mount_timeout = intval; + /* 0 is "wait forever" (i.e. infinite timeout) */ + if (intval < 0 || intval > INT_MAX / 1000) { + pr_err("mount_timeout out of range\n"); + err = -EINVAL; + goto out; + } + opt->mount_timeout = msecs_to_jiffies(intval * 1000); break; case Opt_share: @@ -512,12 +531,14 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) seq_puts(m, "notcp_nodelay,"); if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT) - seq_printf(m, "mount_timeout=%d,", opt->mount_timeout); + seq_printf(m, "mount_timeout=%d,", + jiffies_to_msecs(opt->mount_timeout) / 1000); if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT) - seq_printf(m, "osd_idle_ttl=%d,", opt->osd_idle_ttl); + seq_printf(m, "osd_idle_ttl=%d,", + jiffies_to_msecs(opt->osd_idle_ttl) / 1000); if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT) seq_printf(m, "osdkeepalivetimeout=%d,", - opt->osd_keepalive_timeout); + jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000); /* drop redundant comma */ if (m->count != pos) @@ -627,7 +648,7 @@ static int have_mon_and_osd_map(struct ceph_client *client) int __ceph_open_session(struct ceph_client *client, unsigned long started) { int err; - unsigned long timeout = client->options->mount_timeout * HZ; + unsigned long timeout = client->options->mount_timeout; /* open session, and wait for mon and osd maps */ err = ceph_monc_open_session(&client->monc); @@ -643,7 +664,7 @@ int __ceph_open_session(struct ceph_client *client, unsigned long started) dout("mount waiting for mon_map\n"); err = wait_event_interruptible_timeout(client->auth_wq, have_mon_and_osd_map(client) || (client->auth_err < 0), - timeout); + ceph_timeout_jiffies(timeout)); if (err == -EINTR || err == -ERESTARTSYS) return err; if (client->auth_err < 0) diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 2b3cf05e87b0..0da3bdc116f7 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -298,6 +298,12 @@ void ceph_monc_request_next_osdmap(struct ceph_mon_client *monc) } EXPORT_SYMBOL(ceph_monc_request_next_osdmap); +/* + * Wait for an osdmap with a given epoch. + * + * @epoch: epoch to wait for + * @timeout: in jiffies, 0 means "wait forever" + */ int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch, unsigned long timeout) { @@ -308,11 +314,12 @@ int ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch, while (monc->have_osdmap < epoch) { mutex_unlock(&monc->mutex); - if (timeout != 0 && time_after_eq(jiffies, started + timeout)) + if (timeout && time_after_eq(jiffies, started + timeout)) return -ETIMEDOUT; ret = wait_event_interruptible_timeout(monc->client->auth_wq, - monc->have_osdmap >= epoch, timeout); + monc->have_osdmap >= epoch, + ceph_timeout_jiffies(timeout)); if (ret < 0) return ret; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 4cb4fab46e4f..50033677c0fa 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1097,7 +1097,7 @@ static void __move_osd_to_lru(struct ceph_osd_client *osdc, BUG_ON(!list_empty(&osd->o_osd_lru)); list_add_tail(&osd->o_osd_lru, &osdc->osd_lru); - osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl * HZ; + osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl; } static void maybe_move_osd_to_lru(struct ceph_osd_client *osdc, @@ -1208,7 +1208,7 @@ static struct ceph_osd *__lookup_osd(struct ceph_osd_client *osdc, int o) static void __schedule_osd_timeout(struct ceph_osd_client *osdc) { schedule_delayed_work(&osdc->timeout_work, - osdc->client->options->osd_keepalive_timeout * HZ); + osdc->client->options->osd_keepalive_timeout); } static void __cancel_osd_timeout(struct ceph_osd_client *osdc) @@ -1576,10 +1576,9 @@ static void handle_timeout(struct work_struct *work) { struct ceph_osd_client *osdc = container_of(work, struct ceph_osd_client, timeout_work.work); + struct ceph_options *opts = osdc->client->options; struct ceph_osd_request *req; struct ceph_osd *osd; - unsigned long keepalive = - osdc->client->options->osd_keepalive_timeout * HZ; struct list_head slow_osds; dout("timeout\n"); down_read(&osdc->map_sem); @@ -1595,7 +1594,8 @@ static void handle_timeout(struct work_struct *work) */ INIT_LIST_HEAD(&slow_osds); list_for_each_entry(req, &osdc->req_lru, r_req_lru_item) { - if (time_before(jiffies, req->r_stamp + keepalive)) + if (time_before(jiffies, + req->r_stamp + opts->osd_keepalive_timeout)) break; osd = req->r_osd; @@ -1622,8 +1622,7 @@ static void handle_osds_timeout(struct work_struct *work) struct ceph_osd_client *osdc = container_of(work, struct ceph_osd_client, osds_timeout_work.work); - unsigned long delay = - osdc->client->options->osd_idle_ttl * HZ >> 2; + unsigned long delay = osdc->client->options->osd_idle_ttl / 4; dout("osds timeout\n"); down_read(&osdc->map_sem); @@ -2628,7 +2627,7 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client) osdc->event_count = 0; schedule_delayed_work(&osdc->osds_timeout_work, - round_jiffies_relative(osdc->client->options->osd_idle_ttl * HZ)); + round_jiffies_relative(osdc->client->options->osd_idle_ttl)); err = -ENOMEM; osdc->req_mempool = mempool_create_kmalloc_pool(10, -- cgit v1.2.3 From f66fd9f0952187d274c13c136b74548f792c1925 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 10 Jun 2015 17:26:13 +0800 Subject: ceph: pre-allocate data structure that tracks caps flushing Signed-off-by: Yan, Zheng --- fs/ceph/addr.c | 19 +++++++++++++++---- fs/ceph/caps.c | 26 ++++++++++++++++++++++---- fs/ceph/file.c | 18 ++++++++++++++++-- fs/ceph/inode.c | 15 +++++++++++++-- fs/ceph/mds_client.c | 6 +++++- fs/ceph/super.c | 8 ++++++++ fs/ceph/super.h | 6 +++++- fs/ceph/xattr.c | 20 ++++++++++++++++++-- include/linux/ceph/libceph.h | 1 + 9 files changed, 103 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 5f53ac0d9d7c..7edf3c49e661 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1308,12 +1308,17 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) struct inode *inode = file_inode(vma->vm_file); struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_file_info *fi = vma->vm_file->private_data; + struct ceph_cap_flush *prealloc_cf; struct page *page = vmf->page; loff_t off = page_offset(page); loff_t size = i_size_read(inode); size_t len; int want, got, ret; + prealloc_cf = ceph_alloc_cap_flush(); + if (!prealloc_cf) + return VM_FAULT_SIGBUS; + if (ci->i_inline_version != CEPH_INLINE_NONE) { struct page *locked_page = NULL; if (off == 0) { @@ -1323,8 +1328,10 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ret = ceph_uninline_data(vma->vm_file, locked_page); if (locked_page) unlock_page(locked_page); - if (ret < 0) - return VM_FAULT_SIGBUS; + if (ret < 0) { + ret = VM_FAULT_SIGBUS; + goto out_free; + } } if (off + PAGE_CACHE_SIZE <= size) @@ -1346,7 +1353,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) break; if (ret != -ERESTARTSYS) { WARN_ON(1); - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + goto out_free; } } dout("page_mkwrite %p %llu~%zd got cap refs on %s\n", @@ -1381,7 +1389,8 @@ out: int dirty; spin_lock(&ci->i_ceph_lock); ci->i_inline_version = CEPH_INLINE_NONE; - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR, + &prealloc_cf); spin_unlock(&ci->i_ceph_lock); if (dirty) __mark_inode_dirty(inode, dirty); @@ -1390,6 +1399,8 @@ out: dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %d\n", inode, off, len, ceph_cap_string(got), ret); ceph_put_cap_refs(ci, got); +out_free: + ceph_free_cap_flush(prealloc_cf); return ret; } diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 69a16044ec41..dd7b20adf1d4 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -1356,7 +1356,8 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) * Caller is then responsible for calling __mark_inode_dirty with the * returned flags value. */ -int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) +int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask, + struct ceph_cap_flush **pcf) { struct ceph_mds_client *mdsc = ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; @@ -1376,6 +1377,9 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) ceph_cap_string(was | mask)); ci->i_dirty_caps |= mask; if (was == 0) { + WARN_ON_ONCE(ci->i_prealloc_cap_flush); + swap(ci->i_prealloc_cap_flush, *pcf); + if (!ci->i_head_snapc) { WARN_ON_ONCE(!rwsem_is_locked(&mdsc->snap_rwsem)); ci->i_head_snapc = ceph_get_snap_context( @@ -1391,6 +1395,8 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) ihold(inode); dirty |= I_DIRTY_SYNC; } + } else { + WARN_ON_ONCE(!ci->i_prealloc_cap_flush); } BUG_ON(list_empty(&ci->i_dirty_item)); if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) && @@ -1446,6 +1452,17 @@ static void __add_cap_flushing_to_mdsc(struct ceph_mds_client *mdsc, rb_insert_color(&cf->g_node, &mdsc->cap_flush_tree); } +struct ceph_cap_flush *ceph_alloc_cap_flush(void) +{ + return kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL); +} + +void ceph_free_cap_flush(struct ceph_cap_flush *cf) +{ + if (cf) + kmem_cache_free(ceph_cap_flush_cachep, cf); +} + static u64 __get_oldest_flush_tid(struct ceph_mds_client *mdsc) { struct rb_node *n = rb_first(&mdsc->cap_flush_tree); @@ -1469,11 +1486,12 @@ static int __mark_caps_flushing(struct inode *inode, { struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_inode_info *ci = ceph_inode(inode); - struct ceph_cap_flush *cf; + struct ceph_cap_flush *cf = NULL; int flushing; BUG_ON(ci->i_dirty_caps == 0); BUG_ON(list_empty(&ci->i_dirty_item)); + BUG_ON(!ci->i_prealloc_cap_flush); flushing = ci->i_dirty_caps; dout("__mark_caps_flushing flushing %s, flushing_caps %s -> %s\n", @@ -1484,7 +1502,7 @@ static int __mark_caps_flushing(struct inode *inode, ci->i_dirty_caps = 0; dout(" inode %p now !dirty\n", inode); - cf = kmalloc(sizeof(*cf), GFP_ATOMIC); + swap(cf, ci->i_prealloc_cap_flush); cf->caps = flushing; cf->kick = false; @@ -3075,7 +3093,7 @@ out: cf = list_first_entry(&to_remove, struct ceph_cap_flush, list); list_del(&cf->list); - kfree(cf); + ceph_free_cap_flush(cf); } if (drop) iput(inode); diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 0a76a370d798..8a4eb4d21d3c 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -939,6 +939,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->client->osdc; + struct ceph_cap_flush *prealloc_cf; ssize_t count, written = 0; int err, want, got; loff_t pos; @@ -946,6 +947,10 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; + prealloc_cf = ceph_alloc_cap_flush(); + if (!prealloc_cf) + return -ENOMEM; + mutex_lock(&inode->i_mutex); /* We can write back this queue in page reclaim */ @@ -1050,7 +1055,8 @@ retry_snap: int dirty; spin_lock(&ci->i_ceph_lock); ci->i_inline_version = CEPH_INLINE_NONE; - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR, + &prealloc_cf); spin_unlock(&ci->i_ceph_lock); if (dirty) __mark_inode_dirty(inode, dirty); @@ -1074,6 +1080,7 @@ retry_snap: out: mutex_unlock(&inode->i_mutex); out_unlocked: + ceph_free_cap_flush(prealloc_cf); current->backing_dev_info = NULL; return written ? written : err; } @@ -1270,6 +1277,7 @@ static long ceph_fallocate(struct file *file, int mode, struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->client->osdc; + struct ceph_cap_flush *prealloc_cf; int want, got = 0; int dirty; int ret = 0; @@ -1282,6 +1290,10 @@ static long ceph_fallocate(struct file *file, int mode, if (!S_ISREG(inode->i_mode)) return -EOPNOTSUPP; + prealloc_cf = ceph_alloc_cap_flush(); + if (!prealloc_cf) + return -ENOMEM; + mutex_lock(&inode->i_mutex); if (ceph_snap(inode) != CEPH_NOSNAP) { @@ -1328,7 +1340,8 @@ static long ceph_fallocate(struct file *file, int mode, if (!ret) { spin_lock(&ci->i_ceph_lock); ci->i_inline_version = CEPH_INLINE_NONE; - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR, + &prealloc_cf); spin_unlock(&ci->i_ceph_lock); if (dirty) __mark_inode_dirty(inode, dirty); @@ -1337,6 +1350,7 @@ static long ceph_fallocate(struct file *file, int mode, ceph_put_cap_refs(ci, got); unlock: mutex_unlock(&inode->i_mutex); + ceph_free_cap_flush(prealloc_cf); return ret; } diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 3326302f5884..e86d1a4efc46 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -416,6 +416,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) ci->i_flushing_caps = 0; INIT_LIST_HEAD(&ci->i_dirty_item); INIT_LIST_HEAD(&ci->i_flushing_item); + ci->i_prealloc_cap_flush = NULL; ci->i_cap_flush_tree = RB_ROOT; init_waitqueue_head(&ci->i_cap_wq); ci->i_hold_caps_min = 0; @@ -1720,6 +1721,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) const unsigned int ia_valid = attr->ia_valid; struct ceph_mds_request *req; struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; + struct ceph_cap_flush *prealloc_cf; int issued; int release = 0, dirtied = 0; int mask = 0; @@ -1734,10 +1736,16 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) if (err != 0) return err; + prealloc_cf = ceph_alloc_cap_flush(); + if (!prealloc_cf) + return -ENOMEM; + req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETATTR, USE_AUTH_MDS); - if (IS_ERR(req)) + if (IS_ERR(req)) { + ceph_free_cap_flush(prealloc_cf); return PTR_ERR(req); + } spin_lock(&ci->i_ceph_lock); issued = __ceph_caps_issued(ci, NULL); @@ -1895,7 +1903,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) dout("setattr %p ATTR_FILE ... hrm!\n", inode); if (dirtied) { - inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied); + inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied, + &prealloc_cf); inode->i_ctime = CURRENT_TIME; } @@ -1927,9 +1936,11 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ceph_mdsc_put_request(req); if (mask & CEPH_SETATTR_SIZE) __ceph_do_pending_vmtruncate(inode); + ceph_free_cap_flush(prealloc_cf); return err; out_put: ceph_mdsc_put_request(req); + ceph_free_cap_flush(prealloc_cf); return err; } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 89e4305a94d4..8d73fe9d488b 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1189,6 +1189,10 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, } spin_unlock(&mdsc->cap_dirty_lock); + if (!ci->i_dirty_caps && ci->i_prealloc_cap_flush) { + list_add(&ci->i_prealloc_cap_flush->list, &to_remove); + ci->i_prealloc_cap_flush = NULL; + } } spin_unlock(&ci->i_ceph_lock); while (!list_empty(&to_remove)) { @@ -1196,7 +1200,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, cf = list_first_entry(&to_remove, struct ceph_cap_flush, list); list_del(&cf->list); - kfree(cf); + ceph_free_cap_flush(cf); } while (drop--) iput(inode); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index edeb83c43112..d1c833c321b9 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -622,6 +622,7 @@ static void destroy_fs_client(struct ceph_fs_client *fsc) */ struct kmem_cache *ceph_inode_cachep; struct kmem_cache *ceph_cap_cachep; +struct kmem_cache *ceph_cap_flush_cachep; struct kmem_cache *ceph_dentry_cachep; struct kmem_cache *ceph_file_cachep; @@ -647,6 +648,10 @@ static int __init init_caches(void) SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); if (ceph_cap_cachep == NULL) goto bad_cap; + ceph_cap_flush_cachep = KMEM_CACHE(ceph_cap_flush, + SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); + if (ceph_cap_flush_cachep == NULL) + goto bad_cap_flush; ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); @@ -665,6 +670,8 @@ static int __init init_caches(void) bad_file: kmem_cache_destroy(ceph_dentry_cachep); bad_dentry: + kmem_cache_destroy(ceph_cap_flush_cachep); +bad_cap_flush: kmem_cache_destroy(ceph_cap_cachep); bad_cap: kmem_cache_destroy(ceph_inode_cachep); @@ -681,6 +688,7 @@ static void destroy_caches(void) kmem_cache_destroy(ceph_inode_cachep); kmem_cache_destroy(ceph_cap_cachep); + kmem_cache_destroy(ceph_cap_flush_cachep); kmem_cache_destroy(ceph_dentry_cachep); kmem_cache_destroy(ceph_file_cachep); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index e7f13f742357..4415e977d72b 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -309,6 +309,7 @@ struct ceph_inode_info { /* we need to track cap writeback on a per-cap-bit basis, to allow * overlapping, pipelined cap flushes to the mds. we can probably * reduce the tid to 8 bits if we're concerned about inode size. */ + struct ceph_cap_flush *i_prealloc_cap_flush; struct rb_root i_cap_flush_tree; wait_queue_head_t i_cap_wq; /* threads waiting on a capability */ unsigned long i_hold_caps_min; /* jiffies */ @@ -578,7 +579,10 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci) { return ci->i_dirty_caps | ci->i_flushing_caps; } -extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); +extern struct ceph_cap_flush *ceph_alloc_cap_flush(void); +extern void ceph_free_cap_flush(struct ceph_cap_flush *cf); +extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask, + struct ceph_cap_flush **pcf); extern int __ceph_caps_revoking_other(struct ceph_inode_info *ci, struct ceph_cap *ocap, int mask); diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index c6f7d9b82085..819163d8313b 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -912,6 +912,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, struct ceph_vxattr *vxattr; struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; + struct ceph_cap_flush *prealloc_cf = NULL; int issued; int err; int dirty = 0; @@ -950,6 +951,10 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, if (!xattr) goto out; + prealloc_cf = ceph_alloc_cap_flush(); + if (!prealloc_cf) + goto out; + spin_lock(&ci->i_ceph_lock); retry: issued = __ceph_caps_issued(ci, NULL); @@ -991,7 +996,8 @@ retry: flags, value ? 1 : -1, &xattr); if (!err) { - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL, + &prealloc_cf); ci->i_xattrs.dirty = true; inode->i_ctime = CURRENT_TIME; } @@ -1001,6 +1007,7 @@ retry: up_read(&mdsc->snap_rwsem); if (dirty) __mark_inode_dirty(inode, dirty); + ceph_free_cap_flush(prealloc_cf); return err; do_sync: @@ -1010,6 +1017,7 @@ do_sync_unlocked: up_read(&mdsc->snap_rwsem); err = ceph_sync_setxattr(dentry, name, value, size, flags); out: + ceph_free_cap_flush(prealloc_cf); kfree(newname); kfree(newval); kfree(xattr); @@ -1062,6 +1070,7 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) struct ceph_vxattr *vxattr; struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; + struct ceph_cap_flush *prealloc_cf = NULL; int issued; int err; int required_blob_size; @@ -1079,6 +1088,10 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) goto do_sync_unlocked; + prealloc_cf = ceph_alloc_cap_flush(); + if (!prealloc_cf) + return -ENOMEM; + err = -ENOMEM; spin_lock(&ci->i_ceph_lock); retry: @@ -1120,7 +1133,8 @@ retry: err = __remove_xattr_by_name(ceph_inode(inode), name); - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL, + &prealloc_cf); ci->i_xattrs.dirty = true; inode->i_ctime = CURRENT_TIME; spin_unlock(&ci->i_ceph_lock); @@ -1128,12 +1142,14 @@ retry: up_read(&mdsc->snap_rwsem); if (dirty) __mark_inode_dirty(inode, dirty); + ceph_free_cap_flush(prealloc_cf); return err; do_sync: spin_unlock(&ci->i_ceph_lock); do_sync_unlocked: if (lock_snap_rwsem) up_read(&mdsc->snap_rwsem); + ceph_free_cap_flush(prealloc_cf); err = ceph_send_removexattr(dentry, name); return err; } diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index d73a569f9bf5..9ebee53d3bf5 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -174,6 +174,7 @@ static inline int calc_pages_for(u64 off, u64 len) extern struct kmem_cache *ceph_inode_cachep; extern struct kmem_cache *ceph_cap_cachep; +extern struct kmem_cache *ceph_cap_flush_cachep; extern struct kmem_cache *ceph_dentry_cachep; extern struct kmem_cache *ceph_file_cachep; -- cgit v1.2.3 From b459be739f97e2062b2ba77cfe8ea198dbd58904 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 12 Jun 2015 13:21:07 +0300 Subject: crush: sync up with userspace .. up to ceph.git commit 1db1abc8328d ("crush: eliminate ad hoc diff between kernel and userspace"). This fixes a bunch of recently pulled coding style issues and makes includes a bit cleaner. A patch "crush:Make the function crush_ln static" from Nicholas Krause is folded in as crush_ln() has been made static in userspace as well. Signed-off-by: Ilya Dryomov --- include/linux/crush/crush.h | 40 +++++++++++- include/linux/crush/hash.h | 6 ++ include/linux/crush/mapper.h | 2 +- net/ceph/crush/crush.c | 13 ++-- net/ceph/crush/crush_ln_table.h | 32 +++++----- net/ceph/crush/hash.c | 8 ++- net/ceph/crush/mapper.c | 137 ++++++++++++++++++++++++++-------------- 7 files changed, 160 insertions(+), 78 deletions(-) (limited to 'include') diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h index 48a1a7d100f1..48b49305716b 100644 --- a/include/linux/crush/crush.h +++ b/include/linux/crush/crush.h @@ -1,7 +1,11 @@ #ifndef CEPH_CRUSH_CRUSH_H #define CEPH_CRUSH_CRUSH_H -#include +#ifdef __KERNEL__ +# include +#else +# include "crush_compat.h" +#endif /* * CRUSH is a pseudo-random data distribution algorithm that @@ -20,7 +24,11 @@ #define CRUSH_MAGIC 0x00010000ul /* for detecting algorithm revisions */ #define CRUSH_MAX_DEPTH 10 /* max crush hierarchy depth */ +#define CRUSH_MAX_RULESET (1<<8) /* max crush ruleset number */ +#define CRUSH_MAX_RULES CRUSH_MAX_RULESET /* should be the same as max rulesets */ +#define CRUSH_MAX_DEVICE_WEIGHT (100u * 0x10000u) +#define CRUSH_MAX_BUCKET_WEIGHT (65535u * 0x10000u) #define CRUSH_ITEM_UNDEF 0x7ffffffe /* undefined result (internal use only) */ #define CRUSH_ITEM_NONE 0x7fffffff /* no result */ @@ -108,6 +116,15 @@ enum { }; extern const char *crush_bucket_alg_name(int alg); +/* + * although tree was a legacy algorithm, it has been buggy, so + * exclude it. + */ +#define CRUSH_LEGACY_ALLOWED_BUCKET_ALGS ( \ + (1 << CRUSH_BUCKET_UNIFORM) | \ + (1 << CRUSH_BUCKET_LIST) | \ + (1 << CRUSH_BUCKET_STRAW)) + struct crush_bucket { __s32 id; /* this'll be negative */ __u16 type; /* non-zero; type=0 is reserved for devices */ @@ -174,7 +191,7 @@ struct crush_map { /* choose local attempts using a fallback permutation before * re-descent */ __u32 choose_local_fallback_tries; - /* choose attempts before giving up */ + /* choose attempts before giving up */ __u32 choose_total_tries; /* attempt chooseleaf inner descent once for firstn mode; on * reject retry outer descent. Note that this does *not* @@ -187,6 +204,25 @@ struct crush_map { * that want to limit reshuffling, a value of 3 or 4 will make the * mappings line up a bit better with previous mappings. */ __u8 chooseleaf_vary_r; + +#ifndef __KERNEL__ + /* + * version 0 (original) of straw_calc has various flaws. version 1 + * fixes a few of them. + */ + __u8 straw_calc_version; + + /* + * allowed bucket algs is a bitmask, here the bit positions + * are CRUSH_BUCKET_*. note that these are *bits* and + * CRUSH_BUCKET_* values are not, so we need to or together (1 + * << CRUSH_BUCKET_WHATEVER). The 0th bit is not used to + * minimize confusion (bucket type values start at 1). + */ + __u32 allowed_bucket_algs; + + __u32 *choose_tries; +#endif }; diff --git a/include/linux/crush/hash.h b/include/linux/crush/hash.h index 91e884230d5d..d1d90258242e 100644 --- a/include/linux/crush/hash.h +++ b/include/linux/crush/hash.h @@ -1,6 +1,12 @@ #ifndef CEPH_CRUSH_HASH_H #define CEPH_CRUSH_HASH_H +#ifdef __KERNEL__ +# include +#else +# include "crush_compat.h" +#endif + #define CRUSH_HASH_RJENKINS1 0 #define CRUSH_HASH_DEFAULT CRUSH_HASH_RJENKINS1 diff --git a/include/linux/crush/mapper.h b/include/linux/crush/mapper.h index eab367446eea..5dfd5b1125d2 100644 --- a/include/linux/crush/mapper.h +++ b/include/linux/crush/mapper.h @@ -8,7 +8,7 @@ * LGPL2 */ -#include +#include "crush.h" extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, int size); extern int crush_do_rule(const struct crush_map *map, diff --git a/net/ceph/crush/crush.c b/net/ceph/crush/crush.c index 9d84ce4ea0df..80d7c3a97cb8 100644 --- a/net/ceph/crush/crush.c +++ b/net/ceph/crush/crush.c @@ -1,15 +1,11 @@ - #ifdef __KERNEL__ # include +# include #else -# include -# include -# define kfree(x) do { if (x) free(x); } while (0) -# define BUG_ON(x) assert(!(x)) +# include "crush_compat.h" +# include "crush.h" #endif -#include - const char *crush_bucket_alg_name(int alg) { switch (alg) { @@ -134,6 +130,9 @@ void crush_destroy(struct crush_map *map) kfree(map->rules); } +#ifndef __KERNEL__ + kfree(map->choose_tries); +#endif kfree(map); } diff --git a/net/ceph/crush/crush_ln_table.h b/net/ceph/crush/crush_ln_table.h index 6192c7fc958c..aae534c901a4 100644 --- a/net/ceph/crush/crush_ln_table.h +++ b/net/ceph/crush/crush_ln_table.h @@ -10,20 +10,20 @@ * */ -#if defined(__linux__) -#include -#elif defined(__FreeBSD__) -#include -#endif - #ifndef CEPH_CRUSH_LN_H #define CEPH_CRUSH_LN_H +#ifdef __KERNEL__ +# include +#else +# include "crush_compat.h" +#endif -// RH_LH_tbl[2*k] = 2^48/(1.0+k/128.0) -// RH_LH_tbl[2*k+1] = 2^48*log2(1.0+k/128.0) - -static int64_t __RH_LH_tbl[128*2+2] = { +/* + * RH_LH_tbl[2*k] = 2^48/(1.0+k/128.0) + * RH_LH_tbl[2*k+1] = 2^48*log2(1.0+k/128.0) + */ +static __s64 __RH_LH_tbl[128*2+2] = { 0x0001000000000000ll, 0x0000000000000000ll, 0x0000fe03f80fe040ll, 0x000002dfca16dde1ll, 0x0000fc0fc0fc0fc1ll, 0x000005b9e5a170b4ll, 0x0000fa232cf25214ll, 0x0000088e68ea899all, 0x0000f83e0f83e0f9ll, 0x00000b5d69bac77ell, 0x0000f6603d980f67ll, 0x00000e26fd5c8555ll, @@ -89,11 +89,12 @@ static int64_t __RH_LH_tbl[128*2+2] = { 0x0000820820820821ll, 0x0000fa2f045e7832ll, 0x000081848da8faf1ll, 0x0000fba577877d7dll, 0x0000810204081021ll, 0x0000fd1a708bbe11ll, 0x0000808080808081ll, 0x0000fe8df263f957ll, 0x0000800000000000ll, 0x0000ffff00000000ll, - }; - +}; - // LL_tbl[k] = 2^48*log2(1.0+k/2^15); -static int64_t __LL_tbl[256] = { +/* + * LL_tbl[k] = 2^48*log2(1.0+k/2^15) + */ +static __s64 __LL_tbl[256] = { 0x0000000000000000ull, 0x00000002e2a60a00ull, 0x000000070cb64ec5ull, 0x00000009ef50ce67ull, 0x0000000cd1e588fdull, 0x0000000fb4747e9cull, 0x0000001296fdaf5eull, 0x0000001579811b58ull, 0x000000185bfec2a1ull, 0x0000001b3e76a552ull, 0x0000001e20e8c380ull, 0x0000002103551d43ull, @@ -160,7 +161,4 @@ static int64_t __LL_tbl[256] = { 0x000002d4562d2ec6ull, 0x000002d73330209dull, 0x000002da102d63b0ull, 0x000002dced24f814ull, }; - - - #endif diff --git a/net/ceph/crush/hash.c b/net/ceph/crush/hash.c index 5bb63e37a8a1..ed123af49eba 100644 --- a/net/ceph/crush/hash.c +++ b/net/ceph/crush/hash.c @@ -1,6 +1,8 @@ - -#include -#include +#ifdef __KERNEL__ +# include +#else +# include "hash.h" +#endif /* * Robert Jenkins' function for mixing 32-bit values diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c index 7568cb59b9e5..393bfb22d5bb 100644 --- a/net/ceph/crush/mapper.c +++ b/net/ceph/crush/mapper.c @@ -1,27 +1,31 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2015 Intel Corporation All Rights Reserved + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ #ifdef __KERNEL__ # include # include # include # include -# ifndef dprintk -# define dprintk(args...) -# endif +# include +# include #else -# include -# include -# include -# include -# define BUG_ON(x) assert(!(x)) -# define dprintk(args...) /* printf(args) */ -# define kmalloc(x, f) malloc(x) -# define kfree(x) free(x) +# include "crush_compat.h" +# include "crush.h" +# include "hash.h" #endif - -#include -#include #include "crush_ln_table.h" +#define dprintk(args...) /* printf(args) */ + /* * Implement the core CRUSH mapping algorithm. */ @@ -139,7 +143,7 @@ static int bucket_list_choose(struct crush_bucket_list *bucket, int i; for (i = bucket->h.size-1; i >= 0; i--) { - __u64 w = crush_hash32_4(bucket->h.hash,x, bucket->h.items[i], + __u64 w = crush_hash32_4(bucket->h.hash, x, bucket->h.items[i], r, bucket->h.id); w &= 0xffff; dprintk("list_choose i=%d x=%d r=%d item %d weight %x " @@ -238,43 +242,46 @@ static int bucket_straw_choose(struct crush_bucket_straw *bucket, return bucket->h.items[high]; } -// compute 2^44*log2(input+1) -uint64_t crush_ln(unsigned xin) +/* compute 2^44*log2(input+1) */ +static __u64 crush_ln(unsigned int xin) { - unsigned x=xin, x1; - int iexpon, index1, index2; - uint64_t RH, LH, LL, xl64, result; + unsigned int x = xin, x1; + int iexpon, index1, index2; + __u64 RH, LH, LL, xl64, result; - x++; + x++; - // normalize input - iexpon = 15; - while(!(x&0x18000)) { x<<=1; iexpon--; } + /* normalize input */ + iexpon = 15; + while (!(x & 0x18000)) { + x <<= 1; + iexpon--; + } - index1 = (x>>8)<<1; - // RH ~ 2^56/index1 - RH = __RH_LH_tbl[index1 - 256]; - // LH ~ 2^48 * log2(index1/256) - LH = __RH_LH_tbl[index1 + 1 - 256]; + index1 = (x >> 8) << 1; + /* RH ~ 2^56/index1 */ + RH = __RH_LH_tbl[index1 - 256]; + /* LH ~ 2^48 * log2(index1/256) */ + LH = __RH_LH_tbl[index1 + 1 - 256]; - // RH*x ~ 2^48 * (2^15 + xf), xf<2^8 - xl64 = (int64_t)x * RH; - xl64 >>= 48; - x1 = xl64; + /* RH*x ~ 2^48 * (2^15 + xf), xf<2^8 */ + xl64 = (__s64)x * RH; + xl64 >>= 48; + x1 = xl64; - result = iexpon; - result <<= (12 + 32); + result = iexpon; + result <<= (12 + 32); - index2 = x1 & 0xff; - // LL ~ 2^48*log2(1.0+index2/2^15) - LL = __LL_tbl[index2]; + index2 = x1 & 0xff; + /* LL ~ 2^48*log2(1.0+index2/2^15) */ + LL = __LL_tbl[index2]; - LH = LH + LL; + LH = LH + LL; - LH >>= (48-12 - 32); - result += LH; + LH >>= (48 - 12 - 32); + result += LH; - return result; + return result; } @@ -290,9 +297,9 @@ uint64_t crush_ln(unsigned xin) static int bucket_straw2_choose(struct crush_bucket_straw2 *bucket, int x, int r) { - unsigned i, high = 0; - unsigned u; - unsigned w; + unsigned int i, high = 0; + unsigned int u; + unsigned int w; __s64 ln, draw, high_draw = 0; for (i = 0; i < bucket->h.size; i++) { @@ -567,6 +574,10 @@ reject: out[outpos] = item; outpos++; count--; +#ifndef __KERNEL__ + if (map->choose_tries && ftotal <= map->choose_total_tries) + map->choose_tries[ftotal]++; +#endif } dprintk("CHOOSE returns %d\n", outpos); @@ -610,6 +621,20 @@ static void crush_choose_indep(const struct crush_map *map, } for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) { +#ifdef DEBUG_INDEP + if (out2 && ftotal) { + dprintk("%u %d a: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out[rep]); + } + dprintk("\n"); + dprintk("%u %d b: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out2[rep]); + } + dprintk("\n"); + } +#endif for (rep = outpos; rep < endpos; rep++) { if (out[rep] != CRUSH_ITEM_UNDEF) continue; @@ -726,6 +751,24 @@ static void crush_choose_indep(const struct crush_map *map, out2[rep] = CRUSH_ITEM_NONE; } } +#ifndef __KERNEL__ + if (map->choose_tries && ftotal <= map->choose_total_tries) + map->choose_tries[ftotal]++; +#endif +#ifdef DEBUG_INDEP + if (out2) { + dprintk("%u %d a: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out[rep]); + } + dprintk("\n"); + dprintk("%u %d b: ", ftotal, left); + for (rep = outpos; rep < endpos; rep++) { + dprintk(" %d", out2[rep]); + } + dprintk("\n"); + } +#endif } /** @@ -884,7 +927,7 @@ int crush_do_rule(const struct crush_map *map, 0); } else { out_size = ((numrep < (result_max-osize)) ? - numrep : (result_max-osize)); + numrep : (result_max-osize)); crush_choose_indep( map, map->buckets[-1-w[i]], @@ -930,5 +973,3 @@ int crush_do_rule(const struct crush_map *map, } return result_len; } - - -- cgit v1.2.3 From 7c494375b773497228502133879072a9e959c063 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 1 Jun 2015 10:35:16 -0700 Subject: Input: improve parsing OF parameters for touchscreens When applying touchscreen parameters specified in device tree let's make sure we keep whatever setup was done by the driver and not reset the missing values to zero. Reported-by: Pavel Machek Tested-by: Pavel Machek Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 2 +- drivers/input/touchscreen/of_touchscreen.c | 69 +++++++++++++++++++----------- drivers/input/touchscreen/tsc2005.c | 2 +- include/linux/input/touchscreen.h | 5 ++- 4 files changed, 49 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 29d179a1953b..394b1de9a2a3 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1041,7 +1041,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, 0, tsdata->num_y * 64 - 1, 0, 0); if (!pdata) - touchscreen_parse_of_params(input); + touchscreen_parse_of_params(input, true); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); if (error) { diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index b82b5207c78b..806cd0ad160f 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -14,14 +14,22 @@ #include #include -static u32 of_get_optional_u32(struct device_node *np, - const char *property) +static bool touchscreen_get_prop_u32(struct device_node *np, + const char *property, + unsigned int default_value, + unsigned int *value) { - u32 val = 0; + u32 val; + int error; - of_property_read_u32(np, property, &val); + error = of_property_read_u32(np, property, &val); + if (error) { + *value = default_value; + return false; + } - return val; + *value = val; + return true; } static void touchscreen_set_params(struct input_dev *dev, @@ -54,34 +62,45 @@ static void touchscreen_set_params(struct input_dev *dev, * input device accordingly. The function keeps previously setuped default * values if no value is specified via DT. */ -void touchscreen_parse_of_params(struct input_dev *dev) +void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) { struct device_node *np = dev->dev.parent->of_node; - u32 maximum, fuzz; + unsigned int axis; + unsigned int maximum, fuzz; + bool data_present; input_alloc_absinfo(dev); if (!dev->absinfo) return; - maximum = of_get_optional_u32(np, "touchscreen-size-x"); - fuzz = of_get_optional_u32(np, "touchscreen-fuzz-x"); - if (maximum || fuzz) { - touchscreen_set_params(dev, ABS_X, maximum, fuzz); - touchscreen_set_params(dev, ABS_MT_POSITION_X, maximum, fuzz); - } + axis = multitouch ? ABS_MT_POSITION_X : ABS_X; + data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", + input_abs_get_max(dev, axis), + &maximum) | + touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", + input_abs_get_fuzz(dev, axis), + &fuzz); + if (data_present) + touchscreen_set_params(dev, axis, maximum, fuzz); - maximum = of_get_optional_u32(np, "touchscreen-size-y"); - fuzz = of_get_optional_u32(np, "touchscreen-fuzz-y"); - if (maximum || fuzz) { - touchscreen_set_params(dev, ABS_Y, maximum, fuzz); - touchscreen_set_params(dev, ABS_MT_POSITION_Y, maximum, fuzz); - } + axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; + data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", + input_abs_get_max(dev, axis), + &maximum) | + touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", + input_abs_get_fuzz(dev, axis), + &fuzz); + if (data_present) + touchscreen_set_params(dev, axis, maximum, fuzz); - maximum = of_get_optional_u32(np, "touchscreen-max-pressure"); - fuzz = of_get_optional_u32(np, "touchscreen-fuzz-pressure"); - if (maximum || fuzz) { - touchscreen_set_params(dev, ABS_PRESSURE, maximum, fuzz); - touchscreen_set_params(dev, ABS_MT_PRESSURE, maximum, fuzz); - } + axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; + data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", + input_abs_get_max(dev, axis), + &maximum) | + touchscreen_get_prop_u32(np, "touchscreen-fuzz-pressure", + input_abs_get_fuzz(dev, axis), + &fuzz); + if (data_present) + touchscreen_set_params(dev, axis, maximum, fuzz); } EXPORT_SYMBOL(touchscreen_parse_of_params); diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 72657c579430..d8c025b0f88c 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -709,7 +709,7 @@ static int tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); if (np) - touchscreen_parse_of_params(input_dev); + touchscreen_parse_of_params(input_dev, false); input_dev->open = tsc2005_open; input_dev->close = tsc2005_close; diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h index 08a5ef6e8f25..eecc9ea6cd58 100644 --- a/include/linux/input/touchscreen.h +++ b/include/linux/input/touchscreen.h @@ -12,9 +12,10 @@ #include #ifdef CONFIG_OF -void touchscreen_parse_of_params(struct input_dev *dev); +void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch); #else -static inline void touchscreen_parse_of_params(struct input_dev *dev) +static inline void touchscreen_parse_of_params(struct input_dev *dev, + bool multitouch) { } #endif -- cgit v1.2.3 From 6c5a0d891543873aefc3aaf846c1e7afe0982ff9 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 27 Jun 2015 11:45:46 -0400 Subject: NFSv4.2: LAYOUTSTATS is optional to implement Make it so, by checking the return value for NFS4ERR_MOTSUPP and caching the information as a server capability. Signed-off-by: Trond Myklebust --- fs/nfs/nfs42proc.c | 10 ++++++++-- fs/nfs/nfs4proc.c | 3 ++- fs/nfs/pnfs.c | 3 +++ include/linux/nfs_fs_sb.h | 1 + 4 files changed, 14 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index 06c74cd93875..f486b80f927a 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -189,9 +189,15 @@ nfs42_layoutstat_done(struct rpc_task *task, void *calldata) if (!nfs4_sequence_done(task, &data->res.seq_res)) return; - /* well, we don't care about errors at all! */ - if (task->tk_status) + switch (task->tk_status) { + case 0: + break; + case -ENOTSUPP: + case -EOPNOTSUPP: + NFS_SERVER(data->inode)->caps &= ~NFS_CAP_LAYOUTSTATS; + default: dprintk("%s server returns %d\n", __func__, task->tk_status); + } } static void diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 643ce3a91b22..8eab42407d39 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8635,7 +8635,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | NFS_CAP_ATOMIC_OPEN_V1 | NFS_CAP_ALLOCATE | NFS_CAP_DEALLOCATE - | NFS_CAP_SEEK, + | NFS_CAP_SEEK + | NFS_CAP_LAYOUTSTATS, .init_client = nfs41_init_client, .shutdown_client = nfs41_shutdown_client, .match_stateid = nfs41_match_stateid, diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 40bacebb5b97..0ba9a02c9566 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -2266,6 +2266,9 @@ pnfs_report_layoutstat(struct inode *inode) if (!pnfs_enabled_sb(server) || !ld->prepare_layoutstats) goto out; + if (!nfs_server_capable(inode, NFS_CAP_LAYOUTSTATS)) + goto out; + if (test_and_set_bit(NFS_INO_LAYOUTSTATS, &nfsi->flags)) goto out; diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 5e1273d4de14..a2ea1491d3df 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -237,5 +237,6 @@ struct nfs_server { #define NFS_CAP_SEEK (1U << 19) #define NFS_CAP_ALLOCATE (1U << 20) #define NFS_CAP_DEALLOCATE (1U << 21) +#define NFS_CAP_LAYOUTSTATS (1U << 22) #endif -- cgit v1.2.3 From 2b48d323b26c37555df3447e11ab9e962eccdc26 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 19 Jun 2015 17:31:29 +0200 Subject: drm/amdgpu: add optional dependencies to the CS IOCTL v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: remove unrelated whitespace change, fix C comment Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 59 +++++++++++++++++++++++++++++++++- include/uapi/drm/amdgpu_drm.h | 9 ++++++ 2 files changed, 67 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 84ba1d1bf327..d63135bf29c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -226,6 +226,9 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) } break; + case AMDGPU_CHUNK_ID_DEPENDENCIES: + break; + default: r = -EINVAL; goto out; @@ -663,6 +666,55 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev, return 0; } +static int amdgpu_cs_dependencies(struct amdgpu_device *adev, + struct amdgpu_cs_parser *p) +{ + struct amdgpu_ib *ib; + int i, j, r; + + if (!p->num_ibs) + return 0; + + /* Add dependencies to first IB */ + ib = &p->ibs[0]; + for (i = 0; i < p->nchunks; ++i) { + struct drm_amdgpu_cs_chunk_dep *deps; + struct amdgpu_cs_chunk *chunk; + unsigned num_deps; + + chunk = &p->chunks[i]; + + if (chunk->chunk_id != AMDGPU_CHUNK_ID_DEPENDENCIES) + continue; + + deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata; + num_deps = chunk->length_dw * 4 / + sizeof(struct drm_amdgpu_cs_chunk_dep); + + for (j = 0; j < num_deps; ++j) { + struct amdgpu_fence *fence; + struct amdgpu_ring *ring; + + r = amdgpu_cs_get_ring(adev, deps[j].ip_type, + deps[j].ip_instance, + deps[j].ring, &ring); + if (r) + return r; + + r = amdgpu_fence_recreate(ring, p->filp, + deps[j].handle, + &fence); + if (r) + return r; + + amdgpu_sync_fence(&ib->sync, fence); + amdgpu_fence_unref(&fence); + } + } + + return 0; +} + int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct amdgpu_device *adev = dev->dev_private; @@ -697,11 +749,16 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) else DRM_ERROR("Failed to process the buffer list %d!\n", r); } - } else { + } + + if (!r) { reserved_buffers = true; r = amdgpu_cs_ib_fill(adev, &parser); } + if (!r) + r = amdgpu_cs_dependencies(adev, &parser); + if (r) { amdgpu_cs_parser_fini(&parser, r, reserved_buffers); up_read(&adev->exclusive_lock); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index d3f4832db289..8edf10420361 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -348,6 +348,7 @@ struct drm_amdgpu_gem_va { #define AMDGPU_CHUNK_ID_IB 0x01 #define AMDGPU_CHUNK_ID_FENCE 0x02 +#define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03 struct drm_amdgpu_cs_chunk { uint32_t chunk_id; @@ -399,6 +400,14 @@ struct drm_amdgpu_cs_chunk_ib { uint32_t ring; }; +struct drm_amdgpu_cs_chunk_dep { + uint32_t ip_type; + uint32_t ip_instance; + uint32_t ring; + uint32_t ctx_id; + uint64_t handle; +}; + struct drm_amdgpu_cs_chunk_fence { uint32_t handle; uint32_t offset; -- cgit v1.2.3 From fc220f6580be80c36dfba9964b2fd71ceb1d3d97 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 29 Jun 2015 17:12:20 +0200 Subject: drm/amdgpu: add flag to delay VM updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 6 +++--- include/uapi/drm/amdgpu_drm.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index c3ea3635e1fc..975edb1000a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -525,8 +525,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - invalid_flags = ~(AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | - AMDGPU_VM_PAGE_EXECUTABLE); + invalid_flags = ~(AMDGPU_VM_DELAY_UPDATE | AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | AMDGPU_VM_PAGE_EXECUTABLE); if ((args->flags & invalid_flags)) { dev_err(&dev->pdev->dev, "invalid flags 0x%08X vs 0x%08X\n", args->flags, invalid_flags); @@ -579,7 +579,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, break; } - if (!r) + if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE)) amdgpu_gem_va_update_vm(adev, bo_va); drm_gem_object_unreference_unlocked(gobj); diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 8edf10420361..b6fce900a833 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -313,6 +313,9 @@ struct drm_amdgpu_gem_op { #define AMDGPU_VA_OP_MAP 1 #define AMDGPU_VA_OP_UNMAP 2 +/* Delay the page table update till the next CS */ +#define AMDGPU_VM_DELAY_UPDATE (1 << 0) + /* Mapping flags */ /* readable mapping */ #define AMDGPU_VM_PAGE_READABLE (1 << 1) -- cgit v1.2.3 From 31f02455455d405320e2f749696bef4e02903b35 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 30 Jun 2015 12:07:17 -0400 Subject: sparse: fix misplaced __pmem definition Move the definition of __pmem outside of CONFIG_SPARSE_RCU_POINTER to fix: drivers/nvdimm/pmem.c:198:17: sparse: too many arguments for function __builtin_expect drivers/nvdimm/pmem.c:36:33: sparse: expected ; at end of declaration drivers/nvdimm/pmem.c:48:21: sparse: void declaration ...due to __pmem failing to be defined in some configurations when CONFIG_SPARSE_RCU_POINTER=y. Reported-by: kbuild test robot Reported-by: Dan Carpenter Signed-off-by: Dan Williams --- include/linux/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 26fc8bc77f85..d8fbd500330e 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -17,11 +17,11 @@ # define __release(x) __context__(x,-1) # define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) # define __percpu __attribute__((noderef, address_space(3))) +# define __pmem __attribute__((noderef, address_space(5))) #ifdef CONFIG_SPARSE_RCU_POINTER # define __rcu __attribute__((noderef, address_space(4))) #else # define __rcu -# define __pmem __attribute__((noderef, address_space(5))) #endif extern void __chk_user_ptr(const volatile void __user *); extern void __chk_io_ptr(const volatile void __iomem *); -- cgit v1.2.3 From 8a81252b774b53e628a8a0fe18e2b8fc236d92cc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 30 Jun 2015 15:54:08 +0200 Subject: fs/file.c: don't acquire files->file_lock in fd_install() Mateusz Guzik reported : Currently obtaining a new file descriptor results in locking fdtable twice - once in order to reserve a slot and second time to fill it. Holding the spinlock in __fd_install() is needed in case a resize is done, or to prevent a resize. Mateusz provided an RFC patch and a micro benchmark : http://people.redhat.com/~mguzik/pipebench.c A resize is an unlikely operation in a process lifetime, as table size is at least doubled at every resize. We can use RCU instead of the spinlock. __fd_install() must wait if a resize is in progress. The resize must block new __fd_install() callers from starting, and wait that ongoing install are finished (synchronize_sched()) resize should be attempted by a single thread to not waste resources. rcu_sched variant is used, as __fd_install() and expand_fdtable() run from process context. It gives us a ~30% speedup using pipebench on a dual Intel(R) Xeon(R) CPU E5-2696 v2 @ 2.50GHz Signed-off-by: Eric Dumazet Reported-by: Mateusz Guzik Acked-by: Mateusz Guzik Tested-by: Mateusz Guzik Signed-off-by: Al Viro --- Documentation/filesystems/porting | 4 +++ fs/file.c | 67 ++++++++++++++++++++++++++++----------- include/linux/fdtable.h | 3 ++ 3 files changed, 55 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 3eae250254d5..ec5456113072 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -500,3 +500,7 @@ in your dentry operations instead. dentry, it does not get nameidata at all and it gets called only when cookie is non-NULL. Note that link body isn't available anymore, so if you need it, store it as cookie. +-- +[mandatory] + __fd_install() & fd_install() can now sleep. Callers should not + hold a spinlock or other resources that do not allow a schedule. diff --git a/fs/file.c b/fs/file.c index 93c5f89c248b..3d2eb4c542a4 100644 --- a/fs/file.c +++ b/fs/file.c @@ -147,6 +147,13 @@ static int expand_fdtable(struct files_struct *files, int nr) spin_unlock(&files->file_lock); new_fdt = alloc_fdtable(nr); + + /* make sure all __fd_install() have seen resize_in_progress + * or have finished their rcu_read_lock_sched() section. + */ + if (atomic_read(&files->count) > 1) + synchronize_sched(); + spin_lock(&files->file_lock); if (!new_fdt) return -ENOMEM; @@ -158,21 +165,14 @@ static int expand_fdtable(struct files_struct *files, int nr) __free_fdtable(new_fdt); return -EMFILE; } - /* - * Check again since another task may have expanded the fd table while - * we dropped the lock - */ cur_fdt = files_fdtable(files); - if (nr >= cur_fdt->max_fds) { - /* Continue as planned */ - copy_fdtable(new_fdt, cur_fdt); - rcu_assign_pointer(files->fdt, new_fdt); - if (cur_fdt != &files->fdtab) - call_rcu(&cur_fdt->rcu, free_fdtable_rcu); - } else { - /* Somebody else expanded, so undo our attempt */ - __free_fdtable(new_fdt); - } + BUG_ON(nr < cur_fdt->max_fds); + copy_fdtable(new_fdt, cur_fdt); + rcu_assign_pointer(files->fdt, new_fdt); + if (cur_fdt != &files->fdtab) + call_rcu(&cur_fdt->rcu, free_fdtable_rcu); + /* coupled with smp_rmb() in __fd_install() */ + smp_wmb(); return 1; } @@ -185,21 +185,38 @@ static int expand_fdtable(struct files_struct *files, int nr) * The files->file_lock should be held on entry, and will be held on exit. */ static int expand_files(struct files_struct *files, int nr) + __releases(files->file_lock) + __acquires(files->file_lock) { struct fdtable *fdt; + int expanded = 0; +repeat: fdt = files_fdtable(files); /* Do we need to expand? */ if (nr < fdt->max_fds) - return 0; + return expanded; /* Can we expand? */ if (nr >= sysctl_nr_open) return -EMFILE; + if (unlikely(files->resize_in_progress)) { + spin_unlock(&files->file_lock); + expanded = 1; + wait_event(files->resize_wait, !files->resize_in_progress); + spin_lock(&files->file_lock); + goto repeat; + } + /* All good, so we try */ - return expand_fdtable(files, nr); + files->resize_in_progress = true; + expanded = expand_fdtable(files, nr); + files->resize_in_progress = false; + + wake_up_all(&files->resize_wait); + return expanded; } static inline void __set_close_on_exec(int fd, struct fdtable *fdt) @@ -256,6 +273,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) atomic_set(&newf->count, 1); spin_lock_init(&newf->file_lock); + newf->resize_in_progress = false; + init_waitqueue_head(&newf->resize_wait); newf->next_fd = 0; new_fdt = &newf->fdtab; new_fdt->max_fds = NR_OPEN_DEFAULT; @@ -553,11 +572,21 @@ void __fd_install(struct files_struct *files, unsigned int fd, struct file *file) { struct fdtable *fdt; - spin_lock(&files->file_lock); - fdt = files_fdtable(files); + + might_sleep(); + rcu_read_lock_sched(); + + while (unlikely(files->resize_in_progress)) { + rcu_read_unlock_sched(); + wait_event(files->resize_wait, !files->resize_in_progress); + rcu_read_lock_sched(); + } + /* coupled with smp_wmb() in expand_fdtable() */ + smp_rmb(); + fdt = rcu_dereference_sched(files->fdt); BUG_ON(fdt->fd[fd] != NULL); rcu_assign_pointer(fdt->fd[fd], file); - spin_unlock(&files->file_lock); + rcu_read_unlock_sched(); } void fd_install(unsigned int fd, struct file *file) diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index 230f87bdf5ad..fbb88740634a 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -47,6 +47,9 @@ struct files_struct { * read mostly part */ atomic_t count; + bool resize_in_progress; + wait_queue_head_t resize_wait; + struct fdtable __rcu *fdt; struct fdtable fdtab; /* -- cgit v1.2.3 From 00c570f4ba43ae73b41fa0a2269c3b0ac20386ef Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 1 Jul 2015 16:26:08 +0200 Subject: fuse: device fd clone Allow an open fuse device to be "cloned". Userspace can create a clone by: newfd = open("/dev/fuse", O_RDWR) ioctl(newfd, FUSE_DEV_IOC_CLONE, &oldfd); At this point newfd will refer to the same fuse connection as oldfd. Signed-off-by: Miklos Szeredi Reviewed-by: Ashish Samant --- Documentation/ioctl/ioctl-number.txt | 1 + fs/fuse/dev.c | 40 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/fuse.h | 3 +++ 3 files changed, 44 insertions(+) (limited to 'include') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 51f4221657bf..611c52267d24 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -321,6 +321,7 @@ Code Seq#(hex) Include File Comments 0xDB 00-0F drivers/char/mwave/mwavepub.h 0xDD 00-3F ZFCP device driver see drivers/s390/scsi/ +0xE5 00-3F linux/fuse.h 0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver 0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index dcfc87172a47..d405c1fa4618 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2197,6 +2197,44 @@ static int fuse_dev_fasync(int fd, struct file *file, int on) return fasync_helper(fd, file, on, &fc->iq.fasync); } +static int fuse_device_clone(struct fuse_conn *fc, struct file *new) +{ + if (new->private_data) + return -EINVAL; + + new->private_data = fuse_conn_get(fc); + + return 0; +} + +static long fuse_dev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int err = -ENOTTY; + + if (cmd == FUSE_DEV_IOC_CLONE) { + int oldfd; + + err = -EFAULT; + if (!get_user(oldfd, (__u32 __user *) arg)) { + struct file *old = fget(oldfd); + + err = -EINVAL; + if (old) { + struct fuse_conn *fc = fuse_get_conn(old); + + if (fc) { + mutex_lock(&fuse_mutex); + err = fuse_device_clone(fc, file); + mutex_unlock(&fuse_mutex); + } + fput(old); + } + } + } + return err; +} + const struct file_operations fuse_dev_operations = { .owner = THIS_MODULE, .open = fuse_dev_open, @@ -2208,6 +2246,8 @@ const struct file_operations fuse_dev_operations = { .poll = fuse_dev_poll, .release = fuse_dev_release, .fasync = fuse_dev_fasync, + .unlocked_ioctl = fuse_dev_ioctl, + .compat_ioctl = fuse_dev_ioctl, }; EXPORT_SYMBOL_GPL(fuse_dev_operations); diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 25084a052a1e..c9aca042e61d 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -755,4 +755,7 @@ struct fuse_notify_retrieve_in { uint64_t dummy4; }; +/* Device ioctls: */ +#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) + #endif /* _LINUX_FUSE_H */ -- cgit v1.2.3 From fbabfd0f4ee2e8847bf56edf481249ad1bb8c44d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 9 May 2015 15:54:49 -0500 Subject: fs: Add helper functions for permanently empty directories. To ensure it is safe to mount proc and sysfs I need to check if filesystems that are mounted on top of them are mounted on truly empty directories. Given that some directories can gain entries over time, knowing that a directory is empty right now is insufficient. Therefore add supporting infrastructure for permantently empty directories that proc and sysfs can use when they create mount points for filesystems and fs_fully_visible can use to test for permanently empty directories to ensure that nothing will be gained by mounting a fresh copy of proc or sysfs. Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" --- fs/libfs.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 2 ++ 2 files changed, 98 insertions(+) (limited to 'include') diff --git a/fs/libfs.c b/fs/libfs.c index cb1fb4b9b637..02813592e121 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1093,3 +1093,99 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp, return -EINVAL; } EXPORT_SYMBOL(simple_nosetlease); + + +/* + * Operations for a permanently empty directory. + */ +static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) +{ + return ERR_PTR(-ENOENT); +} + +static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = d_inode(dentry); + generic_fillattr(inode, stat); + return 0; +} + +static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr) +{ + return -EPERM; +} + +static int empty_dir_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + return -EOPNOTSUPP; +} + +static ssize_t empty_dir_getxattr(struct dentry *dentry, const char *name, + void *value, size_t size) +{ + return -EOPNOTSUPP; +} + +static int empty_dir_removexattr(struct dentry *dentry, const char *name) +{ + return -EOPNOTSUPP; +} + +static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size) +{ + return -EOPNOTSUPP; +} + +static const struct inode_operations empty_dir_inode_operations = { + .lookup = empty_dir_lookup, + .permission = generic_permission, + .setattr = empty_dir_setattr, + .getattr = empty_dir_getattr, + .setxattr = empty_dir_setxattr, + .getxattr = empty_dir_getxattr, + .removexattr = empty_dir_removexattr, + .listxattr = empty_dir_listxattr, +}; + +static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence) +{ + /* An empty directory has two entries . and .. at offsets 0 and 1 */ + return generic_file_llseek_size(file, offset, whence, 2, 2); +} + +static int empty_dir_readdir(struct file *file, struct dir_context *ctx) +{ + dir_emit_dots(file, ctx); + return 0; +} + +static const struct file_operations empty_dir_operations = { + .llseek = empty_dir_llseek, + .read = generic_read_dir, + .iterate = empty_dir_readdir, + .fsync = noop_fsync, +}; + + +void make_empty_dir_inode(struct inode *inode) +{ + set_nlink(inode, 2); + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_uid = GLOBAL_ROOT_UID; + inode->i_gid = GLOBAL_ROOT_GID; + inode->i_rdev = 0; + inode->i_size = 2; + inode->i_blkbits = PAGE_SHIFT; + inode->i_blocks = 0; + + inode->i_op = &empty_dir_inode_operations; + inode->i_fop = &empty_dir_operations; +} + +bool is_empty_dir_inode(struct inode *inode) +{ + return (inode->i_fop == &empty_dir_operations) && + (inode->i_op == &empty_dir_inode_operations); +} diff --git a/include/linux/fs.h b/include/linux/fs.h index 2d24eeb8e59c..571aab91bfc0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2780,6 +2780,8 @@ extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned in extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); extern const struct file_operations simple_dir_operations; extern const struct inode_operations simple_dir_inode_operations; +extern void make_empty_dir_inode(struct inode *inode); +extern bool is_empty_dir_inode(struct inode *inode); struct tree_descr { char *name; const struct file_operations *ops; int mode; }; struct dentry *d_alloc_name(struct dentry *, const char *); extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); -- cgit v1.2.3 From f9bd6733d3f11e24f3949becf277507d422ee1eb Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 9 May 2015 22:09:14 -0500 Subject: sysctl: Allow creating permanently empty directories that serve as mountpoints. Add a magic sysctl table sysctl_mount_point that when used to create a directory forces that directory to be permanently empty. Update the code to use make_empty_dir_inode when accessing permanently empty directories. Update the code to not allow adding to permanently empty directories. Update /proc/sys/fs/binfmt_misc to be a permanently empty directory. Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" --- fs/proc/proc_sysctl.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/sysctl.h | 3 +++ kernel/sysctl.c | 8 +------- 3 files changed, 41 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index fea2561d773b..fdda62e6115e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -19,6 +19,28 @@ static const struct inode_operations proc_sys_inode_operations; static const struct file_operations proc_sys_dir_file_operations; static const struct inode_operations proc_sys_dir_operations; +/* Support for permanently empty directories */ + +struct ctl_table sysctl_mount_point[] = { + { } +}; + +static bool is_empty_dir(struct ctl_table_header *head) +{ + return head->ctl_table[0].child == sysctl_mount_point; +} + +static void set_empty_dir(struct ctl_dir *dir) +{ + dir->header.ctl_table[0].child = sysctl_mount_point; +} + +static void clear_empty_dir(struct ctl_dir *dir) + +{ + dir->header.ctl_table[0].child = NULL; +} + void proc_sys_poll_notify(struct ctl_table_poll *poll) { if (!poll) @@ -187,6 +209,17 @@ static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) struct ctl_table *entry; int err; + /* Is this a permanently empty directory? */ + if (is_empty_dir(&dir->header)) + return -EROFS; + + /* Am I creating a permanently empty directory? */ + if (header->ctl_table == sysctl_mount_point) { + if (!RB_EMPTY_ROOT(&dir->root)) + return -EINVAL; + set_empty_dir(dir); + } + dir->header.nreg++; header->parent = dir; err = insert_links(header); @@ -202,6 +235,8 @@ fail: erase_header(header); put_links(header); fail_links: + if (header->ctl_table == sysctl_mount_point) + clear_empty_dir(dir); header->parent = NULL; drop_sysctl_table(&dir->header); return err; @@ -419,6 +454,8 @@ static struct inode *proc_sys_make_inode(struct super_block *sb, inode->i_mode |= S_IFDIR; inode->i_op = &proc_sys_dir_operations; inode->i_fop = &proc_sys_dir_file_operations; + if (is_empty_dir(head)) + make_empty_dir_inode(inode); } out: return inode; diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 795d5fea5697..fa7bc29925c9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -188,6 +188,9 @@ struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, void unregister_sysctl_table(struct ctl_table_header * table); extern int sysctl_init(void); + +extern struct ctl_table sysctl_mount_point[]; + #else /* CONFIG_SYSCTL */ static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 2082b1a88fb9..c3eee4c6d6c1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1531,12 +1531,6 @@ static struct ctl_table vm_table[] = { { } }; -#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) -static struct ctl_table binfmt_misc_table[] = { - { } -}; -#endif - static struct ctl_table fs_table[] = { { .procname = "inode-nr", @@ -1690,7 +1684,7 @@ static struct ctl_table fs_table[] = { { .procname = "binfmt_misc", .mode = 0555, - .child = binfmt_misc_table, + .child = sysctl_mount_point, }, #endif { -- cgit v1.2.3 From ea015218f2f7ace2dad9cedd21ed95bdba2886d7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2015 16:09:29 -0500 Subject: kernfs: Add support for always empty directories. Add a new function kernfs_create_empty_dir that can be used to create directory that can not be modified. Update the code to use make_empty_dir_inode when reporting a permanently empty directory to the vfs. Update the code to not allow adding to permanently empty directories. Cc: stable@vger.kernel.org Signed-off-by: "Eric W. Biederman" --- fs/kernfs/dir.c | 38 +++++++++++++++++++++++++++++++++++++- fs/kernfs/inode.c | 2 ++ include/linux/kernfs.h | 3 +++ 3 files changed, 42 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index f131fc23ffc4..47dc636d80ed 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -585,6 +585,9 @@ int kernfs_add_one(struct kernfs_node *kn) goto out_unlock; ret = -ENOENT; + if (parent->flags & KERNFS_EMPTY_DIR) + goto out_unlock; + if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) goto out_unlock; @@ -776,6 +779,38 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, return ERR_PTR(rc); } +/** + * kernfs_create_empty_dir - create an always empty directory + * @parent: parent in which to create a new directory + * @name: name of the new directory + * + * Returns the created node on success, ERR_PTR() value on failure. + */ +struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, + const char *name) +{ + struct kernfs_node *kn; + int rc; + + /* allocate */ + kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR); + if (!kn) + return ERR_PTR(-ENOMEM); + + kn->flags |= KERNFS_EMPTY_DIR; + kn->dir.root = parent->dir.root; + kn->ns = NULL; + kn->priv = NULL; + + /* link in */ + rc = kernfs_add_one(kn); + if (!rc) + return kn; + + kernfs_put(kn); + return ERR_PTR(rc); +} + static struct dentry *kernfs_iop_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) @@ -1247,7 +1282,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, mutex_lock(&kernfs_mutex); error = -ENOENT; - if (!kernfs_active(kn) || !kernfs_active(new_parent)) + if (!kernfs_active(kn) || !kernfs_active(new_parent) || + (new_parent->flags & KERNFS_EMPTY_DIR)) goto out; error = 0; diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 2da8493a380b..756dd56aaf60 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -296,6 +296,8 @@ static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode) case KERNFS_DIR: inode->i_op = &kernfs_dir_iops; inode->i_fop = &kernfs_dir_fops; + if (kn->flags & KERNFS_EMPTY_DIR) + make_empty_dir_inode(inode); break; case KERNFS_FILE: inode->i_size = kn->attr.size; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 71ecdab1671b..29d1896c3ba5 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -45,6 +45,7 @@ enum kernfs_node_flag { KERNFS_LOCKDEP = 0x0100, KERNFS_SUICIDAL = 0x0400, KERNFS_SUICIDED = 0x0800, + KERNFS_EMPTY_DIR = 0x1000, }; /* @flags for kernfs_create_root() */ @@ -285,6 +286,8 @@ void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, umode_t mode, void *priv, const void *ns); +struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, + const char *name); struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, -- cgit v1.2.3 From 87d2846fcf88113fae2341da1ca9a71f0d916f2c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 13 May 2015 16:31:40 -0500 Subject: sysfs: Add support for permanently empty directories to serve as mount points. Add two functions sysfs_create_mount_point and sysfs_remove_mount_point that hang a permanently empty directory off of a kobject or remove a permanently emptpy directory hanging from a kobject. Export these new functions so modular filesystems can use them. Cc: stable@vger.kernel.org Acked-by: Greg Kroah-Hartman Signed-off-by: "Eric W. Biederman" --- fs/sysfs/dir.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/sysfs.h | 15 +++++++++++++++ 2 files changed, 49 insertions(+) (limited to 'include') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 0b45ff42f374..94374e435025 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -121,3 +121,37 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); } + +/** + * sysfs_create_mount_point - create an always empty directory + * @parent_kobj: kobject that will contain this always empty directory + * @name: The name of the always empty directory to add + */ +int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name) +{ + struct kernfs_node *kn, *parent = parent_kobj->sd; + + kn = kernfs_create_empty_dir(parent, name); + if (IS_ERR(kn)) { + if (PTR_ERR(kn) == -EEXIST) + sysfs_warn_dup(parent, name); + return PTR_ERR(kn); + } + + return 0; +} +EXPORT_SYMBOL_GPL(sysfs_create_mount_point); + +/** + * sysfs_remove_mount_point - remove an always empty directory. + * @parent_kobj: kobject that will contain this always empty directory + * @name: The name of the always empty directory to remove + * + */ +void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name) +{ + struct kernfs_node *parent = parent_kobj->sd; + + kernfs_remove_by_name_ns(parent, name, NULL); +} +EXPORT_SYMBOL_GPL(sysfs_remove_mount_point); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 99382c0df17e..9f65758311a4 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -210,6 +210,10 @@ int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, int __must_check sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, const void *new_ns); +int __must_check sysfs_create_mount_point(struct kobject *parent_kobj, + const char *name); +void sysfs_remove_mount_point(struct kobject *parent_kobj, + const char *name); int __must_check sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, @@ -298,6 +302,17 @@ static inline int sysfs_move_dir_ns(struct kobject *kobj, return 0; } +static inline int sysfs_create_mount_point(struct kobject *parent_kobj, + const char *name) +{ + return 0; +} + +static inline void sysfs_remove_mount_point(struct kobject *parent_kobj, + const char *name) +{ +} + static inline int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns) -- cgit v1.2.3 From aca2a5d3a8fce1879627bc4ec9d180b74ae512e2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:04 +0800 Subject: ACPICA: Hardware: Enable 64-bit firmware waking vector for selected FACS ACPICA commit 7aa598d711644ab0de5f70ad88f1e2de253115e4 The following commit is reported to have broken s2ram on some platforms: Commit: 0249ed2444d65d65fc3f3f64f398f1ad0b7e54cd ACPICA: Add option to favor 32-bit FADT addresses. The platform reports 2 FACS tables (which is not allowed by ACPI specification) and the new 32-bit address favor rule forces OSPMs to use the FACS table reported via FADT's X_FIRMWARE_CTRL field. The root cause of the reported bug might be one of the followings: 1. BIOS may favor the 64-bit firmware waking vector address when the version of the FACS is greater than 0 and Linux currently only supports resuming from the real mode, so the 64-bit firmware waking vector has never been set and might be invalid to BIOS while the commit enables higher version FACS. 2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the FADT while the commit doesn't set the firmware waking vector address of the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking vector address of the FACS reported by "X_FIRMWARE_CTRL". This patch excludes the cases that can trigger the bugs caused by the root cause 1. ACPI specification says: A. 32-bit FACS address (FIRMWARE_CTRL field in FADT): Physical memory address of the FACS, where OSPM and firmware exchange control information. If the X_FIRMWARE_CTRL field contains a non zero value then this field must be zero. A zero value indicates that no FACS is specified by this field. B. 64-bit FACS address (X_FIRMWARE_CTRL field in FADT): 64bit physical memory address of the FACS. This field is used when the physical address of the FACS is above 4GB. If the FIRMWARE_CTRL field contains a non zero value then this field must be zero. A zero value indicates that no FACS is specified by this field. Thus the 32bit and 64bit firmware waking vector should indicate completely different resuming environment - real mode (1MB addressable) and non real mode (4GB+ addressable) and currently Linux only supports resuming from real mode. This patch enables 64-bit firmware waking vector for selected FACS via new acpi_set_firmware_waking_vectors() API so that it's up to OSPMs to determine which resuming mode should be used by BIOS and ACPICA changes won't trigger the bugs caused by the root cause 1. Lv Zheng. Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021 Link: https://github.com/acpica/acpica/commit/7aa598d7 Reported-and-tested-by: Oswald Buddenhagen Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/hwxfsleep.c | 71 ++++++++++++++++++++++++++++++----------- include/acpi/acpixf.h | 8 +++-- 2 files changed, 59 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 82e310b94ae4..25cd9783b640 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -72,6 +72,7 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { /* * These functions are removed for the ACPI_REDUCED_HARDWARE case: + * acpi_set_firmware_waking_vectors * acpi_set_firmware_waking_vector * acpi_set_firmware_waking_vector64 * acpi_enter_sleep_state_s4bios @@ -80,20 +81,24 @@ static struct acpi_sleep_functions acpi_sleep_dispatch[] = { #if (!ACPI_REDUCED_HARDWARE) /******************************************************************************* * - * FUNCTION: acpi_set_firmware_waking_vector + * FUNCTION: acpi_set_firmware_waking_vectors * * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode * entry point. + * physical_address64 - 64-bit physical address of ACPI protected + * mode entry point. * * RETURN: Status * - * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS + * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS * ******************************************************************************/ -acpi_status acpi_set_firmware_waking_vector(u32 physical_address) +acpi_status +acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, + acpi_physical_address physical_address64) { - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); /* @@ -106,17 +111,51 @@ acpi_status acpi_set_firmware_waking_vector(u32 physical_address) /* Set the 32-bit vector */ - acpi_gbl_FACS->firmware_waking_vector = physical_address; + acpi_gbl_FACS->firmware_waking_vector = (u32)physical_address; - /* Clear the 64-bit vector if it exists */ + if (acpi_gbl_FACS->length > 32) { + if (acpi_gbl_FACS->version >= 1) { - if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) { - acpi_gbl_FACS->xfirmware_waking_vector = 0; + /* Set the 64-bit vector */ + + acpi_gbl_FACS->xfirmware_waking_vector = + physical_address64; + } else { + /* Clear the 64-bit vector if it exists */ + + acpi_gbl_FACS->xfirmware_waking_vector = 0; + } } return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors) + +/******************************************************************************* + * + * FUNCTION: acpi_set_firmware_waking_vector + * + * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode + * entry point. + * + * RETURN: Status + * + * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS + * + ******************************************************************************/ +acpi_status acpi_set_firmware_waking_vector(u32 physical_address) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); + + status = acpi_set_firmware_waking_vectors((acpi_physical_address) + physical_address, 0); + + return_ACPI_STATUS(status); +} + ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) #if ACPI_MACHINE_WIDTH == 64 @@ -136,19 +175,15 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) ******************************************************************************/ acpi_status acpi_set_firmware_waking_vector64(u64 physical_address) { - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - - /* Determine if the 64-bit vector actually exists */ + acpi_status status; - if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { - return_ACPI_STATUS(AE_NOT_EXIST); - } + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - /* Clear 32-bit vector, set the 64-bit X_ vector */ + status = acpi_set_firmware_waking_vectors(0, + (acpi_physical_address) + physical_address); - acpi_gbl_FACS->firmware_waking_vector = 0; - acpi_gbl_FACS->xfirmware_waking_vector = physical_address; - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index d68f1cd39c49..821095ce5af7 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -814,8 +814,12 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state)) ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_firmware_waking_vector(u32 - physical_address)) + acpi_set_firmware_waking_vectors + (acpi_physical_address physical_address, + acpi_physical_address physical_address64)) +ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status + acpi_set_firmware_waking_vector(u32 + physical_address)) #if ACPI_MACHINE_WIDTH == 64 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_set_firmware_waking_vector64(u64 -- cgit v1.2.3 From c04e1fb4396d27f18296db0f914760fa7fe8223a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:11 +0800 Subject: ACPICA: Tables: Enable both 32-bit and 64-bit FACS ACPICA commit f7b86f35416e3d1f71c3d816ff5075ddd33ed486 The following commit is reported to have broken s2ram on some platforms: Commit: 0249ed2444d65d65fc3f3f64f398f1ad0b7e54cd ACPICA: Add option to favor 32-bit FADT addresses. The platform reports 2 FACS tables (which is not allowed by ACPI specification) and the new 32-bit address favor rule forces OSPMs to use the FACS table reported via FADT's X_FIRMWARE_CTRL field. The root cause of the reported bug might be one of the followings: 1. BIOS may favor the 64-bit firmware waking vector address when the version of the FACS is greater than 0 and Linux currently only supports resuming from the real mode, so the 64-bit firmware waking vector has never been set and might be invalid to BIOS while the commit enables higher version FACS. 2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the FADT while the commit doesn't set the firmware waking vector address of the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking vector address of the FACS reported by "X_FIRMWARE_CTRL". This patch excludes the cases that can trigger the bugs caused by the root cause 2. There is no handshaking mechanism can be used by OSPM to tell BIOS which FACS is currently used. Thus the FACS reported by "FIRMWARE_CTRL" may still be used by BIOS and the 0 value of the 32-bit firmware waking vector might trigger such failure. This patch tries to favor 32bit FACS address in another way where both the FACS reported by "FIRMWARE_CTRL" and the FACS reported by "X_FIRMWARE_CTRL" are loaded so that further commit can set firmware waking vector in the both tables to ensure we can exclude the cases that trigger the bugs caused by the root cause 2. The exclusion is split into 2 commits as this commit is also useful for dumping more ACPI tables, it won't get reverted when such exclusion is no longer necessary. Lv Zheng. Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021 Link: https://github.com/acpica/acpica/commit/f7b86f35 Cc: 3.14.1+ # 3.14.1+ Reported-and-tested-by: Oswald Buddenhagen Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 1 + drivers/acpi/acpica/tbfadt.c | 21 +++++++++++++-------- drivers/acpi/acpica/tbutils.c | 34 +++++++++++++++++++++++----------- drivers/acpi/acpica/tbxfload.c | 3 ++- include/acpi/acpixf.h | 9 +++++++++ 5 files changed, 48 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index ffdb956391f6..bc600969c6a1 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -213,6 +213,7 @@ struct acpi_table_list { #define ACPI_TABLE_INDEX_DSDT (0) #define ACPI_TABLE_INDEX_FACS (1) +#define ACPI_TABLE_INDEX_X_FACS (2) struct acpi_find_context { char *search_for; diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 7d2486005e3f..05be59c772c7 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -350,9 +350,18 @@ void acpi_tb_parse_fadt(u32 table_index) /* If Hardware Reduced flag is set, there is no FACS */ if (!acpi_gbl_reduced_hardware) { - acpi_tb_install_fixed_table((acpi_physical_address) - acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, - ACPI_TABLE_INDEX_FACS); + if (acpi_gbl_FADT.facs) { + acpi_tb_install_fixed_table((acpi_physical_address) + acpi_gbl_FADT.facs, + ACPI_SIG_FACS, + ACPI_TABLE_INDEX_FACS); + } + if (acpi_gbl_FADT.Xfacs) { + acpi_tb_install_fixed_table((acpi_physical_address) + acpi_gbl_FADT.Xfacs, + ACPI_SIG_FACS, + ACPI_TABLE_INDEX_X_FACS); + } } } @@ -491,13 +500,9 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); /* - * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Expand the 32-bit DSDT addresses to 64-bit as necessary. * Later ACPICA code will always use the X 64-bit field. */ - acpi_gbl_FADT.Xfacs = acpi_tb_select_address("FACS", - acpi_gbl_FADT.facs, - acpi_gbl_FADT.Xfacs); - acpi_gbl_FADT.Xdsdt = acpi_tb_select_address("DSDT", acpi_gbl_FADT.dsdt, acpi_gbl_FADT.Xdsdt); diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 6559a58439c5..2fb1afaacc6d 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -68,7 +68,8 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); acpi_status acpi_tb_initialize_facs(void) { - acpi_status status; + struct acpi_table_facs *facs32; + struct acpi_table_facs *facs64; /* If Hardware Reduced flag is set, there is no FACS */ @@ -77,11 +78,22 @@ acpi_status acpi_tb_initialize_facs(void) return (AE_OK); } - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &acpi_gbl_FACS)); - return (status); + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs32)); + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_X_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &facs64)); + + if (acpi_gbl_use32_bit_facs_addresses) { + acpi_gbl_FACS = facs32 ? facs32 : facs64; + } else { + acpi_gbl_FACS = facs64 ? facs64 : facs32; + } + + return (AE_OK); } #endif /* !ACPI_REDUCED_HARDWARE */ @@ -101,7 +113,7 @@ acpi_status acpi_tb_initialize_facs(void) u8 acpi_tb_tables_loaded(void) { - if (acpi_gbl_root_table_list.current_table_count >= 3) { + if (acpi_gbl_root_table_list.current_table_count >= 4) { return (TRUE); } @@ -357,11 +369,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); /* - * First two entries in the table array are reserved for the DSDT - * and FACS, which are not actually present in the RSDT/XSDT - they - * come from the FADT + * First three entries in the table array are reserved for the DSDT + * and 32bit/64bit FACS, which are not actually present in the + * RSDT/XSDT - they come from the FADT */ - acpi_gbl_root_table_list.current_table_count = 2; + acpi_gbl_root_table_list.current_table_count = 3; /* Initialize the root table array from the RSDT/XSDT */ diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index aadb3002a2dd..b63e35d6d1bf 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -166,7 +166,8 @@ static acpi_status acpi_tb_load_namespace(void) (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if ((!ACPI_COMPARE_NAME + if (!acpi_gbl_root_table_list.tables[i].address || + (!ACPI_COMPARE_NAME (&(acpi_gbl_root_table_list.tables[i].signature), ACPI_SIG_SSDT) && diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 821095ce5af7..445fd1e1688c 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -199,6 +199,15 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); */ ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE); +/* + * Optionally use 32-bit FACS table addresses. + * It is reported that some platforms fail to resume from system suspending + * if 64-bit FACS table address is selected: + * https://bugzilla.kernel.org/show_bug.cgi?id=74021 + * Default is TRUE, favor the 32-bit addresses. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_facs_addresses, TRUE); + /* * Optionally truncate I/O addresses to 16 bits. Provides compatibility * with other ACPI implementations. NOTE: During ACPICA initialization, -- cgit v1.2.3 From c04be18448355441a0c424362df65b6422e27bda Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:26 +0800 Subject: ACPICA: Tables: Fix an issue that FACS initialization is performed twice ACPICA commit 90f5332a15e9d9ba83831ca700b2b9f708274658 This patch adds a new FACS initialization flag for acpi_tb_initialize(). acpi_enable_subsystem() might be invoked several times in OS bootup process, and we don't want FACS initialization to be invoked twice. Lv Zheng. Link: https://github.com/acpica/acpica/commit/90f5332a Cc: All applicable # All applicable Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utxfinit.c | 10 ++++++---- include/acpi/actypes.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 083a76891889..42a32a66ef22 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -179,10 +179,12 @@ acpi_status __init acpi_enable_subsystem(u32 flags) * Obtain a permanent mapping for the FACS. This is required for the * Global Lock and the Firmware Waking Vector */ - status = acpi_tb_initialize_facs(); - if (ACPI_FAILURE(status)) { - ACPI_WARNING((AE_INFO, "Could not map the FACS table")); - return_ACPI_STATUS(status); + if (!(flags & ACPI_NO_FACS_INIT)) { + status = acpi_tb_initialize_facs(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, "Could not map the FACS table")); + return_ACPI_STATUS(status); + } } #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 63fd7f5e9fb3..ff0b53e128ee 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -568,6 +568,7 @@ typedef u64 acpi_integer; #define ACPI_NO_ACPI_ENABLE 0x10 #define ACPI_NO_DEVICE_INIT 0x20 #define ACPI_NO_OBJECT_INIT 0x40 +#define ACPI_NO_FACS_INIT 0x80 /* * Initialization state -- cgit v1.2.3 From 0ea61381788a37d864f9841b0fe97d40f7058f3b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:34 +0800 Subject: ACPICA: Tables: Enable default 64-bit FADT addresses favor ACPICA commit 4da56eeae0749dfe8491285c1e1fad48f6efafd8 The following commit temporarily disables correct 64-bit FADT addresses favor during the period the root cause of the bug is not fixed: Commit: 85dbd5801f62b66e2aa7826aaefcaebead44c8a6 ACPICA: Tables: Restore old behavor to favor 32-bit FADT addresses. With enough protections, this patch re-enables 64-bit FADT addresses by default. If regressions are reported against such change, this patch should be bisected and reverted. Note that 64-bit FACS favor and 64-bit firmware waking vector favor are excluded by this commit in order not to break OSPMs. Lv Zheng. Link: https://bugzilla.kernel.org/show_bug.cgi?id=74021 Link: https://github.com/acpica/acpica/commit/4da56eea Cc: 3.15.1+ # 3.15.1+ Reported-and-tested-by: Oswald Buddenhagen Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 445fd1e1688c..213ed7ecfd8d 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -195,9 +195,9 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); * address. Although ACPICA adheres to the ACPI specification which * requires the use of the corresponding 64-bit address if it is non-zero, * some machines have been found to have a corrupted non-zero 64-bit - * address. Default is TRUE, favor the 32-bit addresses. + * address. Default is FALSE, do not favor the 32-bit addresses. */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE); /* * Optionally use 32-bit FACS table addresses. -- cgit v1.2.3 From 7b09d8fdede65ea0ff4dc79654d10856f0aff0b8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:43 +0800 Subject: ACPICA: MSVC6: Fix build issue for variable argument macros ACPICA commit 72f5a358f28c5d154ed613c142c7dca03192c5ee This patch intoduces generic variable macro detection support and fixes build breakage issue with macros using __VA_ARGS__ feature defined in C99. This patch fixes this build issue. Lv Zheng. This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/72f5a358 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/acoutput.h | 13 +++++++++++-- include/acpi/platform/acgcc.h | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index a8f344363e77..f56de8c5d844 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -294,8 +294,12 @@ /* DEBUG_PRINT functions */ -#define ACPI_DEBUG_PRINT(plist) ACPI_ACTUAL_DEBUG plist -#define ACPI_DEBUG_PRINT_RAW(plist) ACPI_ACTUAL_DEBUG_RAW plist +#ifndef COMPILER_VA_MACRO + +#define ACPI_DEBUG_PRINT(plist) acpi_debug_print plist +#define ACPI_DEBUG_PRINT_RAW(plist) acpi_debug_print_raw plist + +#else /* Helper macros for DEBUG_PRINT */ @@ -315,6 +319,11 @@ ACPI_DO_DEBUG_PRINT (acpi_debug_print_raw, level, line, \ filename, modulename, component, __VA_ARGS__) +#define ACPI_DEBUG_PRINT(plist) ACPI_ACTUAL_DEBUG plist +#define ACPI_DEBUG_PRINT_RAW(plist) ACPI_ACTUAL_DEBUG_RAW plist + +#endif + /* * Function entry tracing * diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index f54de0a63558..5457a06cb528 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -75,4 +75,8 @@ #undef strchr #endif +/* GCC supports __VA_ARGS__ in macros */ + +#define COMPILER_VA_MACRO 1 + #endif /* __ACGCC_H__ */ -- cgit v1.2.3 From 07cf6ce595882c71cc5bd6c551820398b9e7f613 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 1 Jul 2015 14:43:50 +0800 Subject: ACPICA: EFI: Add EFI interface definitions to eliminate dependency of GNU EFI ACPICA commit 5d00e67a74542d030f0a55e7a947a020ef0d9693 This patch copies EFI interface definitions to the ACPICA code base so that the EFI utility support can be ported to other EFI implementation. Known issues: 1. MS Builds of uefi_call_wrapper() The uefi_call_wrapper() in GNU EFI is implemented in a the way to work around the ABI difference between Unix and MS. While I don't have environment to test the MS builds. In order to port the ACPICA utilities to other EFI implementation, all that need to be done is to impelement the 64-bit division support and the program entry point where the efi_main() is invoked. Code to impelement these is platform specific, and ACPICA currently choose to hide such platform specific code within the specific EFI impelementation. Lv Zheng. This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/5d00e67a Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acenvex.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/acpi/platform/acenvex.h b/include/acpi/platform/acenvex.h index 14dc6f68ca18..0a7dc8e583b1 100644 --- a/include/acpi/platform/acenvex.h +++ b/include/acpi/platform/acenvex.h @@ -56,6 +56,12 @@ #if defined(_LINUX) || defined(__linux__) #include +#elif defined(_AED_EFI) +#include "acefiex.h" + +#elif defined(_GNU_EFI) +#include "acefiex.h" + #elif defined(__DragonFly__) #include "acdragonflyex.h" -- cgit v1.2.3 From f65358e5724890ef473d28762f6de0f3284b146e Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Wed, 1 Jul 2015 14:44:04 +0800 Subject: ACPICA: Utilities: Add _CLS processing ACPICA commit 9a2b638acb3a7215209432e070c6bd0312374229 ACPI Device object often contains a _CLS object to supply PCI-defined class code for the device. This patch introduces logic to process the _CLS object. Suravee Suthikulpanit, Lv Zheng. Link: https://github.com/acpica/acpica/commit/9a2b638a Acked-by: Mika Westerberg Reviewed-by: Hanjun Guo Signed-off-by: Suravee Suthikulpanit Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acinterp.h | 2 + drivers/acpi/acpica/acutils.h | 4 ++ drivers/acpi/acpica/exutils.c | 32 +++++++++++++++ drivers/acpi/acpica/nsxfname.c | 23 +++++++++-- drivers/acpi/acpica/utids.c | 91 +++++++++++++++++++++++++++++++++++++++++- include/acpi/acnames.h | 1 + include/acpi/actypes.h | 24 ++++++----- 7 files changed, 164 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 1886bde54b5d..7ac98000b46b 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -468,6 +468,8 @@ void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id); void acpi_ex_integer_to_string(char *dest, u64 value); +void acpi_ex_pci_cls_to_string(char *dest, u8 class_code[3]); + u8 acpi_is_valid_space_id(u8 space_id); /* diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index d49f5c7a20d9..6391c9706e84 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -430,6 +430,10 @@ acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, struct acpi_pnp_device_id_list ** return_cid_list); +acpi_status +acpi_ut_execute_CLS(struct acpi_namespace_node *device_node, + struct acpi_pnp_device_id **return_id); + /* * utlock - reader/writer locks */ diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 3f4225e95d93..30c3f464fda5 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -378,6 +378,38 @@ void acpi_ex_integer_to_string(char *out_string, u64 value) } } +/******************************************************************************* + * + * FUNCTION: acpi_ex_pci_cls_to_string + * + * PARAMETERS: out_string - Where to put the converted string (7 bytes) + * PARAMETERS: class_code - PCI class code to be converted (3 bytes) + * + * RETURN: None + * + * DESCRIPTION: Convert 3-bytes PCI class code to string representation. + * Return buffer must be large enough to hold the string. The + * string returned is always exactly of length + * ACPI_PCICLS_STRING_SIZE (includes null terminator). + * + ******************************************************************************/ + +void acpi_ex_pci_cls_to_string(char *out_string, u8 class_code[3]) +{ + + ACPI_FUNCTION_ENTRY(); + + /* All 3 bytes are hexadecimal */ + + out_string[0] = acpi_ut_hex_to_ascii_char((u64)class_code[0], 4); + out_string[1] = acpi_ut_hex_to_ascii_char((u64)class_code[0], 0); + out_string[2] = acpi_ut_hex_to_ascii_char((u64)class_code[1], 4); + out_string[3] = acpi_ut_hex_to_ascii_char((u64)class_code[1], 0); + out_string[4] = acpi_ut_hex_to_ascii_char((u64)class_code[2], 4); + out_string[5] = acpi_ut_hex_to_ascii_char((u64)class_code[2], 0); + out_string[6] = 0; +} + /******************************************************************************* * * FUNCTION: acpi_is_valid_space_id diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index d66c326485d8..dc0836a9cf17 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -260,7 +260,7 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, * control methods (Such as in the case of a device.) * * For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, - * _STA, _ADR, _sx_w, and _sx_d methods. + * _CLS, _STA, _ADR, _sx_w, and _sx_d methods. * * Note: Allocates the return buffer, must be freed by the caller. * @@ -276,11 +276,12 @@ acpi_get_object_info(acpi_handle handle, struct acpi_pnp_device_id *hid = NULL; struct acpi_pnp_device_id *uid = NULL; struct acpi_pnp_device_id *sub = NULL; + struct acpi_pnp_device_id *cls = NULL; char *next_id_string; acpi_object_type type; acpi_name name; u8 param_count = 0; - u8 valid = 0; + u16 valid = 0; u32 info_size; u32 i; acpi_status status; @@ -320,7 +321,7 @@ acpi_get_object_info(acpi_handle handle, if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* * Get extra info for ACPI Device/Processor objects only: - * Run the Device _HID, _UID, _SUB, and _CID methods. + * Run the Device _HID, _UID, _SUB, _CID, and _CLS methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used @@ -363,6 +364,14 @@ acpi_get_object_info(acpi_handle handle, sizeof(struct acpi_pnp_device_id_list)); valid |= ACPI_VALID_CID; } + + /* Execute the Device._CLS method */ + + status = acpi_ut_execute_CLS(node, &cls); + if (ACPI_SUCCESS(status)) { + info_size += cls->length; + valid |= ACPI_VALID_CLS; + } } /* @@ -486,6 +495,11 @@ acpi_get_object_info(acpi_handle handle, } } + if (cls) { + next_id_string = acpi_ns_copy_device_id(&info->class_code, + cls, next_id_string); + } + /* Copy the fixed-length data */ info->info_size = info_size; @@ -510,6 +524,9 @@ cleanup: if (cid_list) { ACPI_FREE(cid_list); } + if (cls) { + ACPI_FREE(cls); + } return (status); } diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 27431cfc1c44..3afe07f19b9f 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Module Name: utids - support for device Ids - HID, UID, CID + * Module Name: utids - support for device Ids - HID, UID, CID, SUB, CLS * *****************************************************************************/ @@ -416,3 +416,92 @@ cleanup: acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); } + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_CLS + * + * PARAMETERS: device_node - Node for the device + * return_id - Where the _CLS is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _CLS control method that returns PCI-defined + * class code of the device. The _CLS value is always a package + * containing PCI class information as a list of integers. + * The returned string has format "BBSSPP", where: + * BB = Base-class code + * SS = Sub-class code + * PP = Programming Interface code + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_CLS(struct acpi_namespace_node *device_node, + struct acpi_pnp_device_id **return_id) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object **cls_objects; + u32 count; + struct acpi_pnp_device_id *cls; + u32 length; + acpi_status status; + u8 class_code[3] = { 0, 0, 0 }; + + ACPI_FUNCTION_TRACE(ut_execute_CLS); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS, + ACPI_BTYPE_PACKAGE, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + length = ACPI_PCICLS_STRING_SIZE; + cls_objects = obj_desc->package.elements; + count = obj_desc->package.count; + + if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { + if (count > 0 + && cls_objects[0]->common.type == ACPI_TYPE_INTEGER) { + class_code[0] = (u8)cls_objects[0]->integer.value; + } + if (count > 1 + && cls_objects[1]->common.type == ACPI_TYPE_INTEGER) { + class_code[1] = (u8)cls_objects[1]->integer.value; + } + if (count > 2 + && cls_objects[2]->common.type == ACPI_TYPE_INTEGER) { + class_code[2] = (u8)cls_objects[2]->integer.value; + } + } + + /* Allocate a buffer for the CLS */ + + cls = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + + (acpi_size) length); + if (!cls) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Area for the string starts after PNP_DEVICE_ID struct */ + + cls->string = + ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id)); + + /* Simply copy existing string */ + + acpi_ex_pci_cls_to_string(cls->string, class_code); + cls->length = length; + *return_id = cls; + +cleanup: + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index 273de709495c..b52c0dc4b492 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -51,6 +51,7 @@ #define METHOD_NAME__BBN "_BBN" #define METHOD_NAME__CBA "_CBA" #define METHOD_NAME__CID "_CID" +#define METHOD_NAME__CLS "_CLS" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__DDN "_DDN" #define METHOD_NAME__HID "_HID" diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index ff0b53e128ee..d791b986002a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1141,6 +1141,10 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); #define ACPI_UUID_LENGTH 16 +/* Length of 3-byte PCI class code values when converted back to a string */ + +#define ACPI_PCICLS_STRING_SIZE 7 /* Includes null terminator */ + /* Structures used for device/processor HID, UID, CID, and SUB */ struct acpi_pnp_device_id { @@ -1163,7 +1167,7 @@ struct acpi_device_info { u32 name; /* ACPI object Name */ acpi_object_type type; /* ACPI object Type */ u8 param_count; /* If a method, required parameter count */ - u8 valid; /* Indicates which optional fields are valid */ + u16 valid; /* Indicates which optional fields are valid */ u8 flags; /* Miscellaneous info */ u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */ @@ -1172,6 +1176,7 @@ struct acpi_device_info { struct acpi_pnp_device_id hardware_id; /* _HID value */ struct acpi_pnp_device_id unique_id; /* _UID value */ struct acpi_pnp_device_id subsystem_id; /* _SUB value */ + struct acpi_pnp_device_id class_code; /* _CLS value */ struct acpi_pnp_device_id_list compatible_id_list; /* _CID list */ }; @@ -1181,14 +1186,15 @@ struct acpi_device_info { /* Flags for Valid field above (acpi_get_object_info) */ -#define ACPI_VALID_STA 0x01 -#define ACPI_VALID_ADR 0x02 -#define ACPI_VALID_HID 0x04 -#define ACPI_VALID_UID 0x08 -#define ACPI_VALID_SUB 0x10 -#define ACPI_VALID_CID 0x20 -#define ACPI_VALID_SXDS 0x40 -#define ACPI_VALID_SXWS 0x80 +#define ACPI_VALID_STA 0x0001 +#define ACPI_VALID_ADR 0x0002 +#define ACPI_VALID_HID 0x0004 +#define ACPI_VALID_UID 0x0008 +#define ACPI_VALID_SUB 0x0010 +#define ACPI_VALID_CID 0x0020 +#define ACPI_VALID_CLS 0x0040 +#define ACPI_VALID_SXDS 0x0100 +#define ACPI_VALID_SXWS 0x0200 /* Flags for _STA return value (current_status above) */ -- cgit v1.2.3 From a8bd0f07eb594df51845d33f272fb1952fec1a6f Mon Sep 17 00:00:00 2001 From: Hanjun Guo Date: Wed, 1 Jul 2015 14:44:10 +0800 Subject: ACPICA: ACPI 6.0: Add values for MADT GIC version field ACPICA commit 4b100dc43e8baee8c8b4891b23bc7ad03eba6a28 Support for the new version field in the generic distributor subtable. Hanjun Guo Link: https://github.com/acpica/acpica/commit/4b100dc4 Signed-off-by: Hanjun Guo Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl1.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include') diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 06b61f01ea59..fcd570999f35 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -835,6 +835,17 @@ struct acpi_madt_generic_distributor { u8 reserved2[3]; /* reserved - must be zero */ }; +/* Values for Version field above */ + +enum acpi_madt_gic_version { + ACPI_MADT_GIC_VERSION_NONE = 0, + ACPI_MADT_GIC_VERSION_V1 = 1, + ACPI_MADT_GIC_VERSION_V2 = 2, + ACPI_MADT_GIC_VERSION_V3 = 3, + ACPI_MADT_GIC_VERSION_V4 = 4, + ACPI_MADT_GIC_VERSION_RESERVED = 5 /* 5 and greater are reserved */ +}; + /* 13: Generic MSI Frame (ACPI 5.1) */ struct acpi_madt_generic_msi_frame { -- cgit v1.2.3 From fe536995f2fe26fff111a9a06bf3f71e179c92cf Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:44:23 +0800 Subject: ACPICA: Namespace: Add support of OSDT table ACPICA commit 27415c82fcecf467446f66d1007a0691cc5f3709 This patch adds OSDT (Override System Definition Table) support. When OSDT is loaded, conflict namespace objects will be overridden by the AML interpreter. Bob Moore, Lv Zheng. Link: https://github.com/acpica/acpica/commit/27415c82 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsparse.c | 7 +++++++ drivers/acpi/acpica/tbxfload.c | 6 +++++- drivers/acpi/acpica/utmisc.c | 3 ++- include/acpi/actbl.h | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index c95a119767b5..57a4cfe547e4 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -117,6 +117,13 @@ acpi_ns_one_complete_parse(u32 pass_number, (u8) pass_number); } + /* Found OSDT table, enable the namespace override feature */ + + if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT) && + pass_number == ACPI_IMODE_LOAD_PASS1) { + walk_state->namespace_override = TRUE; + } + if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index b63e35d6d1bf..960bd999a6b3 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -173,7 +173,11 @@ static acpi_status acpi_tb_load_namespace(void) && !ACPI_COMPARE_NAME(& (acpi_gbl_root_table_list.tables[i]. - signature), ACPI_SIG_PSDT)) + signature), ACPI_SIG_PSDT) + && + !ACPI_COMPARE_NAME(& + (acpi_gbl_root_table_list.tables[i]. + signature), ACPI_SIG_OSDT)) || ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list.tables[i]))) { diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index cbb7034d28d8..28099e230008 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -97,7 +97,8 @@ u8 acpi_ut_is_aml_table(struct acpi_table_header *table) if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) || ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) || - ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT)) { return (TRUE); } diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index cb8a6b97ceda..2d5faf508cad 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -65,6 +65,7 @@ #define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */ #define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */ #define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */ +#define ACPI_SIG_OSDT "OSDT" /* Override System Description Table */ #define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */ #define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */ #define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */ -- cgit v1.2.3 From 8ea98655775e904ea406d74a887d0b2254651b5a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:44:31 +0800 Subject: ACPICA: Namespace: Change namespace override to avoid node deletion ACPICA commit c0ce529e1fbb8ec47d2522a3aa10f3ab77e16e41 There is no reference counting implemented for struct acpi_namespace_node, so it is currently not removable during runtime. This patch changes the namespace override code to keep the old struct acpi_namespace_node undeleted so that the override mechanism can happen during runtime. Bob Moore. Link: https://github.com/acpica/acpica/commit/c0ce529e Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nssearch.c | 23 +++++++++++++++++++---- include/acpi/acpixf.h | 5 +++++ 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 47fbe5b33524..d73904013830 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -331,13 +331,28 @@ acpi_ns_search_and_enter(u32 target_name, /* * If the namespace override feature is enabled for this node, - * delete any existing node. This can only happen during the - * boot stage, thus it is safe to remove the node here. + * delete any existing attached sub-object and make the node + * look like a new node that is owned by the override table. */ if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "Namespace override: %4.4s pass %u type %X Owner %X\n", + ACPI_CAST_PTR(char, + &target_name), + interpreter_mode, + (*return_node)->type, + walk_state->owner_id)); + acpi_ns_delete_children(*return_node); - acpi_ns_remove_node(*return_node); - *return_node = ACPI_ENTRY_NOT_FOUND; + if (acpi_gbl_runtime_namespace_override) { + acpi_ut_remove_reference((*return_node)->object); + (*return_node)->object = NULL; + (*return_node)->owner_id = + walk_state->owner_id; + } else { + acpi_ns_remove_node(*return_node); + *return_node = ACPI_ENTRY_NOT_FOUND; + } } /* Return an error if we don't expect to find the object */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 213ed7ecfd8d..f6d807170346 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -228,6 +228,11 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); */ ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); +/* + * Optionally enable runtime namespace override. + */ +ACPI_INIT_GLOBAL(u8, acpi_gbl_runtime_namespace_override, TRUE); + /* * We keep track of the latest version of Windows that has been requested by * the BIOS. ACPI 5.0. -- cgit v1.2.3 From 4fa4616e279df89baeb36287bbee83ab272edaed Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:45:11 +0800 Subject: ACPICA: De-macroize calls to standard C library functions ACPICA commit 3b1026e0bdd3c32eb6d5d313f3ba0b1fee7597b4 ACPICA commit 00f0dc83f5cfca53b27a3213ae0d7719b88c2d6b ACPICA commit 47d22a738d0e19fd241ffe4e3e9d4e198e4afc69 Across all of ACPICA. Replace C library macros such as ACPI_STRLEN with the standard names such as strlen. The original purpose for these macros is long since obsolete. Also cast various invocations as necessary. Bob Moore, Jung-uk Kim, Lv Zheng. Link: https://github.com/acpica/acpica/commit/3b1026e0 Link: https://github.com/acpica/acpica/commit/00f0dc83 Link: https://github.com/acpica/acpica/commit/47d22a73 Signed-off-by: Bob Moore Signed-off-by: Jung-uk Kim Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 46 +++++++++---------- drivers/acpi/acpica/dsfield.c | 2 +- drivers/acpi/acpica/dsinit.c | 2 +- drivers/acpi/acpica/dsobject.c | 7 ++- drivers/acpi/acpica/dsutils.c | 4 +- drivers/acpi/acpica/evgpeinit.c | 2 +- drivers/acpi/acpica/exconfig.c | 2 +- drivers/acpi/acpica/exconvrt.c | 9 ++-- drivers/acpi/acpica/exfield.c | 2 +- drivers/acpi/acpica/exfldio.c | 52 +++++++++++----------- drivers/acpi/acpica/exmisc.c | 36 +++++++-------- drivers/acpi/acpica/exnames.c | 2 +- drivers/acpi/acpica/exoparg2.c | 4 +- drivers/acpi/acpica/exoparg3.c | 4 +- drivers/acpi/acpica/exregion.c | 9 ++-- drivers/acpi/acpica/exstorob.c | 18 ++++---- drivers/acpi/acpica/nsaccess.c | 6 +-- drivers/acpi/acpica/nsconvert.c | 10 ++--- drivers/acpi/acpica/nsdump.c | 2 +- drivers/acpi/acpica/nseval.c | 2 +- drivers/acpi/acpica/nsinit.c | 4 +- drivers/acpi/acpica/nsrepair2.c | 2 +- drivers/acpi/acpica/nsutils.c | 3 +- drivers/acpi/acpica/nsxfeval.c | 5 +-- drivers/acpi/acpica/nsxfname.c | 6 +-- drivers/acpi/acpica/psutils.c | 7 ++- drivers/acpi/acpica/rscreate.c | 6 +-- drivers/acpi/acpica/rsmisc.c | 8 ++-- drivers/acpi/acpica/rsutils.c | 11 +++-- drivers/acpi/acpica/rsxface.c | 8 ++-- drivers/acpi/acpica/tbdata.c | 8 ++-- drivers/acpi/acpica/tbfadt.c | 6 +-- drivers/acpi/acpica/tbfind.c | 21 +++++---- drivers/acpi/acpica/tbinstal.c | 7 ++- drivers/acpi/acpica/tbprint.c | 10 ++--- drivers/acpi/acpica/tbutils.c | 2 +- drivers/acpi/acpica/tbxface.c | 16 +++---- drivers/acpi/acpica/tbxfload.c | 4 +- drivers/acpi/acpica/utalloc.c | 6 +-- drivers/acpi/acpica/utbuffer.c | 4 +- drivers/acpi/acpica/utcache.c | 6 +-- drivers/acpi/acpica/utcopy.c | 42 ++++++++--------- drivers/acpi/acpica/utids.c | 9 ++-- drivers/acpi/acpica/utmisc.c | 6 +-- drivers/acpi/acpica/utosi.c | 9 ++-- drivers/acpi/acpica/utpredef.c | 4 +- drivers/acpi/acpica/utprint.c | 6 +-- drivers/acpi/acpica/utstring.c | 33 +++++++------- drivers/acpi/acpica/uttrack.c | 8 ++-- drivers/acpi/acpica/utxface.c | 8 ++-- include/acpi/actypes.h | 8 ++-- include/acpi/platform/acenv.h | 38 ---------------- tools/power/acpi/common/getopt.c | 4 +- .../acpi/os_specific/service_layers/oslinuxtbl.c | 6 +-- tools/power/acpi/tools/acpidump/apdump.c | 8 ++-- tools/power/acpi/tools/acpidump/apfiles.c | 12 ++--- 56 files changed, 260 insertions(+), 312 deletions(-) (limited to 'include') diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6391c9706e84..ef1e51d0f038 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -210,37 +210,35 @@ void acpi_ut_subsystem_shutdown(void); */ #ifndef ACPI_USE_SYSTEM_CLIBRARY -acpi_size acpi_ut_strlen(const char *string); +acpi_size strlen(const char *string); -char *acpi_ut_strchr(const char *string, int ch); +char *strchr(const char *string, int ch); -char *acpi_ut_strcpy(char *dst_string, const char *src_string); +char *strcpy(char *dst_string, const char *src_string); -char *acpi_ut_strncpy(char *dst_string, - const char *src_string, acpi_size count); +char *strncpy(char *dst_string, const char *src_string, acpi_size count); -int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count); +int strncmp(const char *string1, const char *string2, acpi_size count); -int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count); +int strcmp(const char *string1, const char *string2); -int acpi_ut_strcmp(const char *string1, const char *string2); +char *strcat(char *dst_string, const char *src_string); -char *acpi_ut_strcat(char *dst_string, const char *src_string); +char *strncat(char *dst_string, const char *src_string, acpi_size count); -char *acpi_ut_strncat(char *dst_string, - const char *src_string, acpi_size count); +u32 strtoul(const char *string, char **terminator, u32 base); -u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base); +char *strstr(char *string1, char *string2); -char *acpi_ut_strstr(char *string1, char *string2); +int memcmp(void *buffer1, void *buffer2, acpi_size count); -void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count); +void *memcpy(void *dest, const void *src, acpi_size count); -void *acpi_ut_memset(void *dest, u8 value, acpi_size count); +void *memset(void *dest, int value, acpi_size count); -int acpi_ut_to_upper(int c); +int toupper(int c); -int acpi_ut_to_lower(int c); +int tolower(int c); extern const u8 _acpi_ctype[]; @@ -255,13 +253,13 @@ extern const u8 _acpi_ctype[]; #define _ACPI_UP 0x01 /* 'A'-'Z' */ #define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ -#define ACPI_IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) -#define ACPI_IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) -#define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) -#define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) -#define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) -#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) -#define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) +#define isdigit(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) +#define isspace(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) +#define isxdigit(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) +#define isupper(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) +#define islower(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) +#define isprint(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_XS | _ACPI_PU)) +#define isalpha(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) #endif /* !ACPI_USE_SYSTEM_CLIBRARY */ diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 43b40de90484..20de148594fd 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -502,7 +502,7 @@ acpi_ds_create_field(union acpi_parse_object *op, } } - ACPI_MEMSET(&info, 0, sizeof(struct acpi_create_field_info)); + memset(&info, 0, sizeof(struct acpi_create_field_info)); /* Second arg is the field flags */ diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index bbe74bcebbae..95779e8ec3bb 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -207,7 +207,7 @@ acpi_ds_initialize_objects(u32 table_index, /* Set all init info to zero */ - ACPI_MEMSET(&info, 0, sizeof(struct acpi_init_walk_info)); + memset(&info, 0, sizeof(struct acpi_init_walk_info)); info.owner_id = owner_id; info.table_index = table_index; diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 4a4b2f343713..2beb7fd674ae 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -339,8 +339,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, /* Initialize buffer from the byte_list (if present) */ if (byte_list) { - ACPI_MEMCPY(obj_desc->buffer.pointer, - byte_list->named.data, byte_list_length); + memcpy(obj_desc->buffer.pointer, byte_list->named.data, + byte_list_length); } } @@ -750,8 +750,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, case ACPI_TYPE_STRING: obj_desc->string.pointer = op->common.value.string; - obj_desc->string.length = - (u32)ACPI_STRLEN(op->common.value.string); + obj_desc->string.length = (u32)strlen(op->common.value.string); /* * The string is contained in the ACPI table, don't ever try diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index deeddd6d2f05..ebc577baeaf9 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -572,8 +572,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, obj_desc = acpi_ut_create_string_object((acpi_size) name_length); - ACPI_STRNCPY(obj_desc->string.pointer, - name_string, name_length); + strncpy(obj_desc->string.pointer, + name_string, name_length); status = AE_OK; } else { /* diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 8840296d5b20..ea4c0d3fca2d 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -377,7 +377,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, /* 4) The last two characters of the name are the hex GPE Number */ - gpe_number = ACPI_STRTOUL(&name[2], NULL, 16); + gpe_number = strtoul(&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 6e0df2b9d5a4..24a4c5c2b124 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -470,7 +470,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_NO_MEMORY); } - ACPI_MEMCPY(table, table_header, length); + memcpy(table, table_header, length); break; default: diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 89a976b4ccf2..075d654c837f 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -227,9 +227,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, /* Copy the integer to the buffer, LSB first */ new_buf = return_desc->buffer.pointer; - ACPI_MEMCPY(new_buf, - &obj_desc->integer.value, - acpi_gbl_integer_byte_width); + memcpy(new_buf, + &obj_desc->integer.value, acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: @@ -252,8 +251,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, /* Copy the string to the buffer */ new_buf = return_desc->buffer.pointer; - ACPI_STRNCPY((char *)new_buf, (char *)obj_desc->string.pointer, - obj_desc->string.length); + strncpy((char *)new_buf, (char *)obj_desc->string.pointer, + obj_desc->string.length); break; default: diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index c161dd974f74..61fd9c7b88bc 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -428,7 +428,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, } buffer = buffer_desc->buffer.pointer; - ACPI_MEMCPY(buffer, source_desc->buffer.pointer, length); + memcpy(buffer, source_desc->buffer.pointer, length); /* Lock entire transaction if requested */ diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 725a3746a2df..70b7bbbb860b 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -416,22 +416,22 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, * Copy the data from the source buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY(value, - (obj_desc->buffer_field.buffer_obj)->buffer. - pointer + - obj_desc->buffer_field.base_byte_offset + - field_datum_byte_offset, - obj_desc->common_field.access_byte_width); + memcpy(value, + (obj_desc->buffer_field.buffer_obj)->buffer. + pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + obj_desc->common_field.access_byte_width); } else { /* * Copy the data to the target buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY((obj_desc->buffer_field.buffer_obj)->buffer. - pointer + - obj_desc->buffer_field.base_byte_offset + - field_datum_byte_offset, value, - obj_desc->common_field.access_byte_width); + memcpy((obj_desc->buffer_field.buffer_obj)->buffer. + pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, value, + obj_desc->common_field.access_byte_width); } status = AE_OK; @@ -703,7 +703,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_BUFFER_OVERFLOW); } - ACPI_MEMSET(buffer, 0, buffer_length); + memset(buffer, 0, buffer_length); access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width); /* Handle the simple case here */ @@ -720,7 +720,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, status = acpi_ex_field_datum_io(obj_desc, 0, &raw_datum, ACPI_READ); - ACPI_MEMCPY(buffer, &raw_datum, buffer_length); + memcpy(buffer, &raw_datum, buffer_length); } return_ACPI_STATUS(status); @@ -793,9 +793,9 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, /* Write merged datum to target buffer */ - ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(((char *)buffer) + buffer_offset, &merged_datum, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); buffer_offset += obj_desc->common_field.access_byte_width; merged_datum = @@ -811,9 +811,9 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, /* Write the last datum to the buffer */ - ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(((char *)buffer) + buffer_offset, &merged_datum, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); return_ACPI_STATUS(AE_OK); } @@ -878,7 +878,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ - ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length); + memcpy((char *)new_buffer, (char *)buffer, buffer_length); buffer = new_buffer; buffer_length = required_length; } @@ -918,9 +918,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Get initial Datum from the input buffer */ - ACPI_MEMCPY(&raw_datum, buffer, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(&raw_datum, buffer, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; @@ -970,9 +970,9 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* Get the next input datum from the buffer */ buffer_offset += obj_desc->common_field.access_byte_width; - ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset, - ACPI_MIN(obj_desc->common_field.access_byte_width, - buffer_length - buffer_offset)); + memcpy(&raw_datum, ((char *)buffer) + buffer_offset, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset; diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index b56fc9d6f48e..d02afece0f10 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -209,8 +209,8 @@ acpi_ex_concat_template(union acpi_operand_object *operand0, * end_tag descriptor is copied from Operand1. */ new_buf = return_desc->buffer.pointer; - ACPI_MEMCPY(new_buf, operand0->buffer.pointer, length0); - ACPI_MEMCPY(new_buf + length0, operand1->buffer.pointer, length1); + memcpy(new_buf, operand0->buffer.pointer, length0); + memcpy(new_buf + length0, operand1->buffer.pointer, length1); /* Insert end_tag and set the checksum to zero, means "ignore checksum" */ @@ -318,14 +318,14 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Copy the first integer, LSB first */ - ACPI_MEMCPY(new_buf, &operand0->integer.value, - acpi_gbl_integer_byte_width); + memcpy(new_buf, &operand0->integer.value, + acpi_gbl_integer_byte_width); /* Copy the second integer (LSB first) after the first */ - ACPI_MEMCPY(new_buf + acpi_gbl_integer_byte_width, - &local_operand1->integer.value, - acpi_gbl_integer_byte_width); + memcpy(new_buf + acpi_gbl_integer_byte_width, + &local_operand1->integer.value, + acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: @@ -346,9 +346,9 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Concatenate the strings */ - ACPI_STRCPY(new_buf, operand0->string.pointer); - ACPI_STRCPY(new_buf + operand0->string.length, - local_operand1->string.pointer); + strcpy(new_buf, operand0->string.pointer); + strcpy(new_buf + operand0->string.length, + local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: @@ -369,11 +369,11 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, /* Concatenate the buffers */ - ACPI_MEMCPY(new_buf, operand0->buffer.pointer, - operand0->buffer.length); - ACPI_MEMCPY(new_buf + operand0->buffer.length, - local_operand1->buffer.pointer, - local_operand1->buffer.length); + memcpy(new_buf, operand0->buffer.pointer, + operand0->buffer.length); + memcpy(new_buf + operand0->buffer.length, + local_operand1->buffer.pointer, + local_operand1->buffer.length); break; default: @@ -660,9 +660,9 @@ acpi_ex_do_logical_op(u16 opcode, /* Lexicographic compare: compare the data bytes */ - compare = ACPI_MEMCMP(operand0->buffer.pointer, - local_operand1->buffer.pointer, - (length0 > length1) ? length1 : length0); + compare = memcmp(operand0->buffer.pointer, + local_operand1->buffer.pointer, + (length0 > length1) ? length1 : length0); switch (opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 453b00c30177..20e87813c7d7 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -192,7 +192,7 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) char_buf[4] = '\0'; if (name_string) { - ACPI_STRCAT(name_string, char_buf); + strcat(name_string, char_buf); ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Appended to - %s\n", name_string)); } else { diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 6fac5e0a698a..b8944ebb1081 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -337,8 +337,8 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) * Copy the raw buffer data with no transform. * (NULL terminated already) */ - ACPI_MEMCPY(return_desc->string.pointer, - operand[0]->buffer.pointer, length); + memcpy(return_desc->string.pointer, + operand[0]->buffer.pointer, length); break; case AML_CONCAT_RES_OP: diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 1c64a988cbee..fa100b3b92ee 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -237,8 +237,8 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) /* We have a buffer, copy the portion requested */ - ACPI_MEMCPY(buffer, operand[0]->string.pointer + index, - length); + memcpy(buffer, operand[0]->string.pointer + index, + length); } /* Set the length of the new String/Buffer */ diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index f6c2f5499935..b4a5e44c00dd 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -517,15 +517,14 @@ acpi_ex_data_table_space_handler(u32 function, switch (function) { case ACPI_READ: - ACPI_MEMCPY(ACPI_CAST_PTR(char, value), - ACPI_PHYSADDR_TO_PTR(address), - ACPI_DIV_8(bit_width)); + memcpy(ACPI_CAST_PTR(char, value), + ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width)); break; case ACPI_WRITE: - ACPI_MEMCPY(ACPI_PHYSADDR_TO_PTR(address), - ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); + memcpy(ACPI_PHYSADDR_TO_PTR(address), + ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width)); break; default: diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 6fa3c8d8fc5f..e1d4f4d51b97 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -100,9 +100,9 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, /* Clear existing buffer and copy in the new one */ - ACPI_MEMSET(target_desc->buffer.pointer, 0, - target_desc->buffer.length); - ACPI_MEMCPY(target_desc->buffer.pointer, buffer, length); + memset(target_desc->buffer.pointer, 0, + target_desc->buffer.length); + memcpy(target_desc->buffer.pointer, buffer, length); #ifdef ACPI_OBSOLETE_BEHAVIOR /* @@ -129,8 +129,8 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, } else { /* Truncate the source, copy only what will fit */ - ACPI_MEMCPY(target_desc->buffer.pointer, buffer, - target_desc->buffer.length); + memcpy(target_desc->buffer.pointer, buffer, + target_desc->buffer.length); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Truncating source buffer from %X to %X\n", @@ -187,9 +187,9 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, * String will fit in existing non-static buffer. * Clear old string and copy in the new one */ - ACPI_MEMSET(target_desc->string.pointer, 0, - (acpi_size) target_desc->string.length + 1); - ACPI_MEMCPY(target_desc->string.pointer, buffer, length); + memset(target_desc->string.pointer, 0, + (acpi_size) target_desc->string.length + 1); + memcpy(target_desc->string.pointer, buffer, length); } else { /* * Free the current buffer, then allocate a new buffer @@ -210,7 +210,7 @@ acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, } target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; - ACPI_MEMCPY(target_desc->string.pointer, buffer, length); + memcpy(target_desc->string.pointer, buffer, length); } /* Set the new target length */ diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 19ad0b5993d5..c687b9979fb2 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -102,7 +102,7 @@ acpi_status acpi_ns_root_initialize(void) /* _OSI is optional for now, will be permanent later */ - if (!ACPI_STRCMP(init_val->name, "_OSI") + if (!strcmp(init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { continue; } @@ -180,7 +180,7 @@ acpi_status acpi_ns_root_initialize(void) /* Build an object around the static string */ - obj_desc->string.length = (u32)ACPI_STRLEN(val); + obj_desc->string.length = (u32)strlen(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; @@ -203,7 +203,7 @@ acpi_status acpi_ns_root_initialize(void) /* Special case for ACPI Global Lock */ - if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { + if (strcmp(init_val->name, "_GL_") == 0) { acpi_gbl_global_lock_mutex = obj_desc; /* Create additional counting semaphore for global lock */ diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index 1a8b39c8d969..da55a1c60da1 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -187,8 +187,8 @@ acpi_ns_convert_to_string(union acpi_operand_object *original_object, * Copy the raw buffer data with no transform. String is already NULL * terminated at Length+1. */ - ACPI_MEMCPY(new_object->string.pointer, - original_object->buffer.pointer, length); + memcpy(new_object->string.pointer, + original_object->buffer.pointer, length); break; default: @@ -251,9 +251,9 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, return (AE_NO_MEMORY); } - ACPI_MEMCPY(new_object->buffer.pointer, - original_object->string.pointer, - original_object->string.length); + memcpy(new_object->buffer.pointer, + original_object->string.pointer, + original_object->string.length); break; case ACPI_TYPE_PACKAGE: diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index d259393505fa..0f1daba640e7 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -101,7 +101,7 @@ void acpi_ns_print_pathname(u32 num_segments, char *pathname) while (num_segments) { for (i = 0; i < 4; i++) { - ACPI_IS_PRINT(pathname[i]) ? + isprint((int)pathname[i]) ? acpi_os_printf("%c", pathname[i]) : acpi_os_printf("?"); } diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 7bcc68f57afa..a725d88b036b 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -440,7 +440,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, /* Initialize the evaluation information block */ - ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info)); + memset(info, 0, sizeof(struct acpi_evaluate_info)); info->prefix_node = parent_node; /* diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 4a85c4517988..b744a53618eb 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -90,7 +90,7 @@ acpi_status acpi_ns_initialize_objects(void) /* Set all init info to zero */ - ACPI_MEMSET(&info, 0, sizeof(struct acpi_init_walk_info)); + memset(&info, 0, sizeof(struct acpi_init_walk_info)); /* Walk entire namespace from the supplied root */ @@ -566,7 +566,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle, ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, device_node, METHOD_NAME__INI)); - ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info)); + memset(info, 0, sizeof(struct acpi_evaluate_info)); info->prefix_node = device_node; info->relative_pathname = METHOD_NAME__INI; info->parameters = NULL; diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index c30672d23878..0515a70f42a4 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -580,7 +580,7 @@ acpi_ns_repair_HID(struct acpi_evaluate_info *info, * # is a hex digit. */ for (dest = new_string->string.pointer; *source; dest++, source++) { - *dest = (char)ACPI_TOUPPER(*source); + *dest = (char)toupper((int)*source); } acpi_ut_remove_reference(return_object); diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 6ad02008c0c2..8d8104b8bd28 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -292,8 +292,7 @@ acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) } else { /* Convert the character to uppercase and save it */ - result[i] = - (char)ACPI_TOUPPER((int)*external_name); + result[i] = (char)toupper((int)*external_name); external_name++; } } diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index b6030a2deee1..6ee1e52b903d 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -696,7 +696,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, return (AE_CTRL_DEPTH); } - no_match = ACPI_STRCMP(hid->string, info->hid); + no_match = strcmp(hid->string, info->hid); ACPI_FREE(hid); if (no_match) { @@ -715,8 +715,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, found = FALSE; for (i = 0; i < cid->count; i++) { - if (ACPI_STRCMP(cid->ids[i].string, info->hid) - == 0) { + if (strcmp(cid->ids[i].string, info->hid) == 0) { /* Found a matching CID */ diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index dc0836a9cf17..9ff643b9553f 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -114,7 +114,7 @@ acpi_get_handle(acpi_handle parent, /* Special case for root-only, since we can't search for it */ - if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { + if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) { *ret_handle = ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); return (AE_OK); @@ -242,7 +242,7 @@ static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, /* Copy actual string and return a pointer to the next string area */ - ACPI_MEMCPY(string_area, source->string, source->length); + memcpy(string_area, source->string, source->length); return (string_area + source->length); } @@ -637,7 +637,7 @@ acpi_status acpi_install_method(u8 *buffer) /* Copy the method AML to the local buffer */ - ACPI_MEMCPY(aml_buffer, aml_start, aml_length); + memcpy(aml_buffer, aml_start, aml_length); /* Initialize the method object with the new method's information */ diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 960505ab409a..32440912023a 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -93,10 +93,9 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) op->common.descriptor_type = ACPI_DESC_TYPE_PARSER; op->common.aml_opcode = opcode; - ACPI_DISASM_ONLY_MEMBERS(ACPI_STRNCPY(op->common.aml_op_name, - (acpi_ps_get_opcode_info - (opcode))->name, - sizeof(op->common.aml_op_name))); + ACPI_DISASM_ONLY_MEMBERS(strncpy(op->common.aml_op_name, + (acpi_ps_get_opcode_info(opcode))-> + name, sizeof(op->common.aml_op_name))); } /******************************************************************************* diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index f30f35e6ff2a..3fa829e96c2a 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -353,13 +353,13 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, /* +1 to include null terminator */ user_prt->length += - (u32)ACPI_STRLEN(user_prt->source) + 1; + (u32)strlen(user_prt->source) + 1; break; case ACPI_TYPE_STRING: - ACPI_STRCPY(user_prt->source, - obj_desc->string.pointer); + strcpy(user_prt->source, + obj_desc->string.pointer); /* * Add to the Length field the length of the string diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 1fe49d223663..ac37852e0821 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -119,7 +119,7 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, /* * Get the resource type and the initial (minimum) length */ - ACPI_MEMSET(resource, 0, INIT_RESOURCE_LENGTH(info)); + memset(resource, 0, INIT_RESOURCE_LENGTH(info)); resource->type = INIT_RESOURCE_TYPE(info); resource->length = INIT_RESOURCE_LENGTH(info); break; @@ -324,13 +324,13 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, case ACPI_RSC_SET8: - ACPI_MEMSET(destination, info->aml_offset, info->value); + memset(destination, info->aml_offset, info->value); break; case ACPI_RSC_DATA8: target = ACPI_ADD_PTR(char, resource, info->value); - ACPI_MEMCPY(destination, source, ACPI_GET16(target)); + memcpy(destination, source, ACPI_GET16(target)); break; case ACPI_RSC_ADDRESS: @@ -502,7 +502,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, switch (info->opcode) { case ACPI_RSC_INITSET: - ACPI_MEMSET(aml, 0, INIT_RESOURCE_LENGTH(info)); + memset(aml, 0, INIT_RESOURCE_LENGTH(info)); aml_length = INIT_RESOURCE_LENGTH(info); acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), aml_length, aml); diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 90417de38dab..52b024df0052 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -148,7 +148,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) case ACPI_RSC_MOVE_SERIAL_VEN: case ACPI_RSC_MOVE_SERIAL_RES: - ACPI_MEMCPY(destination, source, item_count); + memcpy(destination, source, item_count); return; /* @@ -364,12 +364,11 @@ acpi_rs_get_resource_source(acpi_rs_length resource_length, * Zero the entire area of the buffer. */ total_length = - (u32) - ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + + (u32)strlen(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1; total_length = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(total_length); - ACPI_MEMSET(resource_source->string_ptr, 0, total_length); + memset(resource_source->string_ptr, 0, total_length); /* Copy the resource_source string to the destination */ @@ -432,8 +431,8 @@ acpi_rs_set_resource_source(union aml_resource * aml, /* Copy the resource_source string */ - ACPI_STRCPY(ACPI_CAST_PTR(char, &aml_resource_source[1]), - resource_source->string_ptr); + strcpy(ACPI_CAST_PTR(char, &aml_resource_source[1]), + resource_source->string_ptr); /* * Add the length of the string (+ 1 for null terminator) to the diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 8e6276df0226..de51f836ef68 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -398,8 +398,8 @@ acpi_resource_to_address64(struct acpi_resource *resource, /* Simple copy for 64 bit source */ - ACPI_MEMCPY(out, &resource->data, - sizeof(struct acpi_resource_address64)); + memcpy(out, &resource->data, + sizeof(struct acpi_resource_address64)); break; default: @@ -499,7 +499,7 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) */ if ((vendor->byte_length < (ACPI_UUID_LENGTH + 1)) || (vendor->uuid_subtype != info->uuid->subtype) || - (ACPI_MEMCMP(vendor->uuid, info->uuid->data, ACPI_UUID_LENGTH))) { + (memcmp(vendor->uuid, info->uuid->data, ACPI_UUID_LENGTH))) { return (AE_OK); } @@ -513,7 +513,7 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) /* Found the correct resource, copy and return it */ - ACPI_MEMCPY(buffer->pointer, resource, resource->length); + memcpy(buffer->pointer, resource, resource->length); buffer->length = resource->length; /* Found the desired descriptor, terminate resource walk */ diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index d7f8386455bd..5c9d5abf1588 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -73,7 +73,7 @@ acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc, * Initialize the table descriptor. Set the pointer to NULL, since the * table is not fully mapped at this time. */ - ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc)); + memset(table_desc, 0, sizeof(struct acpi_table_desc)); table_desc->address = address; table_desc->length = table->length; table_desc->flags = flags; @@ -465,9 +465,9 @@ acpi_status acpi_tb_resize_root_table_list(void) /* Copy and free the previous table array */ if (acpi_gbl_root_table_list.tables) { - ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, - (acpi_size) table_count * - sizeof(struct acpi_table_desc)); + memcpy(tables, acpi_gbl_root_table_list.tables, + (acpi_size) table_count * + sizeof(struct acpi_table_desc)); if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { ACPI_FREE(acpi_gbl_root_table_list.tables); diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 05be59c772c7..6253001b6375 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -398,12 +398,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) /* Clear the entire local FADT */ - ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); + memset(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */ - ACPI_MEMCPY(&acpi_gbl_FADT, table, - ACPI_MIN(length, sizeof(struct acpi_table_fadt))); + memcpy(&acpi_gbl_FADT, table, + ACPI_MIN(length, sizeof(struct acpi_table_fadt))); /* Take a copy of the Hardware Reduced flag */ diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 0b879fcfef67..119c84ad9833 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -76,16 +76,16 @@ acpi_tb_find_table(char *signature, /* Normalize the input strings */ - ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header)); + memset(&header, 0, sizeof(struct acpi_table_header)); ACPI_MOVE_NAME(header.signature, signature); - ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); - ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); + strncpy(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); + strncpy(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); /* Search for the table */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { - if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature), - header.signature, ACPI_NAME_SIZE)) { + if (memcmp(&(acpi_gbl_root_table_list.tables[i].signature), + header.signature, ACPI_NAME_SIZE)) { /* Not the requested table */ @@ -112,21 +112,20 @@ acpi_tb_find_table(char *signature, /* Check for table match on all IDs */ - if (!ACPI_MEMCMP + if (!memcmp (acpi_gbl_root_table_list.tables[i].pointer->signature, header.signature, ACPI_NAME_SIZE) && (!oem_id[0] || - !ACPI_MEMCMP + !memcmp (acpi_gbl_root_table_list. tables[i].pointer-> oem_id, header.oem_id, ACPI_OEM_ID_SIZE)) && (!oem_table_id[0] - || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i]. - pointer->oem_table_id, - header.oem_table_id, - ACPI_OEM_TABLE_ID_SIZE))) { + || !memcmp(acpi_gbl_root_table_list.tables[i].pointer-> + oem_table_id, header.oem_table_id, + ACPI_OEM_TABLE_ID_SIZE))) { *table_index = i; ACPI_DEBUG_PRINT((ACPI_DB_TABLES, diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 008a251780f4..15ea98e0068d 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -87,8 +87,8 @@ acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) * not just the header. */ is_identical = (u8)((table_desc->length != table_length || - ACPI_MEMCMP(table_desc->pointer, table, - table_length)) ? FALSE : TRUE); + memcmp(table_desc->pointer, table, table_length)) ? + FALSE : TRUE); /* Release the acquired table */ @@ -289,8 +289,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, if ((new_table_desc.signature.ascii[0] != 0x00) && (!ACPI_COMPARE_NAME (&new_table_desc.signature, ACPI_SIG_SSDT)) - && (ACPI_STRNCMP(new_table_desc.signature.ascii, "OEM", 3))) - { + && (strncmp(new_table_desc.signature.ascii, "OEM", 3))) { ACPI_BIOS_ERROR((AE_INFO, "Table has invalid signature [%4.4s] (0x%8.8X), " "must be SSDT or OEMx", diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index 77ba5c71c6e7..709d5112fc16 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -73,7 +73,7 @@ static void acpi_tb_fix_string(char *string, acpi_size length) { while (length && *string) { - if (!ACPI_IS_PRINT(*string)) { + if (!isprint((int)*string)) { *string = '?'; } string++; @@ -100,7 +100,7 @@ acpi_tb_cleanup_table_header(struct acpi_table_header *out_header, struct acpi_table_header *header) { - ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header)); + memcpy(out_header, header, sizeof(struct acpi_table_header)); acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE); acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE); @@ -138,9 +138,9 @@ acpi_tb_print_table_header(acpi_physical_address address, /* RSDP has no common fields */ - ACPI_MEMCPY(local_header.oem_id, - ACPI_CAST_PTR(struct acpi_table_rsdp, - header)->oem_id, ACPI_OEM_ID_SIZE); + memcpy(local_header.oem_id, + ACPI_CAST_PTR(struct acpi_table_rsdp, header)->oem_id, + ACPI_OEM_ID_SIZE); acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE); ACPI_INFO((AE_INFO, "RSDP 0x%8.8X%8.8X %06X (v%.2d %-6.6s)", diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 2bb6a117c840..568ac0e4a3c6 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -188,7 +188,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) return (NULL); } - ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); + memcpy(new_table, table_desc->pointer, table_desc->length); acpi_tb_uninstall_table(table_desc); acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 54b9f7957ff1..5559e2c70b15 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -119,9 +119,9 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array, } else { /* Root Table Array has been statically allocated by the host */ - ACPI_MEMSET(initial_table_array, 0, - (acpi_size) initial_table_count * - sizeof(struct acpi_table_desc)); + memset(initial_table_array, 0, + (acpi_size) initial_table_count * + sizeof(struct acpi_table_desc)); acpi_gbl_root_table_list.tables = initial_table_array; acpi_gbl_root_table_list.max_table_count = initial_table_count; @@ -243,8 +243,8 @@ acpi_get_table_header(char *signature, return (AE_NO_MEMORY); } - ACPI_MEMCPY(out_table_header, header, - sizeof(struct acpi_table_header)); + memcpy(out_table_header, header, + sizeof(struct acpi_table_header)); acpi_os_unmap_memory(header, sizeof(struct acpi_table_header)); @@ -252,9 +252,9 @@ acpi_get_table_header(char *signature, return (AE_NOT_FOUND); } } else { - ACPI_MEMCPY(out_table_header, - acpi_gbl_root_table_list.tables[i].pointer, - sizeof(struct acpi_table_header)); + memcpy(out_table_header, + acpi_gbl_root_table_list.tables[i].pointer, + sizeof(struct acpi_table_header)); } return (AE_OK); } diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index cf56e18cdc64..9682d40ca6ff 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -150,8 +150,8 @@ static acpi_status acpi_tb_load_namespace(void) * Save the original DSDT header for detection of table corruption * and/or replacement of the DSDT from outside the OS. */ - ACPI_MEMCPY(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, - sizeof(struct acpi_table_header)); + memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, + sizeof(struct acpi_table_header)); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 61d8f6d186d1..7a4101f0685e 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -73,7 +73,7 @@ void *acpi_os_allocate_zeroed(acpi_size size) /* Clear the memory block */ - ACPI_MEMSET(allocation, 0, size); + memset(allocation, 0, size); } return (allocation); @@ -181,7 +181,7 @@ acpi_status acpi_ut_delete_caches(void) char buffer[7]; if (acpi_gbl_display_final_mem_stats) { - ACPI_STRCPY(buffer, "MEMORY"); + strcpy(buffer, "MEMORY"); (void)acpi_db_display_statistics(buffer); } #endif @@ -337,6 +337,6 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, /* Have a valid buffer, clear it */ - ACPI_MEMSET(buffer->pointer, 0, required_length); + memset(buffer->pointer, 0, required_length); return (AE_OK); } diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index a8c39643e618..01c8709ca586 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -159,7 +159,7 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) } buf_char = buffer[(acpi_size) i + j]; - if (ACPI_IS_PRINT(buf_char)) { + if (isprint(buf_char)) { acpi_os_printf("%c", buf_char); } else { acpi_os_printf("."); @@ -319,7 +319,7 @@ acpi_ut_dump_buffer_to_file(ACPI_FILE file, } buf_char = buffer[(acpi_size) i + j]; - if (ACPI_IS_PRINT(buf_char)) { + if (isprint(buf_char)) { acpi_ut_file_printf(file, "%c", buf_char); } else { acpi_ut_file_printf(file, "."); diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index eacc5eee362e..0d21fbd99363 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -84,7 +84,7 @@ acpi_os_create_cache(char *cache_name, /* Populate the cache object and return it */ - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + memset(cache, 0, sizeof(struct acpi_memory_list)); cache->list_name = cache_name; cache->object_size = object_size; cache->max_depth = max_depth; @@ -212,7 +212,7 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object) /* Mark the object as cached */ - ACPI_MEMSET(object, 0xCA, cache->object_size); + memset(object, 0xCA, cache->object_size); ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); /* Put the object at the head of the cache list */ @@ -281,7 +281,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) /* Clear (zero) the previously used Object */ - ACPI_MEMSET(object, 0, cache->object_size); + memset(object, 0, cache->object_size); } else { /* The cache is empty, create a new object */ diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index c37ec5035f4c..257221d452c8 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -129,7 +129,7 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, /* Always clear the external object */ - ACPI_MEMSET(external_object, 0, sizeof(union acpi_object)); + memset(external_object, 0, sizeof(union acpi_object)); /* * In general, the external object will be the same type as @@ -149,9 +149,9 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, string. length + 1); - ACPI_MEMCPY((void *)data_space, - (void *)internal_object->string.pointer, - (acpi_size) internal_object->string.length + 1); + memcpy((void *)data_space, + (void *)internal_object->string.pointer, + (acpi_size) internal_object->string.length + 1); break; case ACPI_TYPE_BUFFER: @@ -162,9 +162,9 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object, ACPI_ROUND_UP_TO_NATIVE_WORD(internal_object->string. length); - ACPI_MEMCPY((void *)data_space, - (void *)internal_object->buffer.pointer, - internal_object->buffer.length); + memcpy((void *)data_space, + (void *)internal_object->buffer.pointer, + internal_object->buffer.length); break; case ACPI_TYPE_INTEGER: @@ -502,9 +502,9 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, goto error_exit; } - ACPI_MEMCPY(internal_object->string.pointer, - external_object->string.pointer, - external_object->string.length); + memcpy(internal_object->string.pointer, + external_object->string.pointer, + external_object->string.length); internal_object->string.length = external_object->string.length; break; @@ -517,9 +517,9 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object, goto error_exit; } - ACPI_MEMCPY(internal_object->buffer.pointer, - external_object->buffer.pointer, - external_object->buffer.length); + memcpy(internal_object->buffer.pointer, + external_object->buffer.pointer, + external_object->buffer.length); internal_object->buffer.length = external_object->buffer.length; @@ -694,8 +694,8 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, copy_size = sizeof(struct acpi_namespace_node); } - ACPI_MEMCPY(ACPI_CAST_PTR(char, dest_desc), - ACPI_CAST_PTR(char, source_desc), copy_size); + memcpy(ACPI_CAST_PTR(char, dest_desc), + ACPI_CAST_PTR(char, source_desc), copy_size); /* Restore the saved fields */ @@ -725,9 +725,9 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, /* Copy the actual buffer data */ - ACPI_MEMCPY(dest_desc->buffer.pointer, - source_desc->buffer.pointer, - source_desc->buffer.length); + memcpy(dest_desc->buffer.pointer, + source_desc->buffer.pointer, + source_desc->buffer.length); } break; @@ -747,9 +747,9 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, /* Copy the actual string data */ - ACPI_MEMCPY(dest_desc->string.pointer, - source_desc->string.pointer, - (acpi_size) source_desc->string.length + 1); + memcpy(dest_desc->string.pointer, + source_desc->string.pointer, + (acpi_size) source_desc->string.length + 1); } break; diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 3afe07f19b9f..7956df1e263c 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -111,7 +111,7 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node, if (obj_desc->common.type == ACPI_TYPE_INTEGER) { acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value); } else { - ACPI_STRCPY(hid->string, obj_desc->string.pointer); + strcpy(hid->string, obj_desc->string.pointer); } hid->length = length; @@ -180,7 +180,7 @@ acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, /* Simply copy existing string */ - ACPI_STRCPY(sub->string, obj_desc->string.pointer); + strcpy(sub->string, obj_desc->string.pointer); sub->length = length; *return_id = sub; @@ -256,7 +256,7 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, if (obj_desc->common.type == ACPI_TYPE_INTEGER) { acpi_ex_integer_to_string(uid->string, obj_desc->integer.value); } else { - ACPI_STRCPY(uid->string, obj_desc->string.pointer); + strcpy(uid->string, obj_desc->string.pointer); } uid->length = length; @@ -393,8 +393,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node, /* Copy the String CID from the returned object */ - ACPI_STRCPY(next_id_string, - cid_objects[i]->string.pointer); + strcpy(next_id_string, cid_objects[i]->string.pointer); length = cid_objects[i]->string.length + 1; } diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 28099e230008..71b66537f826 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -66,9 +66,9 @@ u8 acpi_ut_is_pci_root_bridge(char *id) * Check if this is a PCI root bridge. * ACPI 3.0+: check for a PCI Express root also. */ - if (!(ACPI_STRCMP(id, - PCI_ROOT_HID_STRING)) || - !(ACPI_STRCMP(id, PCI_EXPRESS_ROOT_HID_STRING))) { + if (!(strcmp(id, + PCI_ROOT_HID_STRING)) || + !(strcmp(id, PCI_EXPRESS_ROOT_HID_STRING))) { return (TRUE); } diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 44035abdbf29..8f3d203aed79 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -232,8 +232,7 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name) return (AE_NO_MEMORY); } - interface_info->name = - ACPI_ALLOCATE_ZEROED(ACPI_STRLEN(interface_name) + 1); + interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1); if (!interface_info->name) { ACPI_FREE(interface_info); return (AE_NO_MEMORY); @@ -241,7 +240,7 @@ acpi_status acpi_ut_install_interface(acpi_string interface_name) /* Initialize new info and insert at the head of the global list */ - ACPI_STRCPY(interface_info->name, interface_name); + strcpy(interface_info->name, interface_name); interface_info->flags = ACPI_OSI_DYNAMIC; interface_info->next = acpi_gbl_supported_interfaces; @@ -269,7 +268,7 @@ acpi_status acpi_ut_remove_interface(acpi_string interface_name) previous_interface = next_interface = acpi_gbl_supported_interfaces; while (next_interface) { - if (!ACPI_STRCMP(interface_name, next_interface->name)) { + if (!strcmp(interface_name, next_interface->name)) { /* Found: name is in either the static list or was added at runtime */ @@ -373,7 +372,7 @@ struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name) next_interface = acpi_gbl_supported_interfaces; while (next_interface) { - if (!ACPI_STRCMP(interface_name, next_interface->name)) { + if (!strcmp(interface_name, next_interface->name)) { return (next_interface); } diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index 29e449935a82..97898ed71b4b 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -148,7 +148,7 @@ void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes) u32 j; if (!expected_btypes) { - ACPI_STRCPY(buffer, "NONE"); + strcpy(buffer, "NONE"); return; } @@ -161,7 +161,7 @@ void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes) /* If one of the expected types, concatenate the name of this type */ if (expected_btypes & this_rtype) { - ACPI_STRCAT(buffer, &ut_rtype_names[i][j]); + strcat(buffer, &ut_rtype_names[i][j]); j = 0; /* Use name separator from now on */ } diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 2be6bd4bdc09..b26297c5de49 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -180,7 +180,7 @@ const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) { u64 number = 0; - while (ACPI_IS_DIGIT(*string)) { + while (isdigit((int)*string)) { number *= 10; number += *(string++) - '0'; } @@ -405,7 +405,7 @@ acpi_ut_vsnprintf(char *string, /* Process width */ width = -1; - if (ACPI_IS_DIGIT(*format)) { + if (isdigit((int)*format)) { format = acpi_ut_scan_number(format, &number); width = (s32) number; } else if (*format == '*') { @@ -422,7 +422,7 @@ acpi_ut_vsnprintf(char *string, precision = -1; if (*format == '.') { ++format; - if (ACPI_IS_DIGIT(*format)) { + if (isdigit((int)*format)) { format = acpi_ut_scan_number(format, &number); precision = (s32) number; } else if (*format == '*') { diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 83b6c52490dc..8f3c883dfe0e 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -79,7 +79,7 @@ void acpi_ut_strlwr(char *src_string) /* Walk entire string, lowercasing the letters */ for (string = src_string; *string; string++) { - *string = (char)ACPI_TOLOWER(*string); + *string = (char)tolower((int)*string); } return; @@ -145,7 +145,7 @@ void acpi_ut_strupr(char *src_string) /* Walk entire string, uppercasing the letters */ for (string = src_string; *string; string++) { - *string = (char)ACPI_TOUPPER(*string); + *string = (char)toupper((int)*string); } return; @@ -202,7 +202,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Skip over any white space in the buffer */ - while ((*string) && (ACPI_IS_SPACE(*string) || *string == '\t')) { + while ((*string) && (isspace((int)*string) || *string == '\t')) { string++; } @@ -211,7 +211,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. * We need to determine if it is decimal or hexadecimal. */ - if ((*string == '0') && (ACPI_TOLOWER(*(string + 1)) == 'x')) { + if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { sign_of0x = 1; base = 16; @@ -224,7 +224,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Any string left? Check that '0x' is not followed by white space. */ - if (!(*string) || ACPI_IS_SPACE(*string) || *string == '\t') { + if (!(*string) || isspace((int)*string) || *string == '\t') { if (to_integer_op) { goto error_exit; } else { @@ -241,7 +241,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) /* Main loop: convert the string to a 32- or 64-bit integer */ while (*string) { - if (ACPI_IS_DIGIT(*string)) { + if (isdigit((int)*string)) { /* Convert ASCII 0-9 to Decimal value */ @@ -252,8 +252,8 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) term = 1; } else { - this_digit = (u8)ACPI_TOUPPER(*string); - if (ACPI_IS_XDIGIT((char)this_digit)) { + this_digit = (u8)toupper((int)*string); + if (isxdigit((int)this_digit)) { /* Convert ASCII Hex char to value */ @@ -404,7 +404,7 @@ void acpi_ut_print_string(char *string, u16 max_length) /* Check for printable character or hex escape */ - if (ACPI_IS_PRINT(string[i])) { + if (isprint((int)string[i])) { /* This is a normal character */ acpi_os_printf("%c", (int)string[i]); @@ -609,22 +609,22 @@ void ut_convert_backslashes(char *pathname) u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) { - if (ACPI_STRLEN(source) >= dest_size) { + if (strlen(source) >= dest_size) { return (TRUE); } - ACPI_STRCPY(dest, source); + strcpy(dest, source); return (FALSE); } u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) { - if ((ACPI_STRLEN(dest) + ACPI_STRLEN(source)) >= dest_size) { + if ((strlen(dest) + strlen(source)) >= dest_size) { return (TRUE); } - ACPI_STRCAT(dest, source); + strcat(dest, source); return (FALSE); } @@ -635,14 +635,13 @@ acpi_ut_safe_strncat(char *dest, { acpi_size actual_transfer_length; - actual_transfer_length = - ACPI_MIN(max_transfer_length, ACPI_STRLEN(source)); + actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); - if ((ACPI_STRLEN(dest) + actual_transfer_length) >= dest_size) { + if ((strlen(dest) + actual_transfer_length) >= dest_size) { return (TRUE); } - ACPI_STRNCAT(dest, source, max_transfer_length); + strncat(dest, source, max_transfer_length); return (FALSE); } #endif diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index 130dd9f96f0f..9a7dc8196a5d 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -100,7 +100,7 @@ acpi_ut_create_list(char *list_name, return (AE_NO_MEMORY); } - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + memset(cache, 0, sizeof(struct acpi_memory_list)); cache->list_name = list_name; cache->object_size = object_size; @@ -402,7 +402,7 @@ acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, allocation->component = component; allocation->line = line; - ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME); + strncpy(allocation->module, module, ACPI_MAX_MODULE_NAME); allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; if (!element) { @@ -497,7 +497,7 @@ acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, /* Mark the segment as deleted */ - ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size); + memset(&allocation->user_space, 0xEA, allocation->size); status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); return (status); @@ -595,7 +595,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module) while (element) { if ((element->component & component) && ((module == NULL) - || (0 == ACPI_STRCMP(module, element->module)))) { + || (0 == strcmp(module, element->module)))) { descriptor = ACPI_CAST_PTR(union acpi_descriptor, &element->user_space); diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 0929187bdce0..51cf52d52243 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -234,8 +234,8 @@ acpi_status acpi_get_statistics(struct acpi_statistics *stats) stats->sci_count = acpi_sci_count; stats->gpe_count = acpi_gpe_count; - ACPI_MEMCPY(stats->fixed_event_count, acpi_fixed_event_count, - sizeof(acpi_fixed_event_count)); + memcpy(stats->fixed_event_count, acpi_fixed_event_count, + sizeof(acpi_fixed_event_count)); /* Other counters */ @@ -322,7 +322,7 @@ acpi_status acpi_install_interface(acpi_string interface_name) /* Parameter validation */ - if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) { + if (!interface_name || (strlen(interface_name) == 0)) { return (AE_BAD_PARAMETER); } @@ -374,7 +374,7 @@ acpi_status acpi_remove_interface(acpi_string interface_name) /* Parameter validation */ - if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) { + if (!interface_name || (strlen(interface_name) == 0)) { return (AE_BAD_PARAMETER); } diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index d791b986002a..c2a41d223162 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -542,14 +542,14 @@ typedef u64 acpi_integer; #define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32, (a)) == *ACPI_CAST_PTR (u32, (b))) #define ACPI_MOVE_NAME(dest,src) (*ACPI_CAST_PTR (u32, (dest)) = *ACPI_CAST_PTR (u32, (src))) #else -#define ACPI_COMPARE_NAME(a,b) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) -#define ACPI_MOVE_NAME(dest,src) (ACPI_STRNCPY (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) +#define ACPI_COMPARE_NAME(a,b) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) +#define ACPI_MOVE_NAME(dest,src) (strncpy (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) #endif /* Support for the special RSDP signature (8 characters) */ -#define ACPI_VALIDATE_RSDP_SIG(a) (!ACPI_STRNCMP (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) -#define ACPI_MAKE_RSDP_SIG(dest) (ACPI_MEMCPY (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) +#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) +#define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) /******************************************************************************* * diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 1e84e62b448d..3cedd43943f4 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -346,28 +346,6 @@ /* We will be linking to the standard Clib functions */ -#define ACPI_STRSTR(s1,s2) strstr((s1), (s2)) -#define ACPI_STRCHR(s1,c) strchr((s1), (c)) -#define ACPI_STRLEN(s) (acpi_size) strlen((s)) -#define ACPI_STRCPY(d,s) (void) strcpy((d), (s)) -#define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (acpi_size)(n)) -#define ACPI_STRNCMP(d,s,n) strncmp((d), (s), (acpi_size)(n)) -#define ACPI_STRCMP(d,s) strcmp((d), (s)) -#define ACPI_STRCAT(d,s) (void) strcat((d), (s)) -#define ACPI_STRNCAT(d,s,n) strncat((d), (s), (acpi_size)(n)) -#define ACPI_STRTOUL(d,s,n) strtoul((d), (s), (acpi_size)(n)) -#define ACPI_MEMCMP(s1,s2,n) memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) -#define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (acpi_size)(n)) -#define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (acpi_size)(n)) -#define ACPI_TOUPPER(i) toupper((int) (i)) -#define ACPI_TOLOWER(i) tolower((int) (i)) -#define ACPI_IS_XDIGIT(i) isxdigit((int) (i)) -#define ACPI_IS_DIGIT(i) isdigit((int) (i)) -#define ACPI_IS_SPACE(i) isspace((int) (i)) -#define ACPI_IS_UPPER(i) isupper((int) (i)) -#define ACPI_IS_PRINT(i) isprint((int) (i)) -#define ACPI_IS_ALPHA(i) isalpha((int) (i)) - #else /****************************************************************************** @@ -405,22 +383,6 @@ typedef char *va_list; /* Use the local (ACPICA) definitions of the clib functions */ -#define ACPI_STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2)) -#define ACPI_STRCHR(s1,c) acpi_ut_strchr ((s1), (c)) -#define ACPI_STRLEN(s) (acpi_size) acpi_ut_strlen ((s)) -#define ACPI_STRCPY(d,s) (void) acpi_ut_strcpy ((d), (s)) -#define ACPI_STRNCPY(d,s,n) (void) acpi_ut_strncpy ((d), (s), (acpi_size)(n)) -#define ACPI_STRNCMP(d,s,n) acpi_ut_strncmp ((d), (s), (acpi_size)(n)) -#define ACPI_STRCMP(d,s) acpi_ut_strcmp ((d), (s)) -#define ACPI_STRCAT(d,s) (void) acpi_ut_strcat ((d), (s)) -#define ACPI_STRNCAT(d,s,n) acpi_ut_strncat ((d), (s), (acpi_size)(n)) -#define ACPI_STRTOUL(d,s,n) acpi_ut_strtoul ((d), (s), (acpi_size)(n)) -#define ACPI_MEMCMP(s1,s2,n) acpi_ut_memcmp((const char *)(s1), (const char *)(s2), (acpi_size)(n)) -#define ACPI_MEMCPY(d,s,n) (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n)) -#define ACPI_MEMSET(d,v,n) (void) acpi_ut_memset ((d), (v), (acpi_size)(n)) -#define ACPI_TOUPPER(c) acpi_ut_to_upper ((int) (c)) -#define ACPI_TOLOWER(c) acpi_ut_to_lower ((int) (c)) - #endif /* ACPI_USE_SYSTEM_CLIBRARY */ #ifndef ACPI_FILE diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c index 5da129e10aa2..326e826a5d20 100644 --- a/tools/power/acpi/common/getopt.c +++ b/tools/power/acpi/common/getopt.c @@ -127,7 +127,7 @@ int acpi_getopt(int argc, char **argv, char *opts) argv[acpi_gbl_optind][0] != '-' || argv[acpi_gbl_optind][1] == '\0') { return (ACPI_OPT_END); - } else if (ACPI_STRCMP(argv[acpi_gbl_optind], "--") == 0) { + } else if (strcmp(argv[acpi_gbl_optind], "--") == 0) { acpi_gbl_optind++; return (ACPI_OPT_END); } @@ -140,7 +140,7 @@ int acpi_getopt(int argc, char **argv, char *opts) /* Make sure that the option is legal */ if (current_char == ':' || - (opts_ptr = ACPI_STRCHR(opts, current_char)) == NULL) { + (opts_ptr = strchr(opts, current_char)) == NULL) { ACPI_OPTION_ERROR("Illegal option: -", current_char); if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index 3aff9a2c7088..dd5008b0617a 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -222,7 +222,7 @@ acpi_os_get_table_by_address(acpi_physical_address address, goto exit; } - ACPI_MEMCPY(local_table, mapped_table, table_length); + memcpy(local_table, mapped_table, table_length); exit: osl_unmap_table(mapped_table); @@ -531,7 +531,7 @@ static acpi_status osl_load_rsdp(void) gbl_rsdp_address = rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address); - ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); + memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); acpi_os_unmap_memory(rsdp_address, rsdp_size); return (AE_OK); @@ -964,7 +964,7 @@ osl_get_bios_table(char *signature, goto exit; } - ACPI_MEMCPY(local_table, mapped_table, table_length); + memcpy(local_table, mapped_table, table_length); *address = table_address; *table = local_table; diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index c736adf5fb55..61d0de804b70 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c @@ -329,7 +329,7 @@ int ap_dump_table_by_name(char *signature) acpi_status status; int table_status; - if (ACPI_STRLEN(signature) != ACPI_NAME_SIZE) { + if (strlen(signature) != ACPI_NAME_SIZE) { acpi_log_error ("Invalid table signature [%s]: must be exactly 4 characters\n", signature); @@ -338,15 +338,15 @@ int ap_dump_table_by_name(char *signature) /* Table signatures are expected to be uppercase */ - ACPI_STRCPY(local_signature, signature); + strcpy(local_signature, signature); acpi_ut_strupr(local_signature); /* To be friendly, handle tables whose signatures do not match the name */ if (ACPI_COMPARE_NAME(local_signature, "FADT")) { - ACPI_STRCPY(local_signature, ACPI_SIG_FADT); + strcpy(local_signature, ACPI_SIG_FADT); } else if (ACPI_COMPARE_NAME(local_signature, "MADT")) { - ACPI_STRCPY(local_signature, ACPI_SIG_MADT); + strcpy(local_signature, ACPI_SIG_MADT); } /* Dump all instances of this signature (to handle multiple SSDTs) */ diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c index 8f2fe168228e..a37f9702b2a9 100644 --- a/tools/power/acpi/tools/acpidump/apfiles.c +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -136,10 +136,10 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) } else { ACPI_MOVE_NAME(filename, table->signature); } - filename[0] = (char)ACPI_TOLOWER(filename[0]); - filename[1] = (char)ACPI_TOLOWER(filename[1]); - filename[2] = (char)ACPI_TOLOWER(filename[2]); - filename[3] = (char)ACPI_TOLOWER(filename[3]); + filename[0] = (char)tolower((int)filename[0]); + filename[1] = (char)tolower((int)filename[1]); + filename[2] = (char)tolower((int)filename[2]); + filename[3] = (char)tolower((int)filename[3]); filename[ACPI_NAME_SIZE] = 0; /* Handle multiple SSDts - create different filenames for each */ @@ -147,10 +147,10 @@ int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) if (instance > 0) { acpi_ut_snprintf(instance_str, sizeof(instance_str), "%u", instance); - ACPI_STRCAT(filename, instance_str); + strcat(filename, instance_str); } - ACPI_STRCAT(filename, ACPI_TABLE_FILE_SUFFIX); + strcat(filename, ACPI_TABLE_FILE_SUFFIX); if (gbl_verbose_mode) { acpi_log_error -- cgit v1.2.3 From 9005694e4043be76299916356723d5dc9c772ab0 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:45:25 +0800 Subject: ACPICA: Update definitions for the TCPA and TPM2 ACPI tables ACPICA commit 33140b4498666337dd33a00cf3c4797a53981a7b Changes for a new version of the 3rd party spec for these tables, the "TCG ACPI Specification", December 14, 2014. Also, moved the definition of TPM2 to actbl2.h, next to TCPA, since both should be together. Update the table compiler/disassembler code for the tables. However, the "Server" TCPA table is not supported at this time. Link: https://github.com/acpica/acpica/commit/33140b44 Reported-by: Jarkko Sakkinen Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++----- include/acpi/actbl3.h | 34 ++------------------ 2 files changed, 81 insertions(+), 39 deletions(-) (limited to 'include') diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 370d69d871a0..2a9dcc15d292 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -51,8 +51,8 @@ * These tables are not consumed directly by the ACPICA subsystem, but are * included here to support device drivers and the AML disassembler. * - * The tables in this file are defined by third-party specifications, and are - * not defined directly by the ACPI specification itself. + * Generally, the tables in this file are defined by third-party specifications, + * and are not defined directly by the ACPI specification itself. * ******************************************************************************/ @@ -80,6 +80,7 @@ #define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */ #define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */ #define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ +#define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ #define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */ #define ACPI_SIG_VRTC "VRTC" /* Virtual Real Time Clock Table */ #define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */ @@ -1179,18 +1180,89 @@ enum acpi_spmi_interface_types { /******************************************************************************* * * TCPA - Trusted Computing Platform Alliance table - * Version 1 + * Version 2 + * + * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", + * December 19, 2014 * - * Conforms to "TCG PC Specific Implementation Specification", - * Version 1.1, August 18, 2003 + * NOTE: There are two versions of the table with the same signature -- + * the client version and the server version. * ******************************************************************************/ -struct acpi_table_tcpa { +struct acpi_table_tcpa_client { + struct acpi_table_header header; /* Common ACPI table header */ + u16 platform_class; + u32 minimum_log_length; /* Minimum length for the event log area */ + u64 log_address; /* Address of the event log area */ +}; + +struct acpi_table_tcpa_server { struct acpi_table_header header; /* Common ACPI table header */ + u16 platform_class; u16 reserved; - u32 max_log_length; /* Maximum length for the event log area */ + u64 minimum_log_length; /* Minimum length for the event log area */ u64 log_address; /* Address of the event log area */ + u16 spec_revision; + u8 device_flags; + u8 interrupt_flags; + u8 gpe_number; + u8 reserved2[3]; + u32 global_interrupt; + struct acpi_generic_address address; + u32 reserved3; + struct acpi_generic_address config_address; + u8 group; + u8 bus; /* PCI Bus/Segment/Function numbers */ + u8 device; + u8 function; +}; + +/* Values for device_flags above */ + +#define ACPI_TCPA_PCI_DEVICE (1) +#define ACPI_TCPA_BUS_PNP (1<<1) +#define ACPI_TCPA_ADDRESS_VALID (1<<2) + +/* Values for interrupt_flags above */ + +#define ACPI_TCPA_INTERRUPT_MODE (1) +#define ACPI_TCPA_INTERRUPT_POLARITY (1<<1) +#define ACPI_TCPA_SCI_VIA_GPE (1<<2) +#define ACPI_TCPA_GLOBAL_INTERRUPT (1<<3) + +/******************************************************************************* + * + * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table + * Version 4 + * + * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", + * December 19, 2014 + * + ******************************************************************************/ + +struct acpi_table_tpm2 { + struct acpi_table_header header; /* Common ACPI table header */ + u16 platform_class; + u16 reserved; + u64 control_address; + u32 start_method; + + /* Platform-specific data follows */ +}; + +/* Control area structure (not part of table, pointed to by control_address) */ + +struct acpi_tpm2_control { + u32 reserved; + u32 error; + u32 cancel; + u32 start; + u64 interrupt_control; + u32 command_size; + u64 command_address; + u32 response_size; + u64 response_address; }; /******************************************************************************* diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h index 4018986d2a2e..1df891660f43 100644 --- a/include/acpi/actbl3.h +++ b/include/acpi/actbl3.h @@ -51,7 +51,8 @@ * These tables are not consumed directly by the ACPICA subsystem, but are * included here to support device drivers and the AML disassembler. * - * The tables in this file are fully defined within the ACPI specification. + * In general, the tables in this file are fully defined within the ACPI + * specification. * ******************************************************************************/ @@ -69,7 +70,6 @@ #define ACPI_SIG_PMTT "PMTT" /* Platform Memory Topology Table */ #define ACPI_SIG_RASF "RASF" /* RAS Feature table */ #define ACPI_SIG_STAO "STAO" /* Status Override table */ -#define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ #define ACPI_SIG_WPBT "WPBT" /* Windows Platform Binary Table */ #define ACPI_SIG_XENV "XENV" /* Xen Environment table */ @@ -720,36 +720,6 @@ struct acpi_table_stao { u8 ignore_uart; }; -/******************************************************************************* - * - * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table - * Version 3 - * - * Conforms to "TPM 2.0 Hardware Interface Table (TPM2)" 29 November 2011 - * - ******************************************************************************/ - -struct acpi_table_tpm2 { - struct acpi_table_header header; /* Common ACPI table header */ - u32 flags; - u64 control_address; - u32 start_method; -}; - -/* Control area structure (not part of table, pointed to by control_address) */ - -struct acpi_tpm2_control { - u32 reserved; - u32 error; - u32 cancel; - u32 start; - u64 interrupt_control; - u32 command_size; - u64 command_address; - u32 response_size; - u64 response_address; -}; - /******************************************************************************* * * WPBT - Windows Platform Environment Table (ACPI 6.0) -- cgit v1.2.3 From 413d4a6defe0467cd22d97bfc5c274f8e3220124 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:45:32 +0800 Subject: ACPICA: Update TPM2 ACPI table ACPICA commit 254bf77e7ca01cb27e026fa5737f7df8dae03f2c - Add constans for the start_method. - Remove the control structure, not part of ACPI, not defined in the current TCG spec. Link: https://github.com/acpica/acpica/commit/254bf77e Reported-by: Jarkko Sakkinen Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 2a9dcc15d292..a948fc586b9b 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1251,19 +1251,13 @@ struct acpi_table_tpm2 { /* Platform-specific data follows */ }; -/* Control area structure (not part of table, pointed to by control_address) */ +/* Values for start_method above */ -struct acpi_tpm2_control { - u32 reserved; - u32 error; - u32 cancel; - u32 start; - u64 interrupt_control; - u32 command_size; - u64 command_address; - u32 response_size; - u64 response_address; -}; +#define ACPI_TPM2_NOT_ALLOWED 0 +#define ACPI_TPM2_START_METHOD 2 +#define ACPI_TPM2_MEMORY_MAPPED 6 +#define ACPI_TPM2_COMMAND_BUFFER 7 +#define ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD 8 /******************************************************************************* * -- cgit v1.2.3 From ce55d01e9b4daee5040777d023d52e6b42d3ad8f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Wed, 1 Jul 2015 14:45:45 +0800 Subject: ACPICA: Update version to 20150619 ACPICA commit 2fcf4f4c95e6a4875f39a929f8f92ef50cc53bb5 ACPICA commit d7a940bb308d001b5d2b196174fee36c7daa61d6 Version 20150619. Link: https://github.com/acpica/acpica/commit/2fcf4f4c Link: https://github.com/acpica/acpica/commit/d7a940bb Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index f6d807170346..e8ec18a4a634 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20150515 +#define ACPI_CA_VERSION 0x20150619 #include #include -- cgit v1.2.3 From bd7ade3cd9b0850264306f5c2b79024a417b6396 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Thu, 2 Jul 2015 01:32:44 -0400 Subject: bufferhead: Add _gfp version for sb_getblk() sb_getblk() is used during ext4 (and possibly other FSes) writeback paths. Sometimes such path require allocating memory and guaranteeing that such allocation won't block. Currently, however, there is no way to provide user flags for sb_getblk which could lead to deadlocks. This patch implements a sb_getblk_gfp with the only difference it can accept user-provided GFP flags. Signed-off-by: Nikolay Borisov Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org --- include/linux/buffer_head.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 73b45225a7ca..e6797ded700e 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -317,6 +317,13 @@ sb_getblk(struct super_block *sb, sector_t block) return __getblk_gfp(sb->s_bdev, block, sb->s_blocksize, __GFP_MOVABLE); } + +static inline struct buffer_head * +sb_getblk_gfp(struct super_block *sb, sector_t block, gfp_t gfp) +{ + return __getblk_gfp(sb->s_bdev, block, sb->s_blocksize, gfp); +} + static inline struct buffer_head * sb_find_get_block(struct super_block *sb, sector_t block) { -- cgit v1.2.3 From ec110bc7cc48d7806c9b65094e6afb19452d458f Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 7 May 2015 06:45:21 -0400 Subject: NTB: Move files in preparation for NTB abstraction This patch only moves files to their new locations, before applying the next two patches adding the NTB Abstraction layer. Splitting this patch from the next is intended make distinct which code is changed only due to moving the files, versus which are substantial code changes in adding the NTB Abstraction layer. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/net/Kconfig | 4 +- drivers/net/ntb_netdev.c | 6 +- drivers/ntb/Makefile | 4 +- drivers/ntb/hw/intel/ntb_hw_intel.c | 1894 ++++++++++++++++++++++++++++++++++ drivers/ntb/hw/intel/ntb_hw_intel.h | 385 +++++++ drivers/ntb/ntb_hw.c | 1895 ----------------------------------- drivers/ntb/ntb_hw.h | 256 ----- drivers/ntb/ntb_regs.h | 177 ---- drivers/ntb/ntb_transport.c | 14 +- include/linux/ntb.h | 88 -- include/linux/ntb_transport.h | 88 ++ 11 files changed, 2381 insertions(+), 2430 deletions(-) create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.c create mode 100644 drivers/ntb/hw/intel/ntb_hw_intel.h delete mode 100644 drivers/ntb/ntb_hw.c delete mode 100644 drivers/ntb/ntb_hw.h delete mode 100644 drivers/ntb/ntb_regs.h delete mode 100644 include/linux/ntb.h create mode 100644 include/linux/ntb_transport.h (limited to 'include') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df51d6025a90..bda3cde62bb3 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -203,8 +203,8 @@ config NET_POLL_CONTROLLER def_bool NETPOLL config NTB_NETDEV - tristate "Virtual Ethernet over NTB" - depends on NTB + tristate "Virtual Ethernet over NTB Transport" + depends on NTB_TRANSPORT config RIONET tristate "RapidIO Ethernet over messaging driver support" diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 5a7e6397440a..6d3bfa62f5ec 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -49,7 +49,7 @@ #include #include #include -#include +#include #define NTB_NETDEV_VER "0.7" @@ -410,13 +410,13 @@ static int __init ntb_netdev_init_module(void) rc = ntb_register_client_dev(KBUILD_MODNAME); if (rc) return rc; - return ntb_register_client(&ntb_netdev_client); + return ntb_transport_register_client(&ntb_netdev_client); } module_init(ntb_netdev_init_module); static void __exit ntb_netdev_exit_module(void) { - ntb_unregister_client(&ntb_netdev_client); + ntb_transport_unregister_client(&ntb_netdev_client); ntb_unregister_client_dev(KBUILD_MODNAME); } module_exit(ntb_netdev_exit_module); diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index 15cb59fd354e..545b10a131af 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,3 +1,3 @@ -obj-$(CONFIG_NTB) += ntb.o +obj-$(CONFIG_NTB) += ntb_hw_intel.o -ntb-objs := ntb_hw.o ntb_transport.o +ntb_hw_intel-objs := hw/intel/ntb_hw_intel.o ntb_transport.o diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c new file mode 100644 index 000000000000..044534a995f1 --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -0,0 +1,1894 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Intel PCIe NTB Linux driver + * + * Contact Information: + * Jon Mason + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ntb_hw_intel.h" + +#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver" +#define NTB_VER "1.0" + +MODULE_DESCRIPTION(NTB_NAME); +MODULE_VERSION(NTB_VER); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Intel Corporation"); + +enum { + NTB_CONN_TRANSPARENT = 0, + NTB_CONN_B2B, + NTB_CONN_RP, +}; + +enum { + NTB_DEV_USD = 0, + NTB_DEV_DSD, +}; + +enum { + SNB_HW = 0, + BWD_HW, +}; + +static struct dentry *debugfs_dir; + +#define BWD_LINK_RECOVERY_TIME 500 + +/* Translate memory window 0,1,2 to BAR 2,4,5 */ +#define MW_TO_BAR(mw) (mw == 0 ? 2 : (mw == 1 ? 4 : 5)) + +static const struct pci_device_id ntb_pci_tbl[] = { + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, ntb_pci_tbl); + +static int is_ntb_xeon(struct ntb_device *ndev) +{ + switch (ndev->pdev->device) { + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + return 1; + default: + return 0; + } + + return 0; +} + +static int is_ntb_atom(struct ntb_device *ndev) +{ + switch (ndev->pdev->device) { + case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: + return 1; + default: + return 0; + } + + return 0; +} + +static void ntb_set_errata_flags(struct ntb_device *ndev) +{ + switch (ndev->pdev->device) { + /* + * this workaround applies to all platform up to IvyBridge + * Haswell has splitbar support and use a different workaround + */ + case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: + case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: + case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: + case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: + case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: + case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: + case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + ndev->wa_flags |= WA_SNB_ERR; + break; + } +} + +/** + * ntb_register_event_callback() - register event callback + * @ndev: pointer to ntb_device instance + * @func: callback function to register + * + * This function registers a callback for any HW driver events such as link + * up/down, power management notices and etc. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_register_event_callback(struct ntb_device *ndev, + void (*func)(void *handle, + enum ntb_hw_event event)) +{ + if (ndev->event_cb) + return -EINVAL; + + ndev->event_cb = func; + + return 0; +} + +/** + * ntb_unregister_event_callback() - unregisters the event callback + * @ndev: pointer to ntb_device instance + * + * This function unregisters the existing callback from transport + */ +void ntb_unregister_event_callback(struct ntb_device *ndev) +{ + ndev->event_cb = NULL; +} + +static void ntb_irq_work(unsigned long data) +{ + struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; + int rc; + + rc = db_cb->callback(db_cb->data, db_cb->db_num); + if (rc) + tasklet_schedule(&db_cb->irq_work); + else { + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + mask = readw(ndev->reg_ofs.ldb_mask); + clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + } +} + +/** + * ntb_register_db_callback() - register a callback for doorbell interrupt + * @ndev: pointer to ntb_device instance + * @idx: doorbell index to register callback, zero based + * @data: pointer to be returned to caller with every callback + * @func: callback function to register + * + * This function registers a callback function for the doorbell interrupt + * on the primary side. The function will unmask the doorbell as well to + * allow interrupt. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, + void *data, int (*func)(void *data, int db_num)) +{ + unsigned long mask; + + if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) { + dev_warn(&ndev->pdev->dev, "Invalid Index.\n"); + return -EINVAL; + } + + ndev->db_cb[idx].callback = func; + ndev->db_cb[idx].data = data; + ndev->db_cb[idx].ndev = ndev; + + tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, + (unsigned long) &ndev->db_cb[idx]); + + /* unmask interrupt */ + mask = readw(ndev->reg_ofs.ldb_mask); + clear_bit(idx * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + return 0; +} + +/** + * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt + * @ndev: pointer to ntb_device instance + * @idx: doorbell index to register callback, zero based + * + * This function unregisters a callback function for the doorbell interrupt + * on the primary side. The function will also mask the said doorbell. + */ +void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) +{ + unsigned long mask; + + if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback) + return; + + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(idx * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_disable(&ndev->db_cb[idx].irq_work); + + ndev->db_cb[idx].callback = NULL; +} + +/** + * ntb_find_transport() - find the transport pointer + * @transport: pointer to pci device + * + * Given the pci device pointer, return the transport pointer passed in when + * the transport attached when it was inited. + * + * RETURNS: pointer to transport. + */ +void *ntb_find_transport(struct pci_dev *pdev) +{ + struct ntb_device *ndev = pci_get_drvdata(pdev); + return ndev->ntb_transport; +} + +/** + * ntb_register_transport() - Register NTB transport with NTB HW driver + * @transport: transport identifier + * + * This function allows a transport to reserve the hardware driver for + * NTB usage. + * + * RETURNS: pointer to ntb_device, NULL on error. + */ +struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport) +{ + struct ntb_device *ndev = pci_get_drvdata(pdev); + + if (ndev->ntb_transport) + return NULL; + + ndev->ntb_transport = transport; + return ndev; +} + +/** + * ntb_unregister_transport() - Unregister the transport with the NTB HW driver + * @ndev - ntb_device of the transport to be freed + * + * This function unregisters the transport from the HW driver and performs any + * necessary cleanups. + */ +void ntb_unregister_transport(struct ntb_device *ndev) +{ + int i; + + if (!ndev->ntb_transport) + return; + + for (i = 0; i < ndev->max_cbs; i++) + ntb_unregister_db_callback(ndev, i); + + ntb_unregister_event_callback(ndev); + ndev->ntb_transport = NULL; +} + +/** + * ntb_write_local_spad() - write to the secondary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to the scratchpad register, 0 based + * @val: the data value to put into the register + * + * This function allows writing of a 32bit value to the indexed scratchpad + * register. This writes over the data mirrored to the local scratchpad register + * by the remote system. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n", + val, idx); + writel(val, ndev->reg_ofs.spad_read + idx * 4); + + return 0; +} + +/** + * ntb_read_local_spad() - read from the primary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to scratchpad register, 0 based + * @val: pointer to 32bit integer for storing the register value + * + * This function allows reading of the 32bit scratchpad register on + * the primary (internal) side. This allows the local system to read data + * written and mirrored to the scratchpad register by the remote system. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + *val = readl(ndev->reg_ofs.spad_write + idx * 4); + dev_dbg(&ndev->pdev->dev, + "Reading %x from local scratch pad index %d\n", *val, idx); + + return 0; +} + +/** + * ntb_write_remote_spad() - write to the secondary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to the scratchpad register, 0 based + * @val: the data value to put into the register + * + * This function allows writing of a 32bit value to the indexed scratchpad + * register. The register resides on the secondary (external) side. This allows + * the local system to write data to be mirrored to the remote systems + * scratchpad register. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n", + val, idx); + writel(val, ndev->reg_ofs.spad_write + idx * 4); + + return 0; +} + +/** + * ntb_read_remote_spad() - read from the primary scratchpad register + * @ndev: pointer to ntb_device instance + * @idx: index to scratchpad register, 0 based + * @val: pointer to 32bit integer for storing the register value + * + * This function allows reading of the 32bit scratchpad register on + * the primary (internal) side. This alloows the local system to read the data + * it wrote to be mirrored on the remote system. + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +{ + if (idx >= ndev->limits.max_spads) + return -EINVAL; + + *val = readl(ndev->reg_ofs.spad_read + idx * 4); + dev_dbg(&ndev->pdev->dev, + "Reading %x from remote scratch pad index %d\n", *val, idx); + + return 0; +} + +/** + * ntb_get_mw_base() - get addr for the NTB memory window + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * + * This function provides the base address of the memory window specified. + * + * RETURNS: address, or NULL on error. + */ +resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw) +{ + if (mw >= ntb_max_mw(ndev)) + return 0; + + return pci_resource_start(ndev->pdev, MW_TO_BAR(mw)); +} + +/** + * ntb_get_mw_vbase() - get virtual addr for the NTB memory window + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * + * This function provides the base virtual address of the memory window + * specified. + * + * RETURNS: pointer to virtual address, or NULL on error. + */ +void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw) +{ + if (mw >= ntb_max_mw(ndev)) + return NULL; + + return ndev->mw[mw].vbase; +} + +/** + * ntb_get_mw_size() - return size of NTB memory window + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * + * This function provides the physical size of the memory window specified + * + * RETURNS: the size of the memory window or zero on error + */ +u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw) +{ + if (mw >= ntb_max_mw(ndev)) + return 0; + + return ndev->mw[mw].bar_sz; +} + +/** + * ntb_set_mw_addr - set the memory window address + * @ndev: pointer to ntb_device instance + * @mw: memory window number + * @addr: base address for data + * + * This function sets the base physical address of the memory window. This + * memory address is where data from the remote system will be transfered into + * or out of depending on how the transport is configured. + */ +void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr) +{ + if (mw >= ntb_max_mw(ndev)) + return; + + dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr, + MW_TO_BAR(mw)); + + ndev->mw[mw].phys_addr = addr; + + switch (MW_TO_BAR(mw)) { + case NTB_BAR_23: + writeq(addr, ndev->reg_ofs.bar2_xlat); + break; + case NTB_BAR_4: + if (ndev->split_bar) + writel(addr, ndev->reg_ofs.bar4_xlat); + else + writeq(addr, ndev->reg_ofs.bar4_xlat); + break; + case NTB_BAR_5: + writel(addr, ndev->reg_ofs.bar5_xlat); + break; + } +} + +/** + * ntb_ring_doorbell() - Set the doorbell on the secondary/external side + * @ndev: pointer to ntb_device instance + * @db: doorbell to ring + * + * This function allows triggering of a doorbell on the secondary/external + * side that will initiate an interrupt on the remote host + * + * RETURNS: An appropriate -ERRNO error value on error, or zero for success. + */ +void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db) +{ + dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db); + + if (ndev->hw_type == BWD_HW) + writeq((u64) 1 << db, ndev->reg_ofs.rdb); + else + writew(((1 << ndev->bits_per_vector) - 1) << + (db * ndev->bits_per_vector), ndev->reg_ofs.rdb); +} + +static void bwd_recover_link(struct ntb_device *ndev) +{ + u32 status; + + /* Driver resets the NTB ModPhy lanes - magic! */ + writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6); + writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4); + writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4); + writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6); + + /* Driver waits 100ms to allow the NTB ModPhy to settle */ + msleep(100); + + /* Clear AER Errors, write to clear */ + status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET); + dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status); + status &= PCI_ERR_COR_REP_ROLL; + writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET); + + /* Clear unexpected electrical idle event in LTSSM, write to clear */ + status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); + dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status); + status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; + writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); + + /* Clear DeSkew Buffer error, write to clear */ + status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET); + dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status); + status |= BWD_DESKEWSTS_DBERR; + writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET); + + status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status); + status &= BWD_IBIST_ERR_OFLOW; + writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + + /* Releases the NTB state machine to allow the link to retrain */ + status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); + dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status); + status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; + writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); +} + +static void ntb_link_event(struct ntb_device *ndev, int link_state) +{ + unsigned int event; + + if (ndev->link_status == link_state) + return; + + if (link_state == NTB_LINK_UP) { + u16 status; + + dev_info(&ndev->pdev->dev, "Link Up\n"); + ndev->link_status = NTB_LINK_UP; + event = NTB_EVENT_HW_LINK_UP; + + if (is_ntb_atom(ndev) || + ndev->conn_type == NTB_CONN_TRANSPARENT) + status = readw(ndev->reg_ofs.lnk_stat); + else { + int rc = pci_read_config_word(ndev->pdev, + SNB_LINK_STATUS_OFFSET, + &status); + if (rc) + return; + } + + ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; + ndev->link_speed = (status & NTB_LINK_SPEED_MASK); + dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n", + ndev->link_width, ndev->link_speed); + } else { + dev_info(&ndev->pdev->dev, "Link Down\n"); + ndev->link_status = NTB_LINK_DOWN; + event = NTB_EVENT_HW_LINK_DOWN; + /* Don't modify link width/speed, we need it in link recovery */ + } + + /* notify the upper layer if we have an event change */ + if (ndev->event_cb) + ndev->event_cb(ndev->ntb_transport, event); +} + +static int ntb_link_status(struct ntb_device *ndev) +{ + int link_state; + + if (is_ntb_atom(ndev)) { + u32 ntb_cntl; + + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + if (ntb_cntl & BWD_CNTL_LINK_DOWN) + link_state = NTB_LINK_DOWN; + else + link_state = NTB_LINK_UP; + } else { + u16 status; + int rc; + + rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, + &status); + if (rc) + return rc; + + if (status & NTB_LINK_STATUS_ACTIVE) + link_state = NTB_LINK_UP; + else + link_state = NTB_LINK_DOWN; + } + + ntb_link_event(ndev, link_state); + + return 0; +} + +static void bwd_link_recovery(struct work_struct *work) +{ + struct ntb_device *ndev = container_of(work, struct ntb_device, + lr_timer.work); + u32 status32; + + bwd_recover_link(ndev); + /* There is a potential race between the 2 NTB devices recovering at the + * same time. If the times are the same, the link will not recover and + * the driver will be stuck in this loop forever. Add a random interval + * to the recovery time to prevent this race. + */ + msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME); + + status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); + if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) + goto retry; + + status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + if (status32 & BWD_IBIST_ERR_OFLOW) + goto retry; + + status32 = readl(ndev->reg_ofs.lnk_cntl); + if (!(status32 & BWD_CNTL_LINK_DOWN)) { + unsigned char speed, width; + u16 status16; + + status16 = readw(ndev->reg_ofs.lnk_stat); + width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; + speed = (status16 & NTB_LINK_SPEED_MASK); + if (ndev->link_width != width || ndev->link_speed != speed) + goto retry; + } + + schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); + return; + +retry: + schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT); +} + +/* BWD doesn't have link status interrupt, poll on that platform */ +static void bwd_link_poll(struct work_struct *work) +{ + struct ntb_device *ndev = container_of(work, struct ntb_device, + hb_timer.work); + unsigned long ts = jiffies; + + /* If we haven't gotten an interrupt in a while, check the BWD link + * status bit + */ + if (ts > ndev->last_ts + NTB_HB_TIMEOUT) { + int rc = ntb_link_status(ndev); + if (rc) + dev_err(&ndev->pdev->dev, + "Error determining link status\n"); + + /* Check to see if a link error is the cause of the link down */ + if (ndev->link_status == NTB_LINK_DOWN) { + u32 status32 = readl(ndev->reg_base + + BWD_LTSSMSTATEJMP_OFFSET); + if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) { + schedule_delayed_work(&ndev->lr_timer, 0); + return; + } + } + } + + schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); +} + +static int ntb_xeon_setup(struct ntb_device *ndev) +{ + switch (ndev->conn_type) { + case NTB_CONN_B2B: + ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; + ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; + if (ndev->split_bar) + ndev->reg_ofs.bar5_xlat = + ndev->reg_base + SNB_SBAR5XLAT_OFFSET; + ndev->limits.max_spads = SNB_MAX_B2B_SPADS; + + /* There is a Xeon hardware errata related to writes to + * SDOORBELL or B2BDOORBELL in conjunction with inbound access + * to NTB MMIO Space, which may hang the system. To workaround + * this use the second memory window to access the interrupt and + * scratch pad registers on the remote system. + */ + if (ndev->wa_flags & WA_SNB_ERR) { + if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz) + return -EINVAL; + + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; + ndev->reg_ofs.spad_write = + ndev->mw[ndev->limits.max_mw - 1].vbase + + SNB_SPAD_OFFSET; + ndev->reg_ofs.rdb = + ndev->mw[ndev->limits.max_mw - 1].vbase + + SNB_PDOORBELL_OFFSET; + + /* Set the Limit register to 4k, the minimum size, to + * prevent an illegal access + */ + writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on + * the driver defaults, but write the Limit registers + * first just in case. + */ + + ndev->limits.max_mw = SNB_ERRATA_MAX_MW; + } else { + /* HW Errata on bit 14 of b2bdoorbell register. Writes + * will not be mirrored to the remote system. Shrink + * the number of bits by one, since bit 14 is the last + * bit. + */ + ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; + ndev->reg_ofs.spad_write = ndev->reg_base + + SNB_B2B_SPAD_OFFSET; + ndev->reg_ofs.rdb = ndev->reg_base + + SNB_B2B_DOORBELL_OFFSET; + + /* Disable the Limit register, just incase it is set to + * something silly. A 64bit write should handle it + * regardless of whether it has a split BAR or not. + */ + writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on + * the driver defaults, but write the Limit registers + * first just in case. + */ + if (ndev->split_bar) + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + else + ndev->limits.max_mw = SNB_MAX_MW; + } + + /* The Xeon errata workaround requires setting SBAR Base + * addresses to known values, so that the PBAR XLAT can be + * pointed at SBAR0 of the remote system. + */ + if (ndev->dev_type == NTB_DEV_USD) { + writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + + SNB_PBAR2XLAT_OFFSET); + if (ndev->wa_flags & WA_SNB_ERR) + writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + else { + if (ndev->split_bar) { + writel(SNB_MBAR4_DSD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + writel(SNB_MBAR5_DSD_ADDR, + ndev->reg_base + + SNB_PBAR5XLAT_OFFSET); + } else + writeq(SNB_MBAR4_DSD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + + /* B2B_XLAT_OFFSET is a 64bit register, but can + * only take 32bit writes + */ + writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, + ndev->reg_base + SNB_B2B_XLAT_OFFSETL); + writel(SNB_MBAR01_DSD_ADDR >> 32, + ndev->reg_base + SNB_B2B_XLAT_OFFSETU); + } + + writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + + SNB_SBAR0BASE_OFFSET); + writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + + SNB_SBAR2BASE_OFFSET); + if (ndev->split_bar) { + writel(SNB_MBAR4_USD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + writel(SNB_MBAR5_USD_ADDR, ndev->reg_base + + SNB_SBAR5BASE_OFFSET); + } else + writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + } else { + writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + + SNB_PBAR2XLAT_OFFSET); + if (ndev->wa_flags & WA_SNB_ERR) + writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + else { + if (ndev->split_bar) { + writel(SNB_MBAR4_USD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + writel(SNB_MBAR5_USD_ADDR, + ndev->reg_base + + SNB_PBAR5XLAT_OFFSET); + } else + writeq(SNB_MBAR4_USD_ADDR, + ndev->reg_base + + SNB_PBAR4XLAT_OFFSET); + + /* + * B2B_XLAT_OFFSET is a 64bit register, but can + * only take 32bit writes + */ + writel(SNB_MBAR01_USD_ADDR & 0xffffffff, + ndev->reg_base + SNB_B2B_XLAT_OFFSETL); + writel(SNB_MBAR01_USD_ADDR >> 32, + ndev->reg_base + SNB_B2B_XLAT_OFFSETU); + } + writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + + SNB_SBAR0BASE_OFFSET); + writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + + SNB_SBAR2BASE_OFFSET); + if (ndev->split_bar) { + writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base + + SNB_SBAR5BASE_OFFSET); + } else + writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base + + SNB_SBAR4BASE_OFFSET); + + } + break; + case NTB_CONN_RP: + if (ndev->wa_flags & WA_SNB_ERR) { + dev_err(&ndev->pdev->dev, + "NTB-RP disabled due to hardware errata.\n"); + return -EINVAL; + } + + /* Scratch pads need to have exclusive access from the primary + * or secondary side. Halve the num spads so that each side can + * have an equal amount. + */ + ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; + /* Note: The SDOORBELL is the cause of the errata. You REALLY + * don't want to touch it. + */ + ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; + ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; + /* Offset the start of the spads to correspond to whether it is + * primary or secondary + */ + ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + + ndev->limits.max_spads * 4; + ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; + if (ndev->split_bar) { + ndev->reg_ofs.bar5_xlat = + ndev->reg_base + SNB_SBAR5XLAT_OFFSET; + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + } else + ndev->limits.max_mw = SNB_MAX_MW; + break; + case NTB_CONN_TRANSPARENT: + if (ndev->wa_flags & WA_SNB_ERR) { + dev_err(&ndev->pdev->dev, + "NTB-TRANSPARENT disabled due to hardware errata.\n"); + return -EINVAL; + } + + /* Scratch pads need to have exclusive access from the primary + * or secondary side. Halve the num spads so that each side can + * have an equal amount. + */ + ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; + ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; + ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; + /* Offset the start of the spads to correspond to whether it is + * primary or secondary + */ + ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + + ndev->limits.max_spads * 4; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; + + if (ndev->split_bar) { + ndev->reg_ofs.bar5_xlat = + ndev->reg_base + SNB_PBAR5XLAT_OFFSET; + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + } else + ndev->limits.max_mw = SNB_MAX_MW; + break; + default: + /* + * we should never hit this. the detect function should've + * take cared of everything. + */ + return -EINVAL; + } + + ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; + ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; + ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; + + ndev->limits.msix_cnt = SNB_MSIX_CNT; + ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; + + return 0; +} + +static int ntb_bwd_setup(struct ntb_device *ndev) +{ + int rc; + u32 val; + + ndev->hw_type = BWD_HW; + + rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val); + if (rc) + return rc; + + switch ((val & BWD_PPD_CONN_TYPE) >> 8) { + case NTB_CONN_B2B: + ndev->conn_type = NTB_CONN_B2B; + break; + case NTB_CONN_RP: + default: + dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + return -EINVAL; + } + + if (val & BWD_PPD_DEV_TYPE) + ndev->dev_type = NTB_DEV_DSD; + else + ndev->dev_type = NTB_DEV_USD; + + /* Initiate PCI-E link training */ + rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET, + val | BWD_PPD_INIT_LINK); + if (rc) + return rc; + + ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET; + ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET; + ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET; + ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET; + ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET; + ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET; + ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET; + ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET; + ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET; + ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET; + ndev->limits.max_mw = BWD_MAX_MW; + ndev->limits.max_spads = BWD_MAX_SPADS; + ndev->limits.max_db_bits = BWD_MAX_DB_BITS; + ndev->limits.msix_cnt = BWD_MSIX_CNT; + ndev->bits_per_vector = BWD_DB_BITS_PER_VEC; + + /* Since bwd doesn't have a link interrupt, setup a poll timer */ + INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll); + INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery); + schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); + + return 0; +} + +static int ntb_device_setup(struct ntb_device *ndev) +{ + int rc; + + if (is_ntb_xeon(ndev)) + rc = ntb_xeon_setup(ndev); + else if (is_ntb_atom(ndev)) + rc = ntb_bwd_setup(ndev); + else + rc = -ENODEV; + + if (rc) + return rc; + + if (ndev->conn_type == NTB_CONN_B2B) + /* Enable Bus Master and Memory Space on the secondary side */ + writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->reg_ofs.spci_cmd); + + return 0; +} + +static void ntb_device_free(struct ntb_device *ndev) +{ + if (is_ntb_atom(ndev)) { + cancel_delayed_work_sync(&ndev->hb_timer); + cancel_delayed_work_sync(&ndev->lr_timer); + } +} + +static irqreturn_t bwd_callback_msix_irq(int irq, void *data) +{ + struct ntb_db_cb *db_cb = data; + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, + db_cb->db_num); + + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); + + /* No need to check for the specific HB irq, any interrupt means + * we're connected. + */ + ndev->last_ts = jiffies; + + writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb); + + return IRQ_HANDLED; +} + +static irqreturn_t xeon_callback_msix_irq(int irq, void *data) +{ + struct ntb_db_cb *db_cb = data; + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, + db_cb->db_num); + + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); + + /* On Sandybridge, there are 16 bits in the interrupt register + * but only 4 vectors. So, 5 bits are assigned to the first 3 + * vectors, with the 4th having a single bit for link + * interrupts. + */ + writew(((1 << ndev->bits_per_vector) - 1) << + (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb); + + return IRQ_HANDLED; +} + +/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */ +static irqreturn_t xeon_event_msix_irq(int irq, void *dev) +{ + struct ntb_device *ndev = dev; + int rc; + + dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq); + + rc = ntb_link_status(ndev); + if (rc) + dev_err(&ndev->pdev->dev, "Error determining link status\n"); + + /* bit 15 is always the link bit */ + writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); + + return IRQ_HANDLED; +} + +static irqreturn_t ntb_interrupt(int irq, void *dev) +{ + struct ntb_device *ndev = dev; + unsigned int i = 0; + + if (is_ntb_atom(ndev)) { + u64 ldb = readq(ndev->reg_ofs.ldb); + + dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb); + + while (ldb) { + i = __ffs(ldb); + ldb &= ldb - 1; + bwd_callback_msix_irq(irq, &ndev->db_cb[i]); + } + } else { + u16 ldb = readw(ndev->reg_ofs.ldb); + + dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb); + + if (ldb & SNB_DB_HW_LINK) { + xeon_event_msix_irq(irq, dev); + ldb &= ~SNB_DB_HW_LINK; + } + + while (ldb) { + i = __ffs(ldb); + ldb &= ldb - 1; + xeon_callback_msix_irq(irq, &ndev->db_cb[i]); + } + } + + return IRQ_HANDLED; +} + +static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries) +{ + struct pci_dev *pdev = ndev->pdev; + struct msix_entry *msix; + int rc, i; + + if (msix_entries < ndev->limits.msix_cnt) + return -ENOSPC; + + rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries); + if (rc < 0) + return rc; + + for (i = 0; i < msix_entries; i++) { + msix = &ndev->msix_entries[i]; + WARN_ON(!msix->vector); + + if (i == msix_entries - 1) { + rc = request_irq(msix->vector, + xeon_event_msix_irq, 0, + "ntb-event-msix", ndev); + if (rc) + goto err; + } else { + rc = request_irq(msix->vector, + xeon_callback_msix_irq, 0, + "ntb-callback-msix", + &ndev->db_cb[i]); + if (rc) + goto err; + } + } + + ndev->num_msix = msix_entries; + ndev->max_cbs = msix_entries - 1; + + return 0; + +err: + while (--i >= 0) { + /* Code never reaches here for entry nr 'ndev->num_msix - 1' */ + msix = &ndev->msix_entries[i]; + free_irq(msix->vector, &ndev->db_cb[i]); + } + + pci_disable_msix(pdev); + ndev->num_msix = 0; + + return rc; +} + +static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries) +{ + struct pci_dev *pdev = ndev->pdev; + struct msix_entry *msix; + int rc, i; + + msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries, + 1, msix_entries); + if (msix_entries < 0) + return msix_entries; + + for (i = 0; i < msix_entries; i++) { + msix = &ndev->msix_entries[i]; + WARN_ON(!msix->vector); + + rc = request_irq(msix->vector, bwd_callback_msix_irq, 0, + "ntb-callback-msix", &ndev->db_cb[i]); + if (rc) + goto err; + } + + ndev->num_msix = msix_entries; + ndev->max_cbs = msix_entries; + + return 0; + +err: + while (--i >= 0) + free_irq(msix->vector, &ndev->db_cb[i]); + + pci_disable_msix(pdev); + ndev->num_msix = 0; + + return rc; +} + +static int ntb_setup_msix(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + int msix_entries; + int rc, i; + + msix_entries = pci_msix_vec_count(pdev); + if (msix_entries < 0) { + rc = msix_entries; + goto err; + } else if (msix_entries > ndev->limits.msix_cnt) { + rc = -EINVAL; + goto err; + } + + ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries, + GFP_KERNEL); + if (!ndev->msix_entries) { + rc = -ENOMEM; + goto err; + } + + for (i = 0; i < msix_entries; i++) + ndev->msix_entries[i].entry = i; + + if (is_ntb_atom(ndev)) + rc = ntb_setup_bwd_msix(ndev, msix_entries); + else + rc = ntb_setup_snb_msix(ndev, msix_entries); + if (rc) + goto err1; + + return 0; + +err1: + kfree(ndev->msix_entries); +err: + dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n"); + return rc; +} + +static int ntb_setup_msi(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + int rc; + + rc = pci_enable_msi(pdev); + if (rc) + return rc; + + rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev); + if (rc) { + pci_disable_msi(pdev); + dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); + return rc; + } + + return 0; +} + +static int ntb_setup_intx(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + int rc; + + /* Verify intx is enabled */ + pci_intx(pdev, 1); + + rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx", + ndev); + if (rc) + return rc; + + return 0; +} + +static int ntb_setup_interrupts(struct ntb_device *ndev) +{ + int rc; + + /* On BWD, disable all interrupts. On SNB, disable all but Link + * Interrupt. The rest will be unmasked as callbacks are registered. + */ + if (is_ntb_atom(ndev)) + writeq(~0, ndev->reg_ofs.ldb_mask); + else { + u16 var = 1 << SNB_LINK_DB; + writew(~var, ndev->reg_ofs.ldb_mask); + } + + rc = ntb_setup_msix(ndev); + if (!rc) + goto done; + + ndev->bits_per_vector = 1; + ndev->max_cbs = ndev->limits.max_db_bits; + + rc = ntb_setup_msi(ndev); + if (!rc) + goto done; + + rc = ntb_setup_intx(ndev); + if (rc) { + dev_err(&ndev->pdev->dev, "no usable interrupts\n"); + return rc; + } + +done: + return 0; +} + +static void ntb_free_interrupts(struct ntb_device *ndev) +{ + struct pci_dev *pdev = ndev->pdev; + + /* mask interrupts */ + if (is_ntb_atom(ndev)) + writeq(~0, ndev->reg_ofs.ldb_mask); + else + writew(~0, ndev->reg_ofs.ldb_mask); + + if (ndev->num_msix) { + struct msix_entry *msix; + u32 i; + + for (i = 0; i < ndev->num_msix; i++) { + msix = &ndev->msix_entries[i]; + if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1) + free_irq(msix->vector, ndev); + else + free_irq(msix->vector, &ndev->db_cb[i]); + } + pci_disable_msix(pdev); + kfree(ndev->msix_entries); + } else { + free_irq(pdev->irq, ndev); + + if (pci_dev_msi_enabled(pdev)) + pci_disable_msi(pdev); + } +} + +static int ntb_create_callbacks(struct ntb_device *ndev) +{ + int i; + + /* Chicken-egg issue. We won't know how many callbacks are necessary + * until we see how many MSI-X vectors we get, but these pointers need + * to be passed into the MSI-X register function. So, we allocate the + * max, knowing that they might not all be used, to work around this. + */ + ndev->db_cb = kcalloc(ndev->limits.max_db_bits, + sizeof(struct ntb_db_cb), + GFP_KERNEL); + if (!ndev->db_cb) + return -ENOMEM; + + for (i = 0; i < ndev->limits.max_db_bits; i++) { + ndev->db_cb[i].db_num = i; + ndev->db_cb[i].ndev = ndev; + } + + return 0; +} + +static void ntb_free_callbacks(struct ntb_device *ndev) +{ + int i; + + for (i = 0; i < ndev->limits.max_db_bits; i++) + ntb_unregister_db_callback(ndev, i); + + kfree(ndev->db_cb); +} + +static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct ntb_device *ndev; + char *buf; + ssize_t ret, offset, out_count; + + out_count = 500; + + buf = kmalloc(out_count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ndev = filp->private_data; + offset = 0; + offset += snprintf(buf + offset, out_count - offset, + "NTB Device Information:\n"); + offset += snprintf(buf + offset, out_count - offset, + "Connection Type - \t\t%s\n", + ndev->conn_type == NTB_CONN_TRANSPARENT ? + "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ? + "Back to back" : "Root Port"); + offset += snprintf(buf + offset, out_count - offset, + "Device Type - \t\t\t%s\n", + ndev->dev_type == NTB_DEV_USD ? + "DSD/USP" : "USD/DSP"); + offset += snprintf(buf + offset, out_count - offset, + "Max Number of Callbacks - \t%u\n", + ntb_max_cbs(ndev)); + offset += snprintf(buf + offset, out_count - offset, + "Link Status - \t\t\t%s\n", + ntb_hw_link_status(ndev) ? "Up" : "Down"); + if (ntb_hw_link_status(ndev)) { + offset += snprintf(buf + offset, out_count - offset, + "Link Speed - \t\t\tPCI-E Gen %u\n", + ndev->link_speed); + offset += snprintf(buf + offset, out_count - offset, + "Link Width - \t\t\tx%u\n", + ndev->link_width); + } + + if (is_ntb_xeon(ndev)) { + u32 status32; + u16 status16; + int rc; + + offset += snprintf(buf + offset, out_count - offset, + "\nNTB Device Statistics:\n"); + offset += snprintf(buf + offset, out_count - offset, + "Upstream Memory Miss - \t%u\n", + readw(ndev->reg_base + + SNB_USMEMMISS_OFFSET)); + + offset += snprintf(buf + offset, out_count - offset, + "\nNTB Hardware Errors:\n"); + + rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET, + &status16); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "DEVSTS - \t%#06x\n", status16); + + rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, + &status16); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "LNKSTS - \t%#06x\n", status16); + + rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET, + &status32); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "UNCERRSTS - \t%#010x\n", status32); + + rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET, + &status32); + if (!rc) + offset += snprintf(buf + offset, out_count - offset, + "CORERRSTS - \t%#010x\n", status32); + } + + if (offset > out_count) + offset = out_count; + + ret = simple_read_from_buffer(ubuf, count, offp, buf, offset); + kfree(buf); + return ret; +} + +static const struct file_operations ntb_debugfs_info = { + .owner = THIS_MODULE, + .open = simple_open, + .read = ntb_debugfs_read, +}; + +static void ntb_setup_debugfs(struct ntb_device *ndev) +{ + if (!debugfs_initialized()) + return; + + if (!debugfs_dir) + debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev), + debugfs_dir); + if (ndev->debugfs_dir) + ndev->debugfs_info = debugfs_create_file("info", S_IRUSR, + ndev->debugfs_dir, + ndev, + &ntb_debugfs_info); +} + +static void ntb_free_debugfs(struct ntb_device *ndev) +{ + debugfs_remove_recursive(ndev->debugfs_dir); + + if (debugfs_dir && simple_empty(debugfs_dir)) { + debugfs_remove_recursive(debugfs_dir); + debugfs_dir = NULL; + } +} + +static void ntb_hw_link_up(struct ntb_device *ndev) +{ + if (ndev->conn_type == NTB_CONN_TRANSPARENT) + ntb_link_event(ndev, NTB_LINK_UP); + else { + u32 ntb_cntl; + + /* Let's bring the NTB link up */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); + ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; + ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; + if (ndev->split_bar) + ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP | + NTB_CNTL_S2P_BAR5_SNOOP; + + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + } +} + +static void ntb_hw_link_down(struct ntb_device *ndev) +{ + u32 ntb_cntl; + + if (ndev->conn_type == NTB_CONN_TRANSPARENT) { + ntb_link_event(ndev, NTB_LINK_DOWN); + return; + } + + /* Bring NTB link down */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); + if (ndev->split_bar) + ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | + NTB_CNTL_S2P_BAR5_SNOOP); + ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); +} + +static void ntb_max_mw_detect(struct ntb_device *ndev) +{ + if (ndev->split_bar) + ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + else + ndev->limits.max_mw = SNB_MAX_MW; +} + +static int ntb_xeon_detect(struct ntb_device *ndev) +{ + int rc, bars_mask; + u32 bars; + u8 ppd; + + ndev->hw_type = SNB_HW; + + rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd); + if (rc) + return -EIO; + + if (ppd & SNB_PPD_DEV_TYPE) + ndev->dev_type = NTB_DEV_USD; + else + ndev->dev_type = NTB_DEV_DSD; + + ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0; + + switch (ppd & SNB_PPD_CONN_TYPE) { + case NTB_CONN_B2B: + dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); + ndev->conn_type = NTB_CONN_B2B; + break; + case NTB_CONN_RP: + dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); + ndev->conn_type = NTB_CONN_RP; + break; + case NTB_CONN_TRANSPARENT: + dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); + ndev->conn_type = NTB_CONN_TRANSPARENT; + /* + * This mode is default to USD/DSP. HW does not report + * properly in transparent mode as it has no knowledge of + * NTB. We will just force correct here. + */ + ndev->dev_type = NTB_DEV_USD; + + /* + * This is a way for transparent BAR to figure out if we + * are doing split BAR or not. There is no way for the hw + * on the transparent side to know and set the PPD. + */ + bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM); + bars = hweight32(bars_mask); + if (bars == (HSX_SPLITBAR_MAX_MW + 1)) + ndev->split_bar = 1; + + break; + default: + dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd); + return -ENODEV; + } + + ntb_max_mw_detect(ndev); + + return 0; +} + +static int ntb_atom_detect(struct ntb_device *ndev) +{ + int rc; + u32 ppd; + + ndev->hw_type = BWD_HW; + ndev->limits.max_mw = BWD_MAX_MW; + + rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd); + if (rc) + return rc; + + switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) { + case NTB_CONN_B2B: + dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); + ndev->conn_type = NTB_CONN_B2B; + break; + case NTB_CONN_RP: + default: + dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + return -EINVAL; + } + + if (ppd & BWD_PPD_DEV_TYPE) + ndev->dev_type = NTB_DEV_DSD; + else + ndev->dev_type = NTB_DEV_USD; + + return 0; +} + +static int ntb_device_detect(struct ntb_device *ndev) +{ + int rc; + + if (is_ntb_xeon(ndev)) + rc = ntb_xeon_detect(ndev); + else if (is_ntb_atom(ndev)) + rc = ntb_atom_detect(ndev); + else + rc = -ENODEV; + + dev_info(&ndev->pdev->dev, "Device Type = %s\n", + ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); + + return 0; +} + +static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct ntb_device *ndev; + int rc, i; + + ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL); + if (!ndev) + return -ENOMEM; + + ndev->pdev = pdev; + + ntb_set_errata_flags(ndev); + + ndev->link_status = NTB_LINK_DOWN; + pci_set_drvdata(pdev, ndev); + ntb_setup_debugfs(ndev); + + rc = pci_enable_device(pdev); + if (rc) + goto err; + + pci_set_master(ndev->pdev); + + rc = ntb_device_detect(ndev); + if (rc) + goto err; + + ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw), + GFP_KERNEL); + if (!ndev->mw) { + rc = -ENOMEM; + goto err1; + } + + if (ndev->split_bar) + rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK, + KBUILD_MODNAME); + else + rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, + KBUILD_MODNAME); + + if (rc) + goto err2; + + ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO); + if (!ndev->reg_base) { + dev_warn(&pdev->dev, "Cannot remap BAR 0\n"); + rc = -EIO; + goto err3; + } + + for (i = 0; i < ndev->limits.max_mw; i++) { + ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i)); + + /* + * with the errata we need to steal last of the memory + * windows for workarounds and they point to MMIO registers. + */ + if ((ndev->wa_flags & WA_SNB_ERR) && + (i == (ndev->limits.max_mw - 1))) { + ndev->mw[i].vbase = + ioremap_nocache(pci_resource_start(pdev, + MW_TO_BAR(i)), + ndev->mw[i].bar_sz); + } else { + ndev->mw[i].vbase = + ioremap_wc(pci_resource_start(pdev, + MW_TO_BAR(i)), + ndev->mw[i].bar_sz); + } + + dev_info(&pdev->dev, "MW %d size %llu\n", i, + (unsigned long long) ndev->mw[i].bar_sz); + if (!ndev->mw[i].vbase) { + dev_warn(&pdev->dev, "Cannot remap BAR %d\n", + MW_TO_BAR(i)); + rc = -EIO; + goto err4; + } + } + + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err4; + + dev_warn(&pdev->dev, "Cannot DMA highmem\n"); + } + + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err4; + + dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); + } + + rc = ntb_device_setup(ndev); + if (rc) + goto err4; + + rc = ntb_create_callbacks(ndev); + if (rc) + goto err5; + + rc = ntb_setup_interrupts(ndev); + if (rc) + goto err6; + + /* The scratchpad registers keep the values between rmmod/insmod, + * blast them now + */ + for (i = 0; i < ndev->limits.max_spads; i++) { + ntb_write_local_spad(ndev, i, 0); + ntb_write_remote_spad(ndev, i, 0); + } + + rc = ntb_transport_init(pdev); + if (rc) + goto err7; + + ntb_hw_link_up(ndev); + + return 0; + +err7: + ntb_free_interrupts(ndev); +err6: + ntb_free_callbacks(ndev); +err5: + ntb_device_free(ndev); +err4: + for (i--; i >= 0; i--) + iounmap(ndev->mw[i].vbase); + iounmap(ndev->reg_base); +err3: + if (ndev->split_bar) + pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); + else + pci_release_selected_regions(pdev, NTB_BAR_MASK); +err2: + kfree(ndev->mw); +err1: + pci_disable_device(pdev); +err: + ntb_free_debugfs(ndev); + kfree(ndev); + + dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME); + return rc; +} + +static void ntb_pci_remove(struct pci_dev *pdev) +{ + struct ntb_device *ndev = pci_get_drvdata(pdev); + int i; + + ntb_hw_link_down(ndev); + + ntb_transport_free(ndev->ntb_transport); + + ntb_free_interrupts(ndev); + ntb_free_callbacks(ndev); + ntb_device_free(ndev); + + /* need to reset max_mw limits so we can unmap properly */ + if (ndev->hw_type == SNB_HW) + ntb_max_mw_detect(ndev); + + for (i = 0; i < ndev->limits.max_mw; i++) + iounmap(ndev->mw[i].vbase); + + kfree(ndev->mw); + iounmap(ndev->reg_base); + if (ndev->split_bar) + pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); + else + pci_release_selected_regions(pdev, NTB_BAR_MASK); + pci_disable_device(pdev); + ntb_free_debugfs(ndev); + kfree(ndev); +} + +static struct pci_driver ntb_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = ntb_pci_tbl, + .probe = ntb_pci_probe, + .remove = ntb_pci_remove, +}; + +module_pci_driver(ntb_pci_driver); diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h new file mode 100644 index 000000000000..935610454f70 --- /dev/null +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -0,0 +1,385 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Intel PCIe NTB Linux driver + * + * Contact Information: + * Jon Mason + */ +#include + +#define NTB_LINK_STATUS_ACTIVE 0x2000 +#define NTB_LINK_SPEED_MASK 0x000f +#define NTB_LINK_WIDTH_MASK 0x03f0 + +#define SNB_MSIX_CNT 4 +#define SNB_MAX_B2B_SPADS 16 +#define SNB_MAX_COMPAT_SPADS 16 +/* Reserve the uppermost bit for link interrupt */ +#define SNB_MAX_DB_BITS 15 +#define SNB_LINK_DB 15 +#define SNB_DB_BITS_PER_VEC 5 +#define HSX_SPLITBAR_MAX_MW 3 +#define SNB_MAX_MW 2 +#define SNB_ERRATA_MAX_MW 1 + +#define SNB_DB_HW_LINK 0x8000 + +#define SNB_UNCERRSTS_OFFSET 0x014C +#define SNB_CORERRSTS_OFFSET 0x0158 +#define SNB_LINK_STATUS_OFFSET 0x01A2 +#define SNB_PCICMD_OFFSET 0x0504 +#define SNB_DEVCTRL_OFFSET 0x0598 +#define SNB_DEVSTS_OFFSET 0x059A +#define SNB_SLINK_STATUS_OFFSET 0x05A2 + +#define SNB_PBAR2LMT_OFFSET 0x0000 +#define SNB_PBAR4LMT_OFFSET 0x0008 +#define SNB_PBAR5LMT_OFFSET 0x000C +#define SNB_PBAR2XLAT_OFFSET 0x0010 +#define SNB_PBAR4XLAT_OFFSET 0x0018 +#define SNB_PBAR5XLAT_OFFSET 0x001C +#define SNB_SBAR2LMT_OFFSET 0x0020 +#define SNB_SBAR4LMT_OFFSET 0x0028 +#define SNB_SBAR5LMT_OFFSET 0x002C +#define SNB_SBAR2XLAT_OFFSET 0x0030 +#define SNB_SBAR4XLAT_OFFSET 0x0038 +#define SNB_SBAR5XLAT_OFFSET 0x003C +#define SNB_SBAR0BASE_OFFSET 0x0040 +#define SNB_SBAR2BASE_OFFSET 0x0048 +#define SNB_SBAR4BASE_OFFSET 0x0050 +#define SNB_SBAR5BASE_OFFSET 0x0054 +#define SNB_NTBCNTL_OFFSET 0x0058 +#define SNB_SBDF_OFFSET 0x005C +#define SNB_PDOORBELL_OFFSET 0x0060 +#define SNB_PDBMSK_OFFSET 0x0062 +#define SNB_SDOORBELL_OFFSET 0x0064 +#define SNB_SDBMSK_OFFSET 0x0066 +#define SNB_USMEMMISS_OFFSET 0x0070 +#define SNB_SPAD_OFFSET 0x0080 +#define SNB_SPADSEMA4_OFFSET 0x00c0 +#define SNB_WCCNTRL_OFFSET 0x00e0 +#define SNB_B2B_SPAD_OFFSET 0x0100 +#define SNB_B2B_DOORBELL_OFFSET 0x0140 +#define SNB_B2B_XLAT_OFFSETL 0x0144 +#define SNB_B2B_XLAT_OFFSETU 0x0148 + +/* + * The addresses are setup so the 32bit BARs can function. Thus + * the addresses are all in 32bit space + */ +#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL +#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL +#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL +#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL +#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL +#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL +#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL +#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL + +#define BWD_MSIX_CNT 34 +#define BWD_MAX_SPADS 16 +#define BWD_MAX_DB_BITS 34 +#define BWD_DB_BITS_PER_VEC 1 +#define BWD_MAX_MW 2 + +#define BWD_PCICMD_OFFSET 0xb004 +#define BWD_MBAR23_OFFSET 0xb018 +#define BWD_MBAR45_OFFSET 0xb020 +#define BWD_DEVCTRL_OFFSET 0xb048 +#define BWD_LINK_STATUS_OFFSET 0xb052 +#define BWD_ERRCORSTS_OFFSET 0xb110 + +#define BWD_SBAR2XLAT_OFFSET 0x0008 +#define BWD_SBAR4XLAT_OFFSET 0x0010 +#define BWD_PDOORBELL_OFFSET 0x0020 +#define BWD_PDBMSK_OFFSET 0x0028 +#define BWD_NTBCNTL_OFFSET 0x0060 +#define BWD_EBDF_OFFSET 0x0064 +#define BWD_SPAD_OFFSET 0x0080 +#define BWD_SPADSEMA_OFFSET 0x00c0 +#define BWD_STKYSPAD_OFFSET 0x00c4 +#define BWD_PBAR2XLAT_OFFSET 0x8008 +#define BWD_PBAR4XLAT_OFFSET 0x8010 +#define BWD_B2B_DOORBELL_OFFSET 0x8020 +#define BWD_B2B_SPAD_OFFSET 0x8080 +#define BWD_B2B_SPADSEMA_OFFSET 0x80c0 +#define BWD_B2B_STKYSPAD_OFFSET 0x80c4 + +#define BWD_MODPHY_PCSREG4 0x1c004 +#define BWD_MODPHY_PCSREG6 0x1c006 + +#define BWD_IP_BASE 0xC000 +#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) +#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) +#define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) +#define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) + +#define BWD_DESKEWSTS_DBERR (1 << 15) +#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) +#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) +#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF + +#define NTB_CNTL_CFG_LOCK (1 << 0) +#define NTB_CNTL_LINK_DISABLE (1 << 1) +#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) +#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) +#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6) +#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8) +#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12) +#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14) +#define BWD_CNTL_LINK_DOWN (1 << 16) + +#define NTB_PPD_OFFSET 0x00D4 +#define SNB_PPD_CONN_TYPE 0x0003 +#define SNB_PPD_DEV_TYPE 0x0010 +#define SNB_PPD_SPLIT_BAR (1 << 6) +#define BWD_PPD_INIT_LINK 0x0008 +#define BWD_PPD_CONN_TYPE 0x0300 +#define BWD_PPD_DEV_TYPE 0x1000 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 +#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 +#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E + +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + return readl(addr) | (((u64) readl(addr + 4)) << 32LL); +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(val & 0xffffffff, addr); + writel(val >> 32, addr + 4); +} +#endif + +#define NTB_BAR_MMIO 0 +#define NTB_BAR_23 2 +#define NTB_BAR_4 4 +#define NTB_BAR_5 5 + +#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ + (1 << NTB_BAR_4)) +#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ + (1 << NTB_BAR_4) | (1 << NTB_BAR_5)) + +#define NTB_HB_TIMEOUT msecs_to_jiffies(1000) + +enum ntb_hw_event { + NTB_EVENT_SW_EVENT0 = 0, + NTB_EVENT_SW_EVENT1, + NTB_EVENT_SW_EVENT2, + NTB_EVENT_HW_ERROR, + NTB_EVENT_HW_LINK_UP, + NTB_EVENT_HW_LINK_DOWN, +}; + +struct ntb_mw { + dma_addr_t phys_addr; + void __iomem *vbase; + resource_size_t bar_sz; +}; + +struct ntb_db_cb { + int (*callback)(void *data, int db_num); + unsigned int db_num; + void *data; + struct ntb_device *ndev; + struct tasklet_struct irq_work; +}; + +#define WA_SNB_ERR 0x00000001 + +struct ntb_device { + struct pci_dev *pdev; + struct msix_entry *msix_entries; + void __iomem *reg_base; + struct ntb_mw *mw; + struct { + unsigned char max_mw; + unsigned char max_spads; + unsigned char max_db_bits; + unsigned char msix_cnt; + } limits; + struct { + void __iomem *ldb; + void __iomem *ldb_mask; + void __iomem *rdb; + void __iomem *bar2_xlat; + void __iomem *bar4_xlat; + void __iomem *bar5_xlat; + void __iomem *spad_write; + void __iomem *spad_read; + void __iomem *lnk_cntl; + void __iomem *lnk_stat; + void __iomem *spci_cmd; + } reg_ofs; + struct ntb_transport *ntb_transport; + void (*event_cb)(void *handle, enum ntb_hw_event event); + + struct ntb_db_cb *db_cb; + unsigned char hw_type; + unsigned char conn_type; + unsigned char dev_type; + unsigned char num_msix; + unsigned char bits_per_vector; + unsigned char max_cbs; + unsigned char link_width; + unsigned char link_speed; + unsigned char link_status; + unsigned char split_bar; + + struct delayed_work hb_timer; + unsigned long last_ts; + + struct delayed_work lr_timer; + + struct dentry *debugfs_dir; + struct dentry *debugfs_info; + + unsigned int wa_flags; +}; + +/** + * ntb_max_cbs() - return the max callbacks + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the maximum number of callbacks + * + * RETURNS: the maximum number of callbacks + */ +static inline unsigned char ntb_max_cbs(struct ntb_device *ndev) +{ + return ndev->max_cbs; +} + +/** + * ntb_max_mw() - return the max number of memory windows + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the maximum number of memory windows + * + * RETURNS: the maximum number of memory windows + */ +static inline unsigned char ntb_max_mw(struct ntb_device *ndev) +{ + return ndev->limits.max_mw; +} + +/** + * ntb_hw_link_status() - return the hardware link status + * @ndev: pointer to ntb_device instance + * + * Returns true if the hardware is connected to the remote system + * + * RETURNS: true or false based on the hardware link state + */ +static inline bool ntb_hw_link_status(struct ntb_device *ndev) +{ + return ndev->link_status == NTB_LINK_UP; +} + +/** + * ntb_query_pdev() - return the pci_dev pointer + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device + * + * RETURNS: a pointer to the ntb pci_dev + */ +static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev) +{ + return ndev->pdev; +} + +/** + * ntb_query_debugfs() - return the debugfs pointer + * @ndev: pointer to ntb_device instance + * + * Given the ntb pointer, return the debugfs directory pointer for the NTB + * hardware device + * + * RETURNS: a pointer to the debugfs directory + */ +static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev) +{ + return ndev->debugfs_dir; +} + +struct ntb_device *ntb_register_transport(struct pci_dev *pdev, + void *transport); +void ntb_unregister_transport(struct ntb_device *ndev); +void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); +int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, + void *data, int (*db_cb_func)(void *data, + int db_num)); +void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); +int ntb_register_event_callback(struct ntb_device *ndev, + void (*event_cb_func)(void *handle, + enum ntb_hw_event event)); +void ntb_unregister_event_callback(struct ntb_device *ndev); +int ntb_get_max_spads(struct ntb_device *ndev); +int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val); +int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); +int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val); +int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); +resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw); +void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw); +u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw); +void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx); +void *ntb_find_transport(struct pci_dev *pdev); + +int ntb_transport_init(struct pci_dev *pdev); +void ntb_transport_free(void *transport); diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c deleted file mode 100644 index 3f6738612f45..000000000000 --- a/drivers/ntb/ntb_hw.c +++ /dev/null @@ -1,1895 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copy - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "ntb_hw.h" -#include "ntb_regs.h" - -#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver" -#define NTB_VER "1.0" - -MODULE_DESCRIPTION(NTB_NAME); -MODULE_VERSION(NTB_VER); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Intel Corporation"); - -enum { - NTB_CONN_TRANSPARENT = 0, - NTB_CONN_B2B, - NTB_CONN_RP, -}; - -enum { - NTB_DEV_USD = 0, - NTB_DEV_DSD, -}; - -enum { - SNB_HW = 0, - BWD_HW, -}; - -static struct dentry *debugfs_dir; - -#define BWD_LINK_RECOVERY_TIME 500 - -/* Translate memory window 0,1,2 to BAR 2,4,5 */ -#define MW_TO_BAR(mw) (mw == 0 ? 2 : (mw == 1 ? 4 : 5)) - -static const struct pci_device_id ntb_pci_tbl[] = { - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, - {0} -}; -MODULE_DEVICE_TABLE(pci, ntb_pci_tbl); - -static int is_ntb_xeon(struct ntb_device *ndev) -{ - switch (ndev->pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - return 1; - default: - return 0; - } - - return 0; -} - -static int is_ntb_atom(struct ntb_device *ndev) -{ - switch (ndev->pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: - return 1; - default: - return 0; - } - - return 0; -} - -static void ntb_set_errata_flags(struct ntb_device *ndev) -{ - switch (ndev->pdev->device) { - /* - * this workaround applies to all platform up to IvyBridge - * Haswell has splitbar support and use a different workaround - */ - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - ndev->wa_flags |= WA_SNB_ERR; - break; - } -} - -/** - * ntb_register_event_callback() - register event callback - * @ndev: pointer to ntb_device instance - * @func: callback function to register - * - * This function registers a callback for any HW driver events such as link - * up/down, power management notices and etc. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_event_callback(struct ntb_device *ndev, - void (*func)(void *handle, - enum ntb_hw_event event)) -{ - if (ndev->event_cb) - return -EINVAL; - - ndev->event_cb = func; - - return 0; -} - -/** - * ntb_unregister_event_callback() - unregisters the event callback - * @ndev: pointer to ntb_device instance - * - * This function unregisters the existing callback from transport - */ -void ntb_unregister_event_callback(struct ntb_device *ndev) -{ - ndev->event_cb = NULL; -} - -static void ntb_irq_work(unsigned long data) -{ - struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; - int rc; - - rc = db_cb->callback(db_cb->data, db_cb->db_num); - if (rc) - tasklet_schedule(&db_cb->irq_work); - else { - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - } -} - -/** - * ntb_register_db_callback() - register a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * @data: pointer to be returned to caller with every callback - * @func: callback function to register - * - * This function registers a callback function for the doorbell interrupt - * on the primary side. The function will unmask the doorbell as well to - * allow interrupt. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*func)(void *data, int db_num)) -{ - unsigned long mask; - - if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) { - dev_warn(&ndev->pdev->dev, "Invalid Index.\n"); - return -EINVAL; - } - - ndev->db_cb[idx].callback = func; - ndev->db_cb[idx].data = data; - ndev->db_cb[idx].ndev = ndev; - - tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, - (unsigned long) &ndev->db_cb[idx]); - - /* unmask interrupt */ - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - return 0; -} - -/** - * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * - * This function unregisters a callback function for the doorbell interrupt - * on the primary side. The function will also mask the said doorbell. - */ -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) -{ - unsigned long mask; - - if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback) - return; - - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - tasklet_disable(&ndev->db_cb[idx].irq_work); - - ndev->db_cb[idx].callback = NULL; -} - -/** - * ntb_find_transport() - find the transport pointer - * @transport: pointer to pci device - * - * Given the pci device pointer, return the transport pointer passed in when - * the transport attached when it was inited. - * - * RETURNS: pointer to transport. - */ -void *ntb_find_transport(struct pci_dev *pdev) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); - return ndev->ntb_transport; -} - -/** - * ntb_register_transport() - Register NTB transport with NTB HW driver - * @transport: transport identifier - * - * This function allows a transport to reserve the hardware driver for - * NTB usage. - * - * RETURNS: pointer to ntb_device, NULL on error. - */ -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); - - if (ndev->ntb_transport) - return NULL; - - ndev->ntb_transport = transport; - return ndev; -} - -/** - * ntb_unregister_transport() - Unregister the transport with the NTB HW driver - * @ndev - ntb_device of the transport to be freed - * - * This function unregisters the transport from the HW driver and performs any - * necessary cleanups. - */ -void ntb_unregister_transport(struct ntb_device *ndev) -{ - int i; - - if (!ndev->ntb_transport) - return; - - for (i = 0; i < ndev->max_cbs; i++) - ntb_unregister_db_callback(ndev, i); - - ntb_unregister_event_callback(ndev); - ndev->ntb_transport = NULL; -} - -/** - * ntb_write_local_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. This writes over the data mirrored to the local scratchpad register - * by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_read + idx * 4); - - return 0; -} - -/** - * ntb_read_local_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This allows the local system to read data - * written and mirrored to the scratchpad register by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - *val = readl(ndev->reg_ofs.spad_write + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from local scratch pad index %d\n", *val, idx); - - return 0; -} - -/** - * ntb_write_remote_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. The register resides on the secondary (external) side. This allows - * the local system to write data to be mirrored to the remote systems - * scratchpad register. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_write + idx * 4); - - return 0; -} - -/** - * ntb_read_remote_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This alloows the local system to read the data - * it wrote to be mirrored on the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) -{ - if (idx >= ndev->limits.max_spads) - return -EINVAL; - - *val = readl(ndev->reg_ofs.spad_read + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from remote scratch pad index %d\n", *val, idx); - - return 0; -} - -/** - * ntb_get_mw_base() - get addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base address of the memory window specified. - * - * RETURNS: address, or NULL on error. - */ -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw) -{ - if (mw >= ntb_max_mw(ndev)) - return 0; - - return pci_resource_start(ndev->pdev, MW_TO_BAR(mw)); -} - -/** - * ntb_get_mw_vbase() - get virtual addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base virtual address of the memory window - * specified. - * - * RETURNS: pointer to virtual address, or NULL on error. - */ -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw) -{ - if (mw >= ntb_max_mw(ndev)) - return NULL; - - return ndev->mw[mw].vbase; -} - -/** - * ntb_get_mw_size() - return size of NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the physical size of the memory window specified - * - * RETURNS: the size of the memory window or zero on error - */ -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw) -{ - if (mw >= ntb_max_mw(ndev)) - return 0; - - return ndev->mw[mw].bar_sz; -} - -/** - * ntb_set_mw_addr - set the memory window address - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * @addr: base address for data - * - * This function sets the base physical address of the memory window. This - * memory address is where data from the remote system will be transfered into - * or out of depending on how the transport is configured. - */ -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr) -{ - if (mw >= ntb_max_mw(ndev)) - return; - - dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr, - MW_TO_BAR(mw)); - - ndev->mw[mw].phys_addr = addr; - - switch (MW_TO_BAR(mw)) { - case NTB_BAR_23: - writeq(addr, ndev->reg_ofs.bar2_xlat); - break; - case NTB_BAR_4: - if (ndev->split_bar) - writel(addr, ndev->reg_ofs.bar4_xlat); - else - writeq(addr, ndev->reg_ofs.bar4_xlat); - break; - case NTB_BAR_5: - writel(addr, ndev->reg_ofs.bar5_xlat); - break; - } -} - -/** - * ntb_ring_doorbell() - Set the doorbell on the secondary/external side - * @ndev: pointer to ntb_device instance - * @db: doorbell to ring - * - * This function allows triggering of a doorbell on the secondary/external - * side that will initiate an interrupt on the remote host - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db) -{ - dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db); - - if (ndev->hw_type == BWD_HW) - writeq((u64) 1 << db, ndev->reg_ofs.rdb); - else - writew(((1 << ndev->bits_per_vector) - 1) << - (db * ndev->bits_per_vector), ndev->reg_ofs.rdb); -} - -static void bwd_recover_link(struct ntb_device *ndev) -{ - u32 status; - - /* Driver resets the NTB ModPhy lanes - magic! */ - writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6); - writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6); - - /* Driver waits 100ms to allow the NTB ModPhy to settle */ - msleep(100); - - /* Clear AER Errors, write to clear */ - status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status); - status &= PCI_ERR_COR_REP_ROLL; - writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET); - - /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status); - status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; - writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); - - /* Clear DeSkew Buffer error, write to clear */ - status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status); - status |= BWD_DESKEWSTS_DBERR; - writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET); - - status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status); - status &= BWD_IBIST_ERR_OFLOW; - writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - - /* Releases the NTB state machine to allow the link to retrain */ - status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status); - status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; - writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); -} - -static void ntb_link_event(struct ntb_device *ndev, int link_state) -{ - unsigned int event; - - if (ndev->link_status == link_state) - return; - - if (link_state == NTB_LINK_UP) { - u16 status; - - dev_info(&ndev->pdev->dev, "Link Up\n"); - ndev->link_status = NTB_LINK_UP; - event = NTB_EVENT_HW_LINK_UP; - - if (is_ntb_atom(ndev) || - ndev->conn_type == NTB_CONN_TRANSPARENT) - status = readw(ndev->reg_ofs.lnk_stat); - else { - int rc = pci_read_config_word(ndev->pdev, - SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return; - } - - ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; - ndev->link_speed = (status & NTB_LINK_SPEED_MASK); - dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n", - ndev->link_width, ndev->link_speed); - } else { - dev_info(&ndev->pdev->dev, "Link Down\n"); - ndev->link_status = NTB_LINK_DOWN; - event = NTB_EVENT_HW_LINK_DOWN; - /* Don't modify link width/speed, we need it in link recovery */ - } - - /* notify the upper layer if we have an event change */ - if (ndev->event_cb) - ndev->event_cb(ndev->ntb_transport, event); -} - -static int ntb_link_status(struct ntb_device *ndev) -{ - int link_state; - - if (is_ntb_atom(ndev)) { - u32 ntb_cntl; - - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - if (ntb_cntl & BWD_CNTL_LINK_DOWN) - link_state = NTB_LINK_DOWN; - else - link_state = NTB_LINK_UP; - } else { - u16 status; - int rc; - - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return rc; - - if (status & NTB_LINK_STATUS_ACTIVE) - link_state = NTB_LINK_UP; - else - link_state = NTB_LINK_DOWN; - } - - ntb_link_event(ndev, link_state); - - return 0; -} - -static void bwd_link_recovery(struct work_struct *work) -{ - struct ntb_device *ndev = container_of(work, struct ntb_device, - lr_timer.work); - u32 status32; - - bwd_recover_link(ndev); - /* There is a potential race between the 2 NTB devices recovering at the - * same time. If the times are the same, the link will not recover and - * the driver will be stuck in this loop forever. Add a random interval - * to the recovery time to prevent this race. - */ - msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME); - - status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) - goto retry; - - status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - if (status32 & BWD_IBIST_ERR_OFLOW) - goto retry; - - status32 = readl(ndev->reg_ofs.lnk_cntl); - if (!(status32 & BWD_CNTL_LINK_DOWN)) { - unsigned char speed, width; - u16 status16; - - status16 = readw(ndev->reg_ofs.lnk_stat); - width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; - speed = (status16 & NTB_LINK_SPEED_MASK); - if (ndev->link_width != width || ndev->link_speed != speed) - goto retry; - } - - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); - return; - -retry: - schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT); -} - -/* BWD doesn't have link status interrupt, poll on that platform */ -static void bwd_link_poll(struct work_struct *work) -{ - struct ntb_device *ndev = container_of(work, struct ntb_device, - hb_timer.work); - unsigned long ts = jiffies; - - /* If we haven't gotten an interrupt in a while, check the BWD link - * status bit - */ - if (ts > ndev->last_ts + NTB_HB_TIMEOUT) { - int rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, - "Error determining link status\n"); - - /* Check to see if a link error is the cause of the link down */ - if (ndev->link_status == NTB_LINK_DOWN) { - u32 status32 = readl(ndev->reg_base + - BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) { - schedule_delayed_work(&ndev->lr_timer, 0); - return; - } - } - } - - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); -} - -static int ntb_xeon_setup(struct ntb_device *ndev) -{ - switch (ndev->conn_type) { - case NTB_CONN_B2B: - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_spads = SNB_MAX_B2B_SPADS; - - /* There is a Xeon hardware errata related to writes to - * SDOORBELL or B2BDOORBELL in conjunction with inbound access - * to NTB MMIO Space, which may hang the system. To workaround - * this use the second memory window to access the interrupt and - * scratch pad registers on the remote system. - */ - if (ndev->wa_flags & WA_SNB_ERR) { - if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz) - return -EINVAL; - - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.spad_write = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_SPAD_OFFSET; - ndev->reg_ofs.rdb = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_PDOORBELL_OFFSET; - - /* Set the Limit register to 4k, the minimum size, to - * prevent an illegal access - */ - writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + - SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - - ndev->limits.max_mw = SNB_ERRATA_MAX_MW; - } else { - /* HW Errata on bit 14 of b2bdoorbell register. Writes - * will not be mirrored to the remote system. Shrink - * the number of bits by one, since bit 14 is the last - * bit. - */ - ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; - ndev->reg_ofs.spad_write = ndev->reg_base + - SNB_B2B_SPAD_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + - SNB_B2B_DOORBELL_OFFSET; - - /* Disable the Limit register, just incase it is set to - * something silly. A 64bit write should handle it - * regardless of whether it has a split BAR or not. - */ - writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - else - ndev->limits.max_mw = SNB_MAX_MW; - } - - /* The Xeon errata workaround requires setting SBAR Base - * addresses to known values, so that the PBAR XLAT can be - * pointed at SBAR0 of the remote system. - */ - if (ndev->dev_type == NTB_DEV_USD) { - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_DSD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_USD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - } else { - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_USD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* - * B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_USD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_USD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - - } - break; - case NTB_CONN_RP: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-RP disabled due to hardware errata.\n"); - return -EINVAL; - } - - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - /* Note: The SDOORBELL is the cause of the errata. You REALLY - * don't want to touch it. - */ - ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - case NTB_CONN_TRANSPARENT: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-TRANSPARENT disabled due to hardware errata.\n"); - return -EINVAL; - } - - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; - - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_PBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - default: - /* - * we should never hit this. the detect function should've - * take cared of everything. - */ - return -EINVAL; - } - - ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; - - ndev->limits.msix_cnt = SNB_MSIX_CNT; - ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; - - return 0; -} - -static int ntb_bwd_setup(struct ntb_device *ndev) -{ - int rc; - u32 val; - - ndev->hw_type = BWD_HW; - - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val); - if (rc) - return rc; - - switch ((val & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); - return -EINVAL; - } - - if (val & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; - - /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET, - val | BWD_PPD_INIT_LINK); - if (rc) - return rc; - - ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET; - ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET; - ndev->limits.max_mw = BWD_MAX_MW; - ndev->limits.max_spads = BWD_MAX_SPADS; - ndev->limits.max_db_bits = BWD_MAX_DB_BITS; - ndev->limits.msix_cnt = BWD_MSIX_CNT; - ndev->bits_per_vector = BWD_DB_BITS_PER_VEC; - - /* Since bwd doesn't have a link interrupt, setup a poll timer */ - INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll); - INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery); - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); - - return 0; -} - -static int ntb_device_setup(struct ntb_device *ndev) -{ - int rc; - - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_setup(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_bwd_setup(ndev); - else - rc = -ENODEV; - - if (rc) - return rc; - - if (ndev->conn_type == NTB_CONN_B2B) - /* Enable Bus Master and Memory Space on the secondary side */ - writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->reg_ofs.spci_cmd); - - return 0; -} - -static void ntb_device_free(struct ntb_device *ndev) -{ - if (is_ntb_atom(ndev)) { - cancel_delayed_work_sync(&ndev->hb_timer); - cancel_delayed_work_sync(&ndev->lr_timer); - } -} - -static irqreturn_t bwd_callback_msix_irq(int irq, void *data) -{ - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); - - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - tasklet_schedule(&db_cb->irq_work); - - /* No need to check for the specific HB irq, any interrupt means - * we're connected. - */ - ndev->last_ts = jiffies; - - writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb); - - return IRQ_HANDLED; -} - -static irqreturn_t xeon_callback_msix_irq(int irq, void *data) -{ - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); - - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - - tasklet_schedule(&db_cb->irq_work); - - /* On Sandybridge, there are 16 bits in the interrupt register - * but only 4 vectors. So, 5 bits are assigned to the first 3 - * vectors, with the 4th having a single bit for link - * interrupts. - */ - writew(((1 << ndev->bits_per_vector) - 1) << - (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb); - - return IRQ_HANDLED; -} - -/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */ -static irqreturn_t xeon_event_msix_irq(int irq, void *dev) -{ - struct ntb_device *ndev = dev; - int rc; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq); - - rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, "Error determining link status\n"); - - /* bit 15 is always the link bit */ - writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); - - return IRQ_HANDLED; -} - -static irqreturn_t ntb_interrupt(int irq, void *dev) -{ - struct ntb_device *ndev = dev; - unsigned int i = 0; - - if (is_ntb_atom(ndev)) { - u64 ldb = readq(ndev->reg_ofs.ldb); - - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb); - - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - bwd_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } else { - u16 ldb = readw(ndev->reg_ofs.ldb); - - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb); - - if (ldb & SNB_DB_HW_LINK) { - xeon_event_msix_irq(irq, dev); - ldb &= ~SNB_DB_HW_LINK; - } - - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - xeon_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } - - return IRQ_HANDLED; -} - -static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries) -{ - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; - - if (msix_entries < ndev->limits.msix_cnt) - return -ENOSPC; - - rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries); - if (rc < 0) - return rc; - - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); - - if (i == msix_entries - 1) { - rc = request_irq(msix->vector, - xeon_event_msix_irq, 0, - "ntb-event-msix", ndev); - if (rc) - goto err; - } else { - rc = request_irq(msix->vector, - xeon_callback_msix_irq, 0, - "ntb-callback-msix", - &ndev->db_cb[i]); - if (rc) - goto err; - } - } - - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries - 1; - - return 0; - -err: - while (--i >= 0) { - /* Code never reaches here for entry nr 'ndev->num_msix - 1' */ - msix = &ndev->msix_entries[i]; - free_irq(msix->vector, &ndev->db_cb[i]); - } - - pci_disable_msix(pdev); - ndev->num_msix = 0; - - return rc; -} - -static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries) -{ - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; - - msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries, - 1, msix_entries); - if (msix_entries < 0) - return msix_entries; - - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); - - rc = request_irq(msix->vector, bwd_callback_msix_irq, 0, - "ntb-callback-msix", &ndev->db_cb[i]); - if (rc) - goto err; - } - - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries; - - return 0; - -err: - while (--i >= 0) - free_irq(msix->vector, &ndev->db_cb[i]); - - pci_disable_msix(pdev); - ndev->num_msix = 0; - - return rc; -} - -static int ntb_setup_msix(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - int msix_entries; - int rc, i; - - msix_entries = pci_msix_vec_count(pdev); - if (msix_entries < 0) { - rc = msix_entries; - goto err; - } else if (msix_entries > ndev->limits.msix_cnt) { - rc = -EINVAL; - goto err; - } - - ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries, - GFP_KERNEL); - if (!ndev->msix_entries) { - rc = -ENOMEM; - goto err; - } - - for (i = 0; i < msix_entries; i++) - ndev->msix_entries[i].entry = i; - - if (is_ntb_atom(ndev)) - rc = ntb_setup_bwd_msix(ndev, msix_entries); - else - rc = ntb_setup_snb_msix(ndev, msix_entries); - if (rc) - goto err1; - - return 0; - -err1: - kfree(ndev->msix_entries); -err: - dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n"); - return rc; -} - -static int ntb_setup_msi(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - int rc; - - rc = pci_enable_msi(pdev); - if (rc) - return rc; - - rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev); - if (rc) { - pci_disable_msi(pdev); - dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); - return rc; - } - - return 0; -} - -static int ntb_setup_intx(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - int rc; - - /* Verify intx is enabled */ - pci_intx(pdev, 1); - - rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx", - ndev); - if (rc) - return rc; - - return 0; -} - -static int ntb_setup_interrupts(struct ntb_device *ndev) -{ - int rc; - - /* On BWD, disable all interrupts. On SNB, disable all but Link - * Interrupt. The rest will be unmasked as callbacks are registered. - */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else { - u16 var = 1 << SNB_LINK_DB; - writew(~var, ndev->reg_ofs.ldb_mask); - } - - rc = ntb_setup_msix(ndev); - if (!rc) - goto done; - - ndev->bits_per_vector = 1; - ndev->max_cbs = ndev->limits.max_db_bits; - - rc = ntb_setup_msi(ndev); - if (!rc) - goto done; - - rc = ntb_setup_intx(ndev); - if (rc) { - dev_err(&ndev->pdev->dev, "no usable interrupts\n"); - return rc; - } - -done: - return 0; -} - -static void ntb_free_interrupts(struct ntb_device *ndev) -{ - struct pci_dev *pdev = ndev->pdev; - - /* mask interrupts */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else - writew(~0, ndev->reg_ofs.ldb_mask); - - if (ndev->num_msix) { - struct msix_entry *msix; - u32 i; - - for (i = 0; i < ndev->num_msix; i++) { - msix = &ndev->msix_entries[i]; - if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1) - free_irq(msix->vector, ndev); - else - free_irq(msix->vector, &ndev->db_cb[i]); - } - pci_disable_msix(pdev); - kfree(ndev->msix_entries); - } else { - free_irq(pdev->irq, ndev); - - if (pci_dev_msi_enabled(pdev)) - pci_disable_msi(pdev); - } -} - -static int ntb_create_callbacks(struct ntb_device *ndev) -{ - int i; - - /* Chicken-egg issue. We won't know how many callbacks are necessary - * until we see how many MSI-X vectors we get, but these pointers need - * to be passed into the MSI-X register function. So, we allocate the - * max, knowing that they might not all be used, to work around this. - */ - ndev->db_cb = kcalloc(ndev->limits.max_db_bits, - sizeof(struct ntb_db_cb), - GFP_KERNEL); - if (!ndev->db_cb) - return -ENOMEM; - - for (i = 0; i < ndev->limits.max_db_bits; i++) { - ndev->db_cb[i].db_num = i; - ndev->db_cb[i].ndev = ndev; - } - - return 0; -} - -static void ntb_free_callbacks(struct ntb_device *ndev) -{ - int i; - - for (i = 0; i < ndev->limits.max_db_bits; i++) - ntb_unregister_db_callback(ndev, i); - - kfree(ndev->db_cb); -} - -static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) -{ - struct ntb_device *ndev; - char *buf; - ssize_t ret, offset, out_count; - - out_count = 500; - - buf = kmalloc(out_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ndev = filp->private_data; - offset = 0; - offset += snprintf(buf + offset, out_count - offset, - "NTB Device Information:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Connection Type - \t\t%s\n", - ndev->conn_type == NTB_CONN_TRANSPARENT ? - "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ? - "Back to back" : "Root Port"); - offset += snprintf(buf + offset, out_count - offset, - "Device Type - \t\t\t%s\n", - ndev->dev_type == NTB_DEV_USD ? - "DSD/USP" : "USD/DSP"); - offset += snprintf(buf + offset, out_count - offset, - "Max Number of Callbacks - \t%u\n", - ntb_max_cbs(ndev)); - offset += snprintf(buf + offset, out_count - offset, - "Link Status - \t\t\t%s\n", - ntb_hw_link_status(ndev) ? "Up" : "Down"); - if (ntb_hw_link_status(ndev)) { - offset += snprintf(buf + offset, out_count - offset, - "Link Speed - \t\t\tPCI-E Gen %u\n", - ndev->link_speed); - offset += snprintf(buf + offset, out_count - offset, - "Link Width - \t\t\tx%u\n", - ndev->link_width); - } - - if (is_ntb_xeon(ndev)) { - u32 status32; - u16 status16; - int rc; - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Device Statistics:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Upstream Memory Miss - \t%u\n", - readw(ndev->reg_base + - SNB_USMEMMISS_OFFSET)); - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Hardware Errors:\n"); - - rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "DEVSTS - \t%#06x\n", status16); - - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "LNKSTS - \t%#06x\n", status16); - - rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "UNCERRSTS - \t%#010x\n", status32); - - rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "CORERRSTS - \t%#010x\n", status32); - } - - if (offset > out_count) - offset = out_count; - - ret = simple_read_from_buffer(ubuf, count, offp, buf, offset); - kfree(buf); - return ret; -} - -static const struct file_operations ntb_debugfs_info = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ntb_debugfs_read, -}; - -static void ntb_setup_debugfs(struct ntb_device *ndev) -{ - if (!debugfs_initialized()) - return; - - if (!debugfs_dir) - debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - - ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev), - debugfs_dir); - if (ndev->debugfs_dir) - ndev->debugfs_info = debugfs_create_file("info", S_IRUSR, - ndev->debugfs_dir, - ndev, - &ntb_debugfs_info); -} - -static void ntb_free_debugfs(struct ntb_device *ndev) -{ - debugfs_remove_recursive(ndev->debugfs_dir); - - if (debugfs_dir && simple_empty(debugfs_dir)) { - debugfs_remove_recursive(debugfs_dir); - debugfs_dir = NULL; - } -} - -static void ntb_hw_link_up(struct ntb_device *ndev) -{ - if (ndev->conn_type == NTB_CONN_TRANSPARENT) - ntb_link_event(ndev, NTB_LINK_UP); - else { - u32 ntb_cntl; - - /* Let's bring the NTB link up */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); - ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; - ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; - if (ndev->split_bar) - ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP; - - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); - } -} - -static void ntb_hw_link_down(struct ntb_device *ndev) -{ - u32 ntb_cntl; - - if (ndev->conn_type == NTB_CONN_TRANSPARENT) { - ntb_link_event(ndev, NTB_LINK_DOWN); - return; - } - - /* Bring NTB link down */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); - if (ndev->split_bar) - ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP); - ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); -} - -static void ntb_max_mw_detect(struct ntb_device *ndev) -{ - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - else - ndev->limits.max_mw = SNB_MAX_MW; -} - -static int ntb_xeon_detect(struct ntb_device *ndev) -{ - int rc, bars_mask; - u32 bars; - u8 ppd; - - ndev->hw_type = SNB_HW; - - rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd); - if (rc) - return -EIO; - - if (ppd & SNB_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_USD; - else - ndev->dev_type = NTB_DEV_DSD; - - ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0; - - switch (ppd & SNB_PPD_CONN_TYPE) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); - ndev->conn_type = NTB_CONN_RP; - break; - case NTB_CONN_TRANSPARENT: - dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); - ndev->conn_type = NTB_CONN_TRANSPARENT; - /* - * This mode is default to USD/DSP. HW does not report - * properly in transparent mode as it has no knowledge of - * NTB. We will just force correct here. - */ - ndev->dev_type = NTB_DEV_USD; - - /* - * This is a way for transparent BAR to figure out if we - * are doing split BAR or not. There is no way for the hw - * on the transparent side to know and set the PPD. - */ - bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM); - bars = hweight32(bars_mask); - if (bars == (HSX_SPLITBAR_MAX_MW + 1)) - ndev->split_bar = 1; - - break; - default: - dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd); - return -ENODEV; - } - - ntb_max_mw_detect(ndev); - - return 0; -} - -static int ntb_atom_detect(struct ntb_device *ndev) -{ - int rc; - u32 ppd; - - ndev->hw_type = BWD_HW; - ndev->limits.max_mw = BWD_MAX_MW; - - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd); - if (rc) - return rc; - - switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); - return -EINVAL; - } - - if (ppd & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; - - return 0; -} - -static int ntb_device_detect(struct ntb_device *ndev) -{ - int rc; - - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_detect(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_atom_detect(ndev); - else - rc = -ENODEV; - - dev_info(&ndev->pdev->dev, "Device Type = %s\n", - ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); - - return 0; -} - -static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct ntb_device *ndev; - int rc, i; - - ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL); - if (!ndev) - return -ENOMEM; - - ndev->pdev = pdev; - - ntb_set_errata_flags(ndev); - - ndev->link_status = NTB_LINK_DOWN; - pci_set_drvdata(pdev, ndev); - ntb_setup_debugfs(ndev); - - rc = pci_enable_device(pdev); - if (rc) - goto err; - - pci_set_master(ndev->pdev); - - rc = ntb_device_detect(ndev); - if (rc) - goto err; - - ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw), - GFP_KERNEL); - if (!ndev->mw) { - rc = -ENOMEM; - goto err1; - } - - if (ndev->split_bar) - rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK, - KBUILD_MODNAME); - else - rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, - KBUILD_MODNAME); - - if (rc) - goto err2; - - ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO); - if (!ndev->reg_base) { - dev_warn(&pdev->dev, "Cannot remap BAR 0\n"); - rc = -EIO; - goto err3; - } - - for (i = 0; i < ndev->limits.max_mw; i++) { - ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i)); - - /* - * with the errata we need to steal last of the memory - * windows for workarounds and they point to MMIO registers. - */ - if ((ndev->wa_flags & WA_SNB_ERR) && - (i == (ndev->limits.max_mw - 1))) { - ndev->mw[i].vbase = - ioremap_nocache(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } else { - ndev->mw[i].vbase = - ioremap_wc(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } - - dev_info(&pdev->dev, "MW %d size %llu\n", i, - (unsigned long long) ndev->mw[i].bar_sz); - if (!ndev->mw[i].vbase) { - dev_warn(&pdev->dev, "Cannot remap BAR %d\n", - MW_TO_BAR(i)); - rc = -EIO; - goto err4; - } - } - - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err4; - - dev_warn(&pdev->dev, "Cannot DMA highmem\n"); - } - - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err4; - - dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); - } - - rc = ntb_device_setup(ndev); - if (rc) - goto err4; - - rc = ntb_create_callbacks(ndev); - if (rc) - goto err5; - - rc = ntb_setup_interrupts(ndev); - if (rc) - goto err6; - - /* The scratchpad registers keep the values between rmmod/insmod, - * blast them now - */ - for (i = 0; i < ndev->limits.max_spads; i++) { - ntb_write_local_spad(ndev, i, 0); - ntb_write_remote_spad(ndev, i, 0); - } - - rc = ntb_transport_init(pdev); - if (rc) - goto err7; - - ntb_hw_link_up(ndev); - - return 0; - -err7: - ntb_free_interrupts(ndev); -err6: - ntb_free_callbacks(ndev); -err5: - ntb_device_free(ndev); -err4: - for (i--; i >= 0; i--) - iounmap(ndev->mw[i].vbase); - iounmap(ndev->reg_base); -err3: - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); -err2: - kfree(ndev->mw); -err1: - pci_disable_device(pdev); -err: - ntb_free_debugfs(ndev); - kfree(ndev); - - dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME); - return rc; -} - -static void ntb_pci_remove(struct pci_dev *pdev) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); - int i; - - ntb_hw_link_down(ndev); - - ntb_transport_free(ndev->ntb_transport); - - ntb_free_interrupts(ndev); - ntb_free_callbacks(ndev); - ntb_device_free(ndev); - - /* need to reset max_mw limits so we can unmap properly */ - if (ndev->hw_type == SNB_HW) - ntb_max_mw_detect(ndev); - - for (i = 0; i < ndev->limits.max_mw; i++) - iounmap(ndev->mw[i].vbase); - - kfree(ndev->mw); - iounmap(ndev->reg_base); - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); - pci_disable_device(pdev); - ntb_free_debugfs(ndev); - kfree(ndev); -} - -static struct pci_driver ntb_pci_driver = { - .name = KBUILD_MODNAME, - .id_table = ntb_pci_tbl, - .probe = ntb_pci_probe, - .remove = ntb_pci_remove, -}; - -module_pci_driver(ntb_pci_driver); diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h deleted file mode 100644 index 96de5fc95f90..000000000000 --- a/drivers/ntb/ntb_hw.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copy - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ -#include - -#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 -#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 -#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 -#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E - -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(val & 0xffffffff, addr); - writel(val >> 32, addr + 4); -} -#endif - -#define NTB_BAR_MMIO 0 -#define NTB_BAR_23 2 -#define NTB_BAR_4 4 -#define NTB_BAR_5 5 - -#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4)) -#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4) | (1 << NTB_BAR_5)) - -#define NTB_HB_TIMEOUT msecs_to_jiffies(1000) - -enum ntb_hw_event { - NTB_EVENT_SW_EVENT0 = 0, - NTB_EVENT_SW_EVENT1, - NTB_EVENT_SW_EVENT2, - NTB_EVENT_HW_ERROR, - NTB_EVENT_HW_LINK_UP, - NTB_EVENT_HW_LINK_DOWN, -}; - -struct ntb_mw { - dma_addr_t phys_addr; - void __iomem *vbase; - resource_size_t bar_sz; -}; - -struct ntb_db_cb { - int (*callback)(void *data, int db_num); - unsigned int db_num; - void *data; - struct ntb_device *ndev; - struct tasklet_struct irq_work; -}; - -#define WA_SNB_ERR 0x00000001 - -struct ntb_device { - struct pci_dev *pdev; - struct msix_entry *msix_entries; - void __iomem *reg_base; - struct ntb_mw *mw; - struct { - unsigned char max_mw; - unsigned char max_spads; - unsigned char max_db_bits; - unsigned char msix_cnt; - } limits; - struct { - void __iomem *ldb; - void __iomem *ldb_mask; - void __iomem *rdb; - void __iomem *bar2_xlat; - void __iomem *bar4_xlat; - void __iomem *bar5_xlat; - void __iomem *spad_write; - void __iomem *spad_read; - void __iomem *lnk_cntl; - void __iomem *lnk_stat; - void __iomem *spci_cmd; - } reg_ofs; - struct ntb_transport *ntb_transport; - void (*event_cb)(void *handle, enum ntb_hw_event event); - - struct ntb_db_cb *db_cb; - unsigned char hw_type; - unsigned char conn_type; - unsigned char dev_type; - unsigned char num_msix; - unsigned char bits_per_vector; - unsigned char max_cbs; - unsigned char link_width; - unsigned char link_speed; - unsigned char link_status; - unsigned char split_bar; - - struct delayed_work hb_timer; - unsigned long last_ts; - - struct delayed_work lr_timer; - - struct dentry *debugfs_dir; - struct dentry *debugfs_info; - - unsigned int wa_flags; -}; - -/** - * ntb_max_cbs() - return the max callbacks - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of callbacks - * - * RETURNS: the maximum number of callbacks - */ -static inline unsigned char ntb_max_cbs(struct ntb_device *ndev) -{ - return ndev->max_cbs; -} - -/** - * ntb_max_mw() - return the max number of memory windows - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of memory windows - * - * RETURNS: the maximum number of memory windows - */ -static inline unsigned char ntb_max_mw(struct ntb_device *ndev) -{ - return ndev->limits.max_mw; -} - -/** - * ntb_hw_link_status() - return the hardware link status - * @ndev: pointer to ntb_device instance - * - * Returns true if the hardware is connected to the remote system - * - * RETURNS: true or false based on the hardware link state - */ -static inline bool ntb_hw_link_status(struct ntb_device *ndev) -{ - return ndev->link_status == NTB_LINK_UP; -} - -/** - * ntb_query_pdev() - return the pci_dev pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device - * - * RETURNS: a pointer to the ntb pci_dev - */ -static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev) -{ - return ndev->pdev; -} - -/** - * ntb_query_debugfs() - return the debugfs pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the debugfs directory pointer for the NTB - * hardware device - * - * RETURNS: a pointer to the debugfs directory - */ -static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev) -{ - return ndev->debugfs_dir; -} - -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, - void *transport); -void ntb_unregister_transport(struct ntb_device *ndev); -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*db_cb_func)(void *data, - int db_num)); -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); -int ntb_register_event_callback(struct ntb_device *ndev, - void (*event_cb_func)(void *handle, - enum ntb_hw_event event)); -void ntb_unregister_event_callback(struct ntb_device *ndev); -int ntb_get_max_spads(struct ntb_device *ndev); -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw); -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw); -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw); -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx); -void *ntb_find_transport(struct pci_dev *pdev); - -int ntb_transport_init(struct pci_dev *pdev); -void ntb_transport_free(void *transport); diff --git a/drivers/ntb/ntb_regs.h b/drivers/ntb/ntb_regs.h deleted file mode 100644 index f028ff81fd77..000000000000 --- a/drivers/ntb/ntb_regs.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copy - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ - -#define NTB_LINK_STATUS_ACTIVE 0x2000 -#define NTB_LINK_SPEED_MASK 0x000f -#define NTB_LINK_WIDTH_MASK 0x03f0 - -#define SNB_MSIX_CNT 4 -#define SNB_MAX_B2B_SPADS 16 -#define SNB_MAX_COMPAT_SPADS 16 -/* Reserve the uppermost bit for link interrupt */ -#define SNB_MAX_DB_BITS 15 -#define SNB_LINK_DB 15 -#define SNB_DB_BITS_PER_VEC 5 -#define HSX_SPLITBAR_MAX_MW 3 -#define SNB_MAX_MW 2 -#define SNB_ERRATA_MAX_MW 1 - -#define SNB_DB_HW_LINK 0x8000 - -#define SNB_UNCERRSTS_OFFSET 0x014C -#define SNB_CORERRSTS_OFFSET 0x0158 -#define SNB_LINK_STATUS_OFFSET 0x01A2 -#define SNB_PCICMD_OFFSET 0x0504 -#define SNB_DEVCTRL_OFFSET 0x0598 -#define SNB_DEVSTS_OFFSET 0x059A -#define SNB_SLINK_STATUS_OFFSET 0x05A2 - -#define SNB_PBAR2LMT_OFFSET 0x0000 -#define SNB_PBAR4LMT_OFFSET 0x0008 -#define SNB_PBAR5LMT_OFFSET 0x000C -#define SNB_PBAR2XLAT_OFFSET 0x0010 -#define SNB_PBAR4XLAT_OFFSET 0x0018 -#define SNB_PBAR5XLAT_OFFSET 0x001C -#define SNB_SBAR2LMT_OFFSET 0x0020 -#define SNB_SBAR4LMT_OFFSET 0x0028 -#define SNB_SBAR5LMT_OFFSET 0x002C -#define SNB_SBAR2XLAT_OFFSET 0x0030 -#define SNB_SBAR4XLAT_OFFSET 0x0038 -#define SNB_SBAR5XLAT_OFFSET 0x003C -#define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR2BASE_OFFSET 0x0048 -#define SNB_SBAR4BASE_OFFSET 0x0050 -#define SNB_SBAR5BASE_OFFSET 0x0054 -#define SNB_NTBCNTL_OFFSET 0x0058 -#define SNB_SBDF_OFFSET 0x005C -#define SNB_PDOORBELL_OFFSET 0x0060 -#define SNB_PDBMSK_OFFSET 0x0062 -#define SNB_SDOORBELL_OFFSET 0x0064 -#define SNB_SDBMSK_OFFSET 0x0066 -#define SNB_USMEMMISS_OFFSET 0x0070 -#define SNB_SPAD_OFFSET 0x0080 -#define SNB_SPADSEMA4_OFFSET 0x00c0 -#define SNB_WCCNTRL_OFFSET 0x00e0 -#define SNB_B2B_SPAD_OFFSET 0x0100 -#define SNB_B2B_DOORBELL_OFFSET 0x0140 -#define SNB_B2B_XLAT_OFFSETL 0x0144 -#define SNB_B2B_XLAT_OFFSETU 0x0148 - -/* - * The addresses are setup so the 32bit BARs can function. Thus - * the addresses are all in 32bit space - */ -#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL -#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL -#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL -#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL -#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL -#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL -#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL -#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL - -#define BWD_MSIX_CNT 34 -#define BWD_MAX_SPADS 16 -#define BWD_MAX_DB_BITS 34 -#define BWD_DB_BITS_PER_VEC 1 -#define BWD_MAX_MW 2 - -#define BWD_PCICMD_OFFSET 0xb004 -#define BWD_MBAR23_OFFSET 0xb018 -#define BWD_MBAR45_OFFSET 0xb020 -#define BWD_DEVCTRL_OFFSET 0xb048 -#define BWD_LINK_STATUS_OFFSET 0xb052 -#define BWD_ERRCORSTS_OFFSET 0xb110 - -#define BWD_SBAR2XLAT_OFFSET 0x0008 -#define BWD_SBAR4XLAT_OFFSET 0x0010 -#define BWD_PDOORBELL_OFFSET 0x0020 -#define BWD_PDBMSK_OFFSET 0x0028 -#define BWD_NTBCNTL_OFFSET 0x0060 -#define BWD_EBDF_OFFSET 0x0064 -#define BWD_SPAD_OFFSET 0x0080 -#define BWD_SPADSEMA_OFFSET 0x00c0 -#define BWD_STKYSPAD_OFFSET 0x00c4 -#define BWD_PBAR2XLAT_OFFSET 0x8008 -#define BWD_PBAR4XLAT_OFFSET 0x8010 -#define BWD_B2B_DOORBELL_OFFSET 0x8020 -#define BWD_B2B_SPAD_OFFSET 0x8080 -#define BWD_B2B_SPADSEMA_OFFSET 0x80c0 -#define BWD_B2B_STKYSPAD_OFFSET 0x80c4 - -#define BWD_MODPHY_PCSREG4 0x1c004 -#define BWD_MODPHY_PCSREG6 0x1c006 - -#define BWD_IP_BASE 0xC000 -#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) -#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) -#define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) -#define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) - -#define BWD_DESKEWSTS_DBERR (1 << 15) -#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) -#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) -#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define NTB_CNTL_CFG_LOCK (1 << 0) -#define NTB_CNTL_LINK_DISABLE (1 << 1) -#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) -#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) -#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6) -#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8) -#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12) -#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14) -#define BWD_CNTL_LINK_DOWN (1 << 16) - -#define NTB_PPD_OFFSET 0x00D4 -#define SNB_PPD_CONN_TYPE 0x0003 -#define SNB_PPD_DEV_TYPE 0x0010 -#define SNB_PPD_SPLIT_BAR (1 << 6) -#define BWD_PPD_INIT_LINK 0x0008 -#define BWD_PPD_CONN_TYPE 0x0300 -#define BWD_PPD_DEV_TYPE 0x1000 diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index e9bf2f47b61a..c5f26cda9f97 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -56,7 +56,7 @@ #include #include #include -#include "ntb_hw.h" +#include "hw/intel/ntb_hw_intel.h" #define NTB_TRANSPORT_VERSION 3 @@ -360,14 +360,14 @@ err: EXPORT_SYMBOL_GPL(ntb_register_client_dev); /** - * ntb_register_client - Register NTB client driver + * ntb_transport_register_client - Register NTB client driver * @drv: NTB client driver to be registered * * Register an NTB client driver with the NTB transport layer * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -int ntb_register_client(struct ntb_client *drv) +int ntb_transport_register_client(struct ntb_client *drv) { drv->driver.bus = &ntb_bus_type; @@ -376,21 +376,21 @@ int ntb_register_client(struct ntb_client *drv) return driver_register(&drv->driver); } -EXPORT_SYMBOL_GPL(ntb_register_client); +EXPORT_SYMBOL_GPL(ntb_transport_register_client); /** - * ntb_unregister_client - Unregister NTB client driver + * ntb_transport_unregister_client - Unregister NTB client driver * @drv: NTB client driver to be unregistered * * Unregister an NTB client driver with the NTB transport layer * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -void ntb_unregister_client(struct ntb_client *drv) +void ntb_transport_unregister_client(struct ntb_client *drv) { driver_unregister(&drv->driver); } -EXPORT_SYMBOL_GPL(ntb_unregister_client); +EXPORT_SYMBOL_GPL(ntb_transport_unregister_client); static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) diff --git a/include/linux/ntb.h b/include/linux/ntb.h deleted file mode 100644 index 9ac1a62fc6f5..000000000000 --- a/include/linux/ntb.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * BSD LICENSE - * - * Copyright(c) 2012 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copy - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Intel PCIe NTB Linux driver - * - * Contact Information: - * Jon Mason - */ - -struct ntb_transport_qp; - -struct ntb_client { - struct device_driver driver; - int (*probe)(struct pci_dev *pdev); - void (*remove)(struct pci_dev *pdev); -}; - -enum { - NTB_LINK_DOWN = 0, - NTB_LINK_UP, -}; - -int ntb_register_client(struct ntb_client *drvr); -void ntb_unregister_client(struct ntb_client *drvr); -int ntb_register_client_dev(char *device_name); -void ntb_unregister_client_dev(char *device_name); - -struct ntb_queue_handlers { - void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, - void *data, int len); - void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data, - void *data, int len); - void (*event_handler)(void *data, int status); -}; - -unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp); -unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); -struct ntb_transport_qp * -ntb_transport_create_queue(void *data, struct pci_dev *pdev, - const struct ntb_queue_handlers *handlers); -void ntb_transport_free_queue(struct ntb_transport_qp *qp); -int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, - unsigned int len); -int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, - unsigned int len); -void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len); -void ntb_transport_link_up(struct ntb_transport_qp *qp); -void ntb_transport_link_down(struct ntb_transport_qp *qp); -bool ntb_transport_link_query(struct ntb_transport_qp *qp); diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h new file mode 100644 index 000000000000..f78b64cc09d5 --- /dev/null +++ b/include/linux/ntb_transport.h @@ -0,0 +1,88 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * BSD LICENSE + * + * Copyright(c) 2012 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Intel PCIe NTB Linux driver + * + * Contact Information: + * Jon Mason + */ + +struct ntb_transport_qp; + +struct ntb_client { + struct device_driver driver; + int (*probe)(struct pci_dev *pdev); + void (*remove)(struct pci_dev *pdev); +}; + +enum { + NTB_LINK_DOWN = 0, + NTB_LINK_UP, +}; + +int ntb_transport_register_client(struct ntb_client *drvr); +void ntb_transport_unregister_client(struct ntb_client *drvr); +int ntb_register_client_dev(char *device_name); +void ntb_unregister_client_dev(char *device_name); + +struct ntb_queue_handlers { + void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, + void *data, int len); + void (*tx_handler)(struct ntb_transport_qp *qp, void *qp_data, + void *data, int len); + void (*event_handler)(void *data, int status); +}; + +unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp); +unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); +struct ntb_transport_qp * +ntb_transport_create_queue(void *data, struct pci_dev *pdev, + const struct ntb_queue_handlers *handlers); +void ntb_transport_free_queue(struct ntb_transport_qp *qp); +int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, + unsigned int len); +int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, + unsigned int len); +void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len); +void ntb_transport_link_up(struct ntb_transport_qp *qp); +void ntb_transport_link_down(struct ntb_transport_qp *qp); +bool ntb_transport_link_query(struct ntb_transport_qp *qp); -- cgit v1.2.3 From a13f35e8714009145e32ebe2bf25b84e1376e314 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 2 Jul 2015 08:44:34 -0600 Subject: writeback: don't embed root bdi_writeback_congested in bdi_writeback 52ebea749aae ("writeback: make backing_dev_info host cgroup-specific bdi_writebacks") made bdi (backing_dev_info) host per-cgroup wb's (bdi_writeback's). As the congested state needs to be per-wb and referenced from blkcg side and multiple wbs, the patch made all non-root cong's (bdi_writeback_congested's) reference counted and indexed on bdi. When a bdi is destroyed, cgwb_bdi_destroy() tries to drain all non-root cong's; however, this can hang indefinitely because wb's can also be referenced from blkcg_gq's which are destroyed after bdi destruction is complete. To fix the bug, bdi destruction will be updated to not wait for cong's to drain, which naturally means that cong's may outlive the associated bdi. This is fine for non-root cong's but is problematic for the root cong's which are embedded in their bdi's as they may end up getting dereferenced after the containing bdi's are freed. This patch makes root cong's behave the same as non-root cong's. They are no longer embedded in their bdi's but allocated separately during bdi initialization, indexed and reference counted the same way. * As cong handling is the same for all wb's, wb->congested initialization is moved into wb_init(). * When !CONFIG_CGROUP_WRITEBACK, there was no indexing or refcnting. bdi->wb_congested is now a pointer pointing to the root cong allocated during bdi init and minimal refcnting operations are implemented. * The above makes root wb init paths diverge depending on CONFIG_CGROUP_WRITEBACK. root wb init is moved to cgwb_bdi_init(). This patch in itself shouldn't cause any consequential behavior differences but prepares for the actual fix. Signed-off-by: Tejun Heo Reported-by: Jon Christopherson Link: https://bugzilla.kernel.org/show_bug.cgi?id=100681 Tested-by: Jon Christopherson Added include to backing-dev.h for kfree() definition. Signed-off-by: Jens Axboe --- include/linux/backing-dev-defs.h | 5 ++- include/linux/backing-dev.h | 6 ++- mm/backing-dev.c | 87 +++++++++++++++++++++------------------- 3 files changed, 54 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index a48d90e3bcbb..a23209b43842 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -50,10 +50,10 @@ enum wb_stat_item { */ struct bdi_writeback_congested { unsigned long state; /* WB_[a]sync_congested flags */ + atomic_t refcnt; /* nr of attached wb's and blkg */ #ifdef CONFIG_CGROUP_WRITEBACK struct backing_dev_info *bdi; /* the associated bdi */ - atomic_t refcnt; /* nr of attached wb's and blkg */ int blkcg_id; /* ID of the associated blkcg */ struct rb_node rb_node; /* on bdi->cgwb_congestion_tree */ #endif @@ -150,11 +150,12 @@ struct backing_dev_info { atomic_long_t tot_write_bandwidth; struct bdi_writeback wb; /* the root writeback info for this bdi */ - struct bdi_writeback_congested wb_congested; /* its congested state */ #ifdef CONFIG_CGROUP_WRITEBACK struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */ struct rb_root cgwb_congested_tree; /* their congested states */ atomic_t usage_cnt; /* counts both cgwbs and cgwb_contested's */ +#else + struct bdi_writeback_congested *wb_congested; #endif wait_queue_head_t wb_waitq; diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 0e6d4828a77a..0fe9df983ab7 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -15,6 +15,7 @@ #include #include #include +#include int __must_check bdi_init(struct backing_dev_info *bdi); void bdi_destroy(struct backing_dev_info *bdi); @@ -465,11 +466,14 @@ static inline bool inode_cgwb_enabled(struct inode *inode) static inline struct bdi_writeback_congested * wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) { - return bdi->wb.congested; + atomic_inc(&bdi->wb_congested->refcnt); + return bdi->wb_congested; } static inline void wb_congested_put(struct bdi_writeback_congested *congested) { + if (atomic_dec_and_test(&congested->refcnt)) + kfree(congested); } static inline struct bdi_writeback *wb_find_current(struct backing_dev_info *bdi) diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 7756da31b02b..51cc461e7256 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -287,7 +287,7 @@ void wb_wakeup_delayed(struct bdi_writeback *wb) #define INIT_BW (100 << (20 - PAGE_SHIFT)) static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi, - gfp_t gfp) + int blkcg_id, gfp_t gfp) { int i, err; @@ -311,21 +311,29 @@ static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi, INIT_LIST_HEAD(&wb->work_list); INIT_DELAYED_WORK(&wb->dwork, wb_workfn); + wb->congested = wb_congested_get_create(bdi, blkcg_id, gfp); + if (!wb->congested) + return -ENOMEM; + err = fprop_local_init_percpu(&wb->completions, gfp); if (err) - return err; + goto out_put_cong; for (i = 0; i < NR_WB_STAT_ITEMS; i++) { err = percpu_counter_init(&wb->stat[i], 0, gfp); - if (err) { - while (--i) - percpu_counter_destroy(&wb->stat[i]); - fprop_local_destroy_percpu(&wb->completions); - return err; - } + if (err) + goto out_destroy_stat; } return 0; + +out_destroy_stat: + while (--i) + percpu_counter_destroy(&wb->stat[i]); + fprop_local_destroy_percpu(&wb->completions); +out_put_cong: + wb_congested_put(wb->congested); + return err; } /* @@ -361,6 +369,7 @@ static void wb_exit(struct bdi_writeback *wb) percpu_counter_destroy(&wb->stat[i]); fprop_local_destroy_percpu(&wb->completions); + wb_congested_put(wb->congested); } #ifdef CONFIG_CGROUP_WRITEBACK @@ -392,9 +401,6 @@ wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) struct bdi_writeback_congested *new_congested = NULL, *congested; struct rb_node **node, *parent; unsigned long flags; - - if (blkcg_id == 1) - return &bdi->wb_congested; retry: spin_lock_irqsave(&cgwb_lock, flags); @@ -453,9 +459,6 @@ void wb_congested_put(struct bdi_writeback_congested *congested) struct backing_dev_info *bdi = congested->bdi; unsigned long flags; - if (congested->blkcg_id == 1) - return; - local_irq_save(flags); if (!atomic_dec_and_lock(&congested->refcnt, &cgwb_lock)) { local_irq_restore(flags); @@ -480,7 +483,6 @@ static void cgwb_release_workfn(struct work_struct *work) css_put(wb->memcg_css); css_put(wb->blkcg_css); - wb_congested_put(wb->congested); fprop_local_destroy_percpu(&wb->memcg_completions); percpu_ref_exit(&wb->refcnt); @@ -541,7 +543,7 @@ static int cgwb_create(struct backing_dev_info *bdi, if (!wb) return -ENOMEM; - ret = wb_init(wb, bdi, gfp); + ret = wb_init(wb, bdi, blkcg_css->id, gfp); if (ret) goto err_free; @@ -553,12 +555,6 @@ static int cgwb_create(struct backing_dev_info *bdi, if (ret) goto err_ref_exit; - wb->congested = wb_congested_get_create(bdi, blkcg_css->id, gfp); - if (!wb->congested) { - ret = -ENOMEM; - goto err_fprop_exit; - } - wb->memcg_css = memcg_css; wb->blkcg_css = blkcg_css; INIT_WORK(&wb->release_work, cgwb_release_workfn); @@ -588,12 +584,10 @@ static int cgwb_create(struct backing_dev_info *bdi, if (ret) { if (ret == -EEXIST) ret = 0; - goto err_put_congested; + goto err_fprop_exit; } goto out_put; -err_put_congested: - wb_congested_put(wb->congested); err_fprop_exit: fprop_local_destroy_percpu(&wb->memcg_completions); err_ref_exit: @@ -662,14 +656,20 @@ struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, return wb; } -static void cgwb_bdi_init(struct backing_dev_info *bdi) +static int cgwb_bdi_init(struct backing_dev_info *bdi) { - bdi->wb.memcg_css = mem_cgroup_root_css; - bdi->wb.blkcg_css = blkcg_root_css; - bdi->wb_congested.blkcg_id = 1; + int ret; + INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC); bdi->cgwb_congested_tree = RB_ROOT; atomic_set(&bdi->usage_cnt, 1); + + ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); + if (!ret) { + bdi->wb.memcg_css = mem_cgroup_root_css; + bdi->wb.blkcg_css = blkcg_root_css; + } + return ret; } static void cgwb_bdi_destroy(struct backing_dev_info *bdi) @@ -732,15 +732,28 @@ void wb_blkcg_offline(struct blkcg *blkcg) #else /* CONFIG_CGROUP_WRITEBACK */ -static void cgwb_bdi_init(struct backing_dev_info *bdi) { } +static int cgwb_bdi_init(struct backing_dev_info *bdi) +{ + int err; + + bdi->wb_congested = kzalloc(sizeof(*bdi->wb_congested), GFP_KERNEL); + if (!bdi->wb_congested) + return -ENOMEM; + + err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); + if (err) { + kfree(bdi->wb_congested); + return err; + } + return 0; +} + static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { } #endif /* CONFIG_CGROUP_WRITEBACK */ int bdi_init(struct backing_dev_info *bdi) { - int err; - bdi->dev = NULL; bdi->min_ratio = 0; @@ -749,15 +762,7 @@ int bdi_init(struct backing_dev_info *bdi) INIT_LIST_HEAD(&bdi->bdi_list); init_waitqueue_head(&bdi->wb_waitq); - err = wb_init(&bdi->wb, bdi, GFP_KERNEL); - if (err) - return err; - - bdi->wb_congested.state = 0; - bdi->wb.congested = &bdi->wb_congested; - - cgwb_bdi_init(bdi); - return 0; + return cgwb_bdi_init(bdi); } EXPORT_SYMBOL(bdi_init); -- cgit v1.2.3 From 91e20b5040c67c51aad88cf87db4305c5bd7f79d Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Thu, 2 Jul 2015 15:32:00 -0400 Subject: irqchip: Move IRQCHIP_DECLARE macro to include/linux/irqchip.h At the moment the IRQCHIP_DECLARE macro is only declared locally in drivers/irqchip/irqchip.h. It prevents from using it directly in arch/* directories whenever irqchip drivers only exist there, which happens in a few cases (e.g. arc, arm, microblaze and mips). This patch makes the macro to be globally defined, i.e. in include/linux/irqchip.h, and thus usable for arch-specific declarations of irqchip drivers. In this way, it is very similar to what clocksource does (ie CLOCKSOURCE_OF_DECLARE is defined in include/linux/clocksource.h). For now, this patch only moves the declaration of the macro IRQCHIP_DECLARE to the global header 'include/linux/irqchip.h' and make 'drivers/irqchip/irqchip.h' include 'include/linux/irqchip.h'. Later, other patches will get rid of 'drivers/irqchip/irqchip.h' and modify all the impacted irqchip drivers. Signed-off-by: Joel Porquet Cc: Jason Cooper Link: http://lkml.kernel.org/r/1435865565-14114-1-git-send-email-joel@porquet.org Signed-off-by: Thomas Gleixner --- drivers/irqchip/irqchip.h | 19 +------------------ include/linux/irqchip.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h index 0f6486d4f1b0..0f67ae32464f 100644 --- a/drivers/irqchip/irqchip.h +++ b/drivers/irqchip/irqchip.h @@ -8,21 +8,4 @@ * warranty of any kind, whether express or implied. */ -#ifndef _IRQCHIP_H -#define _IRQCHIP_H - -#include - -/* - * This macro must be used by the different irqchip drivers to declare - * the association between their DT compatible string and their - * initialization function. - * - * @name: name that must be unique accross all IRQCHIP_DECLARE of the - * same file. - * @compstr: compatible string of the irqchip driver - * @fn: initialization function - */ -#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) - -#endif +#include diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index 14d79131f53d..638887376e58 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -11,6 +11,20 @@ #ifndef _LINUX_IRQCHIP_H #define _LINUX_IRQCHIP_H +#include + +/* + * This macro must be used by the different irqchip drivers to declare + * the association between their DT compatible string and their + * initialization function. + * + * @name: name that must be unique accross all IRQCHIP_DECLARE of the + * same file. + * @compstr: compatible string of the irqchip driver + * @fn: initialization function + */ +#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn) + #ifdef CONFIG_IRQCHIP void irqchip_init(void); #else -- cgit v1.2.3 From 2ecd9d29abb171d6e97a4f3eb29d7456a11401b7 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 3 Jul 2015 18:53:58 +0200 Subject: sched, preempt_notifier: separate notifier registration from static_key inc/dec Commit 1cde2930e154 ("sched/preempt: Add static_key() to preempt_notifiers") had two problems. First, the preempt-notifier API needs to sleep with the addition of the static_key, we do however need to hold off preemption while modifying the preempt notifier list, otherwise a preemption could observe an inconsistent list state. KVM correctly registers and unregisters preempt notifiers with preemption disabled, so the sleep caused dmesg splats. Second, KVM registers and unregisters preemption notifiers very often (in vcpu_load/vcpu_put). With a single uniprocessor guest the static key would move between 0 and 1 continuously, hitting the slow path on every userspace exit. To fix this, wrap the static_key inc/dec in a new API, and call it from KVM. Fixes: 1cde2930e154 ("sched/preempt: Add static_key() to preempt_notifiers") Reported-by: Pontus Fuchs Reported-by: Takashi Iwai Tested-by: Takashi Iwai Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Paolo Bonzini --- include/linux/preempt.h | 2 ++ kernel/sched/core.c | 17 +++++++++++++++-- virt/kvm/kvm_main.c | 3 +++ 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/preempt.h b/include/linux/preempt.h index 0f1534acaf60..84991f185173 100644 --- a/include/linux/preempt.h +++ b/include/linux/preempt.h @@ -293,6 +293,8 @@ struct preempt_notifier { struct preempt_ops *ops; }; +void preempt_notifier_inc(void); +void preempt_notifier_dec(void); void preempt_notifier_register(struct preempt_notifier *notifier); void preempt_notifier_unregister(struct preempt_notifier *notifier); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b803e1b8ab0c..552710ab19e0 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2320,13 +2320,27 @@ void wake_up_new_task(struct task_struct *p) static struct static_key preempt_notifier_key = STATIC_KEY_INIT_FALSE; +void preempt_notifier_inc(void) +{ + static_key_slow_inc(&preempt_notifier_key); +} +EXPORT_SYMBOL_GPL(preempt_notifier_inc); + +void preempt_notifier_dec(void) +{ + static_key_slow_dec(&preempt_notifier_key); +} +EXPORT_SYMBOL_GPL(preempt_notifier_dec); + /** * preempt_notifier_register - tell me when current is being preempted & rescheduled * @notifier: notifier struct to register */ void preempt_notifier_register(struct preempt_notifier *notifier) { - static_key_slow_inc(&preempt_notifier_key); + if (!static_key_false(&preempt_notifier_key)) + WARN(1, "registering preempt_notifier while notifiers disabled\n"); + hlist_add_head(¬ifier->link, ¤t->preempt_notifiers); } EXPORT_SYMBOL_GPL(preempt_notifier_register); @@ -2340,7 +2354,6 @@ EXPORT_SYMBOL_GPL(preempt_notifier_register); void preempt_notifier_unregister(struct preempt_notifier *notifier) { hlist_del(¬ifier->link); - static_key_slow_dec(&preempt_notifier_key); } EXPORT_SYMBOL_GPL(preempt_notifier_unregister); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 848af90b8091..8b8a44453670 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -553,6 +553,8 @@ static struct kvm *kvm_create_vm(unsigned long type) list_add(&kvm->vm_list, &vm_list); spin_unlock(&kvm_lock); + preempt_notifier_inc(); + return kvm; out_err: @@ -620,6 +622,7 @@ static void kvm_destroy_vm(struct kvm *kvm) cleanup_srcu_struct(&kvm->irq_srcu); cleanup_srcu_struct(&kvm->srcu); kvm_arch_free_vm(kvm); + preempt_notifier_dec(); hardware_disable_all(); mmdrop(mm); } -- cgit v1.2.3 From f6db8347993256b58bd4746b0c4c5b935c32210d Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Thu, 25 Jun 2015 23:53:37 +0530 Subject: sched/stat: Simplify the sched_info accounting dependency Both CONFIG_SCHEDSTATS=y and CONFIG_TASK_DELAY_ACCT=y track task sched_info, which results in ugly #if clauses. Simplify the code by introducing a synthethic CONFIG_SCHED_INFO switch, selected by both. Signed-off-by: Naveen N. Rao Cc: Balbir Singh Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Srikar Dronamraju Cc: Thomas Gleixner Cc: a.p.zijlstra@chello.nl Cc: ricklind@us.ibm.com Link: http://lkml.kernel.org/r/8d19eef800811a94b0f91bcbeb27430a884d7433.1435255405.git.naveen.n.rao@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- include/linux/sched.h | 6 +++--- init/Kconfig | 1 + kernel/sched/core.c | 2 +- kernel/sched/stats.h | 4 ++-- lib/Kconfig.debug | 5 +++++ 5 files changed, 12 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6633e83e608a..9bf4bc0e3b8b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -849,7 +849,7 @@ extern struct user_struct root_user; struct backing_dev_info; struct reclaim_state; -#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) +#ifdef CONFIG_SCHED_INFO struct sched_info { /* cumulative counters */ unsigned long pcount; /* # of times run on this cpu */ @@ -859,7 +859,7 @@ struct sched_info { unsigned long long last_arrival,/* when we last ran on a cpu */ last_queued; /* when we were last queued to run */ }; -#endif /* defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) */ +#endif /* CONFIG_SCHED_INFO */ #ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info { @@ -1408,7 +1408,7 @@ struct task_struct { int rcu_tasks_idle_cpu; #endif /* #ifdef CONFIG_TASKS_RCU */ -#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) +#ifdef CONFIG_SCHED_INFO struct sched_info sched_info; #endif diff --git a/init/Kconfig b/init/Kconfig index b999fa381bf9..12cb556ad160 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -435,6 +435,7 @@ config TASKSTATS config TASK_DELAY_ACCT bool "Enable per-task delay accounting" depends on TASKSTATS + select SCHED_INFO help Collect information on time spent by a task waiting for system resources like cpu, synchronous block I/O completion and swapping diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c86935a7f1f8..abb8785ed1ba 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1975,7 +1975,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) set_task_cpu(p, cpu); raw_spin_unlock_irqrestore(&p->pi_lock, flags); -#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) +#ifdef CONFIG_SCHED_INFO if (likely(sched_info_on())) memset(&p->sched_info, 0, sizeof(p->sched_info)); #endif diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h index 077ebbd5e10f..b0fbc7632de5 100644 --- a/kernel/sched/stats.h +++ b/kernel/sched/stats.h @@ -47,7 +47,7 @@ rq_sched_info_depart(struct rq *rq, unsigned long long delta) # define schedstat_set(var, val) do { } while (0) #endif -#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) +#ifdef CONFIG_SCHED_INFO static inline void sched_info_reset_dequeued(struct task_struct *t) { t->sched_info.last_queued = 0; @@ -156,7 +156,7 @@ sched_info_switch(struct rq *rq, #define sched_info_depart(rq, t) do { } while (0) #define sched_info_arrive(rq, next) do { } while (0) #define sched_info_switch(rq, t, next) do { } while (0) -#endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */ +#endif /* CONFIG_SCHED_INFO */ /* * The following are functions that support scheduler-internal time accounting. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b908048f8d6a..e2894b23efb6 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -841,9 +841,14 @@ config SCHED_DEBUG that can help debug the scheduler. The runtime overhead of this option is minimal. +config SCHED_INFO + bool + default n + config SCHEDSTATS bool "Collect scheduler statistics" depends on DEBUG_KERNEL && PROC_FS + select SCHED_INFO help If you say Y here, additional code will be inserted into the scheduler and related routines to collect statistics about -- cgit v1.2.3 From 6b55c9654fccf69ae7ace23ca101dc37b903181b Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Thu, 25 Jun 2015 22:51:41 +0530 Subject: sched/debug: Move print_cfs_rq() declaration to kernel/sched/sched.h Currently print_cfs_rq() is declared in include/linux/sched.h. However it's not used outside kernel/sched. Hence move the declaration to kernel/sched/sched.h Also some functions are only available for CONFIG_SCHED_DEBUG=y. Hence move the declarations to within the #ifdef. Signed-off-by: Srikar Dronamraju Acked-by: Rik van Riel Cc: Iulia Manda Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1435252903-1081-2-git-send-email-srikar@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- include/linux/sched.h | 2 -- kernel/sched/sched.h | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 9bf4bc0e3b8b..3505352dd296 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -191,8 +191,6 @@ struct task_group; #ifdef CONFIG_SCHED_DEBUG extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m); extern void proc_sched_set_task(struct task_struct *p); -extern void -print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq); #endif /* diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index aea7c1f393cb..7d5895258fe3 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1668,9 +1668,14 @@ static inline void double_rq_unlock(struct rq *rq1, struct rq *rq2) extern struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq); extern struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq); + +#ifdef CONFIG_SCHED_DEBUG extern void print_cfs_stats(struct seq_file *m, int cpu); extern void print_rt_stats(struct seq_file *m, int cpu); extern void print_dl_stats(struct seq_file *m, int cpu); +extern void +print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq); +#endif extern void init_cfs_rq(struct cfs_rq *cfs_rq); extern void init_rt_rq(struct rt_rq *rt_rq); -- cgit v1.2.3 From a1bd3baeb2f18b2b3d0f98ce5fdaa725149b950b Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 9 Apr 2015 10:33:20 -0400 Subject: NTB: Add NTB hardware abstraction layer Abstract the NTB device behind a programming interface, so that it can support different hardware and client drivers. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 32 ++ MAINTAINERS | 4 +- drivers/ntb/Makefile | 1 + drivers/ntb/ntb.c | 251 +++++++++++++ include/linux/ntb.h | 984 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1271 insertions(+), 1 deletion(-) create mode 100644 Documentation/ntb.txt create mode 100644 drivers/ntb/ntb.c create mode 100644 include/linux/ntb.h (limited to 'include') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt new file mode 100644 index 000000000000..9d46dc9712a8 --- /dev/null +++ b/Documentation/ntb.txt @@ -0,0 +1,32 @@ +# NTB Drivers + +NTB (Non-Transparent Bridge) is a type of PCI-Express bridge chip that connects +the separate memory systems of two computers to the same PCI-Express fabric. +Existing NTB hardware supports a common feature set, including scratchpad +registers, doorbell registers, and memory translation windows. Scratchpad +registers are read-and-writable registers that are accessible from either side +of the device, so that peers can exchange a small amount of information at a +fixed address. Doorbell registers provide a way for peers to send interrupt +events. Memory windows allow translated read and write access to the peer +memory. + +## NTB Core Driver (ntb) + +The NTB core driver defines an api wrapping the common feature set, and allows +clients interested in NTB features to discover NTB the devices supported by +hardware drivers. The term "client" is used here to mean an upper layer +component making use of the NTB api. The term "driver," or "hardware driver," +is used here to mean a driver for a specific vendor and model of NTB hardware. + +## NTB Client Drivers + +NTB client drivers should register with the NTB core driver. After +registering, the client probe and remove functions will be called appropriately +as ntb hardware, or hardware drivers, are inserted and removed. The +registration uses the Linux Device framework, so it should feel familiar to +anyone who has written a pci driver. + +## NTB Hardware Drivers + +NTB hardware drivers should register devices with the NTB core driver. After +registering, clients probe and remove functions will be called. diff --git a/MAINTAINERS b/MAINTAINERS index 663bc8ed1860..e2fc9eec2e16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6995,15 +6995,17 @@ F: drivers/power/bq27x00_battery.c F: drivers/power/isp1704_charger.c F: drivers/power/rx51_battery.c -NTB DRIVER +NTB DRIVER CORE M: Jon Mason M: Dave Jiang +M: Allen Hubbe S: Supported W: https://github.com/jonmason/ntb/wiki T: git git://github.com/jonmason/ntb.git F: drivers/ntb/ F: drivers/net/ntb_netdev.c F: include/linux/ntb.h +F: include/linux/ntb_transport.h NTFS FILESYSTEM M: Anton Altaparmakov diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index 545b10a131af..712e953a8fda 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_NTB) += ntb.o obj-$(CONFIG_NTB) += ntb_hw_intel.o ntb_hw_intel-objs := hw/intel/ntb_hw_intel.o ntb_transport.o diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c new file mode 100644 index 000000000000..23435f2a5486 --- /dev/null +++ b/drivers/ntb/ntb.c @@ -0,0 +1,251 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * PCIe NTB Linux driver + * + * Contact Information: + * Allen Hubbe + */ + +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "ntb" +#define DRIVER_DESCRIPTION "PCIe NTB Driver Framework" + +#define DRIVER_LICENSE "Dual BSD/GPL" +#define DRIVER_VERSION "1.0" +#define DRIVER_RELDATE "24 March 2015" +#define DRIVER_AUTHOR "Allen Hubbe " + +MODULE_LICENSE(DRIVER_LICENSE); +MODULE_VERSION(DRIVER_VERSION); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); + +static struct bus_type ntb_bus; +static void ntb_dev_release(struct device *dev); + +int __ntb_register_client(struct ntb_client *client, struct module *mod, + const char *mod_name) +{ + if (!client) + return -EINVAL; + if (!ntb_client_ops_is_valid(&client->ops)) + return -EINVAL; + + memset(&client->drv, 0, sizeof(client->drv)); + client->drv.bus = &ntb_bus; + client->drv.name = mod_name; + client->drv.owner = mod; + + return driver_register(&client->drv); +} +EXPORT_SYMBOL(__ntb_register_client); + +void ntb_unregister_client(struct ntb_client *client) +{ + driver_unregister(&client->drv); +} +EXPORT_SYMBOL(ntb_unregister_client); + +int ntb_register_device(struct ntb_dev *ntb) +{ + if (!ntb) + return -EINVAL; + if (!ntb->pdev) + return -EINVAL; + if (!ntb->ops) + return -EINVAL; + if (!ntb_dev_ops_is_valid(ntb->ops)) + return -EINVAL; + + init_completion(&ntb->released); + + memset(&ntb->dev, 0, sizeof(ntb->dev)); + ntb->dev.bus = &ntb_bus; + ntb->dev.parent = &ntb->pdev->dev; + ntb->dev.release = ntb_dev_release; + dev_set_name(&ntb->dev, pci_name(ntb->pdev)); + + ntb->ctx = NULL; + ntb->ctx_ops = NULL; + spin_lock_init(&ntb->ctx_lock); + + return device_register(&ntb->dev); +} +EXPORT_SYMBOL(ntb_register_device); + +void ntb_unregister_device(struct ntb_dev *ntb) +{ + device_unregister(&ntb->dev); + wait_for_completion(&ntb->released); +} +EXPORT_SYMBOL(ntb_unregister_device); + +int ntb_set_ctx(struct ntb_dev *ntb, void *ctx, + const struct ntb_ctx_ops *ctx_ops) +{ + unsigned long irqflags; + + if (!ntb_ctx_ops_is_valid(ctx_ops)) + return -EINVAL; + if (ntb->ctx_ops) + return -EINVAL; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + ntb->ctx = ctx; + ntb->ctx_ops = ctx_ops; + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); + + return 0; +} +EXPORT_SYMBOL(ntb_set_ctx); + +void ntb_clear_ctx(struct ntb_dev *ntb) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + ntb->ctx_ops = NULL; + ntb->ctx = NULL; + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); +} +EXPORT_SYMBOL(ntb_clear_ctx); + +void ntb_link_event(struct ntb_dev *ntb) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + if (ntb->ctx_ops && ntb->ctx_ops->link_event) + ntb->ctx_ops->link_event(ntb->ctx); + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); +} +EXPORT_SYMBOL(ntb_link_event); + +void ntb_db_event(struct ntb_dev *ntb, int vector) +{ + unsigned long irqflags; + + spin_lock_irqsave(&ntb->ctx_lock, irqflags); + { + if (ntb->ctx_ops && ntb->ctx_ops->db_event) + ntb->ctx_ops->db_event(ntb->ctx, vector); + } + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); +} +EXPORT_SYMBOL(ntb_db_event); + +static int ntb_probe(struct device *dev) +{ + struct ntb_dev *ntb; + struct ntb_client *client; + int rc; + + get_device(dev); + ntb = dev_ntb(dev); + client = drv_ntb_client(dev->driver); + + rc = client->ops.probe(client, ntb); + if (rc) + put_device(dev); + + return rc; +} + +static int ntb_remove(struct device *dev) +{ + struct ntb_dev *ntb; + struct ntb_client *client; + + if (dev->driver) { + ntb = dev_ntb(dev); + client = drv_ntb_client(dev->driver); + + client->ops.remove(client, ntb); + put_device(dev); + } + + return 0; +} + +static void ntb_dev_release(struct device *dev) +{ + struct ntb_dev *ntb = dev_ntb(dev); + + complete(&ntb->released); +} + +static struct bus_type ntb_bus = { + .name = "ntb", + .probe = ntb_probe, + .remove = ntb_remove, +}; + +static int __init ntb_driver_init(void) +{ + return bus_register(&ntb_bus); +} +module_init(ntb_driver_init); + +static void __exit ntb_driver_exit(void) +{ + bus_unregister(&ntb_bus); +} +module_exit(ntb_driver_exit); + diff --git a/include/linux/ntb.h b/include/linux/ntb.h new file mode 100644 index 000000000000..b02f72bb8e32 --- /dev/null +++ b/include/linux/ntb.h @@ -0,0 +1,984 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copy + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * PCIe NTB Linux driver + * + * Contact Information: + * Allen Hubbe + */ + +#ifndef _NTB_H_ +#define _NTB_H_ + +#include +#include + +struct ntb_client; +struct ntb_dev; +struct pci_dev; + +/** + * enum ntb_topo - NTB connection topology + * @NTB_TOPO_NONE: Topology is unknown or invalid. + * @NTB_TOPO_PRI: On primary side of local ntb. + * @NTB_TOPO_SEC: On secondary side of remote ntb. + * @NTB_TOPO_B2B_USD: On primary side of local ntb upstream of remote ntb. + * @NTB_TOPO_B2B_DSD: On primary side of local ntb downstream of remote ntb. + */ +enum ntb_topo { + NTB_TOPO_NONE = -1, + NTB_TOPO_PRI, + NTB_TOPO_SEC, + NTB_TOPO_B2B_USD, + NTB_TOPO_B2B_DSD, +}; + +static inline int ntb_topo_is_b2b(enum ntb_topo topo) +{ + switch ((int)topo) { + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + return 1; + } + return 0; +} + +static inline char *ntb_topo_string(enum ntb_topo topo) +{ + switch (topo) { + case NTB_TOPO_NONE: return "NTB_TOPO_NONE"; + case NTB_TOPO_PRI: return "NTB_TOPO_PRI"; + case NTB_TOPO_SEC: return "NTB_TOPO_SEC"; + case NTB_TOPO_B2B_USD: return "NTB_TOPO_B2B_USD"; + case NTB_TOPO_B2B_DSD: return "NTB_TOPO_B2B_DSD"; + } + return "NTB_TOPO_INVALID"; +} + +/** + * enum ntb_speed - NTB link training speed + * @NTB_SPEED_AUTO: Request the max supported speed. + * @NTB_SPEED_NONE: Link is not trained to any speed. + * @NTB_SPEED_GEN1: Link is trained to gen1 speed. + * @NTB_SPEED_GEN2: Link is trained to gen2 speed. + * @NTB_SPEED_GEN3: Link is trained to gen3 speed. + */ +enum ntb_speed { + NTB_SPEED_AUTO = -1, + NTB_SPEED_NONE = 0, + NTB_SPEED_GEN1 = 1, + NTB_SPEED_GEN2 = 2, + NTB_SPEED_GEN3 = 3, +}; + +/** + * enum ntb_width - NTB link training width + * @NTB_WIDTH_AUTO: Request the max supported width. + * @NTB_WIDTH_NONE: Link is not trained to any width. + * @NTB_WIDTH_1: Link is trained to 1 lane width. + * @NTB_WIDTH_2: Link is trained to 2 lane width. + * @NTB_WIDTH_4: Link is trained to 4 lane width. + * @NTB_WIDTH_8: Link is trained to 8 lane width. + * @NTB_WIDTH_12: Link is trained to 12 lane width. + * @NTB_WIDTH_16: Link is trained to 16 lane width. + * @NTB_WIDTH_32: Link is trained to 32 lane width. + */ +enum ntb_width { + NTB_WIDTH_AUTO = -1, + NTB_WIDTH_NONE = 0, + NTB_WIDTH_1 = 1, + NTB_WIDTH_2 = 2, + NTB_WIDTH_4 = 4, + NTB_WIDTH_8 = 8, + NTB_WIDTH_12 = 12, + NTB_WIDTH_16 = 16, + NTB_WIDTH_32 = 32, +}; + +/** + * struct ntb_client_ops - ntb client operations + * @probe: Notify client of a new device. + * @remove: Notify client to remove a device. + */ +struct ntb_client_ops { + int (*probe)(struct ntb_client *client, struct ntb_dev *ntb); + void (*remove)(struct ntb_client *client, struct ntb_dev *ntb); +}; + +static inline int ntb_client_ops_is_valid(const struct ntb_client_ops *ops) +{ + /* commented callbacks are not required: */ + return + ops->probe && + ops->remove && + 1; +} + +/** + * struct ntb_ctx_ops - ntb driver context operations + * @link_event: See ntb_link_event(). + * @db_event: See ntb_db_event(). + */ +struct ntb_ctx_ops { + void (*link_event)(void *ctx); + void (*db_event)(void *ctx, int db_vector); +}; + +static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) +{ + /* commented callbacks are not required: */ + return + /* ops->link_event && */ + /* ops->db_event && */ + 1; +} + +/** + * struct ntb_ctx_ops - ntb device operations + * @mw_count: See ntb_mw_count(). + * @mw_get_range: See ntb_mw_get_range(). + * @mw_set_trans: See ntb_mw_set_trans(). + * @mw_clear_trans: See ntb_mw_clear_trans(). + * @link_is_up: See ntb_link_is_up(). + * @link_enable: See ntb_link_enable(). + * @link_disable: See ntb_link_disable(). + * @db_is_unsafe: See ntb_db_is_unsafe(). + * @db_valid_mask: See ntb_db_valid_mask(). + * @db_vector_count: See ntb_db_vector_count(). + * @db_vector_mask: See ntb_db_vector_mask(). + * @db_read: See ntb_db_read(). + * @db_set: See ntb_db_set(). + * @db_clear: See ntb_db_clear(). + * @db_read_mask: See ntb_db_read_mask(). + * @db_set_mask: See ntb_db_set_mask(). + * @db_clear_mask: See ntb_db_clear_mask(). + * @peer_db_addr: See ntb_peer_db_addr(). + * @peer_db_read: See ntb_peer_db_read(). + * @peer_db_set: See ntb_peer_db_set(). + * @peer_db_clear: See ntb_peer_db_clear(). + * @peer_db_read_mask: See ntb_peer_db_read_mask(). + * @peer_db_set_mask: See ntb_peer_db_set_mask(). + * @peer_db_clear_mask: See ntb_peer_db_clear_mask(). + * @spad_is_unsafe: See ntb_spad_is_unsafe(). + * @spad_count: See ntb_spad_count(). + * @spad_read: See ntb_spad_read(). + * @spad_write: See ntb_spad_write(). + * @peer_spad_addr: See ntb_peer_spad_addr(). + * @peer_spad_read: See ntb_peer_spad_read(). + * @peer_spad_write: See ntb_peer_spad_write(). + */ +struct ntb_dev_ops { + int (*mw_count)(struct ntb_dev *ntb); + int (*mw_get_range)(struct ntb_dev *ntb, int idx, + phys_addr_t *base, resource_size_t *size, + resource_size_t *align, resource_size_t *align_size); + int (*mw_set_trans)(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size); + int (*mw_clear_trans)(struct ntb_dev *ntb, int idx); + + int (*link_is_up)(struct ntb_dev *ntb, + enum ntb_speed *speed, enum ntb_width *width); + int (*link_enable)(struct ntb_dev *ntb, + enum ntb_speed max_speed, enum ntb_width max_width); + int (*link_disable)(struct ntb_dev *ntb); + + int (*db_is_unsafe)(struct ntb_dev *ntb); + u64 (*db_valid_mask)(struct ntb_dev *ntb); + int (*db_vector_count)(struct ntb_dev *ntb); + u64 (*db_vector_mask)(struct ntb_dev *ntb, int db_vector); + + u64 (*db_read)(struct ntb_dev *ntb); + int (*db_set)(struct ntb_dev *ntb, u64 db_bits); + int (*db_clear)(struct ntb_dev *ntb, u64 db_bits); + + u64 (*db_read_mask)(struct ntb_dev *ntb); + int (*db_set_mask)(struct ntb_dev *ntb, u64 db_bits); + int (*db_clear_mask)(struct ntb_dev *ntb, u64 db_bits); + + int (*peer_db_addr)(struct ntb_dev *ntb, + phys_addr_t *db_addr, resource_size_t *db_size); + u64 (*peer_db_read)(struct ntb_dev *ntb); + int (*peer_db_set)(struct ntb_dev *ntb, u64 db_bits); + int (*peer_db_clear)(struct ntb_dev *ntb, u64 db_bits); + + u64 (*peer_db_read_mask)(struct ntb_dev *ntb); + int (*peer_db_set_mask)(struct ntb_dev *ntb, u64 db_bits); + int (*peer_db_clear_mask)(struct ntb_dev *ntb, u64 db_bits); + + int (*spad_is_unsafe)(struct ntb_dev *ntb); + int (*spad_count)(struct ntb_dev *ntb); + + u32 (*spad_read)(struct ntb_dev *ntb, int idx); + int (*spad_write)(struct ntb_dev *ntb, int idx, u32 val); + + int (*peer_spad_addr)(struct ntb_dev *ntb, int idx, + phys_addr_t *spad_addr); + u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx); + int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val); +}; + +static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops) +{ + /* commented callbacks are not required: */ + return + ops->mw_count && + ops->mw_get_range && + ops->mw_set_trans && + /* ops->mw_clear_trans && */ + ops->link_is_up && + ops->link_enable && + ops->link_disable && + /* ops->db_is_unsafe && */ + ops->db_valid_mask && + + /* both set, or both unset */ + (!ops->db_vector_count == !ops->db_vector_mask) && + + ops->db_read && + /* ops->db_set && */ + ops->db_clear && + /* ops->db_read_mask && */ + ops->db_set_mask && + ops->db_clear_mask && + ops->peer_db_addr && + /* ops->peer_db_read && */ + ops->peer_db_set && + /* ops->peer_db_clear && */ + /* ops->peer_db_read_mask && */ + /* ops->peer_db_set_mask && */ + /* ops->peer_db_clear_mask && */ + /* ops->spad_is_unsafe && */ + ops->spad_count && + ops->spad_read && + ops->spad_write && + ops->peer_spad_addr && + /* ops->peer_spad_read && */ + ops->peer_spad_write && + 1; +} + +/** + * struct ntb_client - client interested in ntb devices + * @drv: Linux driver object. + * @ops: See &ntb_client_ops. + */ +struct ntb_client { + struct device_driver drv; + const struct ntb_client_ops ops; +}; + +#define drv_ntb_client(__drv) container_of((__drv), struct ntb_client, drv) + +/** + * struct ntb_device - ntb device + * @dev: Linux device object. + * @pdev: Pci device entry of the ntb. + * @topo: Detected topology of the ntb. + * @ops: See &ntb_dev_ops. + * @ctx: See &ntb_ctx_ops. + * @ctx_ops: See &ntb_ctx_ops. + */ +struct ntb_dev { + struct device dev; + struct pci_dev *pdev; + enum ntb_topo topo; + const struct ntb_dev_ops *ops; + void *ctx; + const struct ntb_ctx_ops *ctx_ops; + + /* private: */ + + /* synchronize setting, clearing, and calling ctx_ops */ + spinlock_t ctx_lock; + /* block unregister until device is fully released */ + struct completion released; +}; + +#define dev_ntb(__dev) container_of((__dev), struct ntb_dev, dev) + +/** + * ntb_register_client() - register a client for interest in ntb devices + * @client: Client context. + * + * The client will be added to the list of clients interested in ntb devices. + * The client will be notified of any ntb devices that are not already + * associated with a client, or if ntb devices are registered later. + * + * Return: Zero if the client is registered, otherwise an error number. + */ +#define ntb_register_client(client) \ + __ntb_register_client((client), THIS_MODULE, KBUILD_MODNAME) + +int __ntb_register_client(struct ntb_client *client, struct module *mod, + const char *mod_name); + +/** + * ntb_unregister_client() - unregister a client for interest in ntb devices + * @client: Client context. + * + * The client will be removed from the list of clients interested in ntb + * devices. If any ntb devices are associated with the client, the client will + * be notified to remove those devices. + */ +void ntb_unregister_client(struct ntb_client *client); + +#define module_ntb_client(__ntb_client) \ + module_driver(__ntb_client, ntb_register_client, \ + ntb_unregister_client) + +/** + * ntb_register_device() - register a ntb device + * @ntb: NTB device context. + * + * The device will be added to the list of ntb devices. If any clients are + * interested in ntb devices, each client will be notified of the ntb device, + * until at most one client accepts the device. + * + * Return: Zero if the device is registered, otherwise an error number. + */ +int ntb_register_device(struct ntb_dev *ntb); + +/** + * ntb_register_device() - unregister a ntb device + * @ntb: NTB device context. + * + * The device will be removed from the list of ntb devices. If the ntb device + * is associated with a client, the client will be notified to remove the + * device. + */ +void ntb_unregister_device(struct ntb_dev *ntb); + +/** + * ntb_set_ctx() - associate a driver context with an ntb device + * @ntb: NTB device context. + * @ctx: Driver context. + * @ctx_ops: Driver context operations. + * + * Associate a driver context and operations with a ntb device. The context is + * provided by the client driver, and the driver may associate a different + * context with each ntb device. + * + * Return: Zero if the context is associated, otherwise an error number. + */ +int ntb_set_ctx(struct ntb_dev *ntb, void *ctx, + const struct ntb_ctx_ops *ctx_ops); + +/** + * ntb_clear_ctx() - disassociate any driver context from an ntb device + * @ntb: NTB device context. + * + * Clear any association that may exist between a driver context and the ntb + * device. + */ +void ntb_clear_ctx(struct ntb_dev *ntb); + +/** + * ntb_link_event() - notify driver context of a change in link status + * @ntb: NTB device context. + * + * Notify the driver context that the link status may have changed. The driver + * should call ntb_link_is_up() to get the current status. + */ +void ntb_link_event(struct ntb_dev *ntb); + +/** + * ntb_db_event() - notify driver context of a doorbell event + * @ntb: NTB device context. + * @vector: Interrupt vector number. + * + * Notify the driver context of a doorbell event. If hardware supports + * multiple interrupt vectors for doorbells, the vector number indicates which + * vector received the interrupt. The vector number is relative to the first + * vector used for doorbells, starting at zero, and must be less than + ** ntb_db_vector_count(). The driver may call ntb_db_read() to check which + * doorbell bits need service, and ntb_db_vector_mask() to determine which of + * those bits are associated with the vector number. + */ +void ntb_db_event(struct ntb_dev *ntb, int vector); + +/** + * ntb_mw_count() - get the number of memory windows + * @ntb: NTB device context. + * + * Hardware and topology may support a different number of memory windows. + * + * Return: the number of memory windows. + */ +static inline int ntb_mw_count(struct ntb_dev *ntb) +{ + return ntb->ops->mw_count(ntb); +} + +/** + * ntb_mw_get_range() - get the range of a memory window + * @ntb: NTB device context. + * @idx: Memory window number. + * @base: OUT - the base address for mapping the memory window + * @size: OUT - the size for mapping the memory window + * @align: OUT - the base alignment for translating the memory window + * @align_size: OUT - the size alignment for translating the memory window + * + * Get the range of a memory window. NULL may be given for any output + * parameter if the value is not needed. The base and size may be used for + * mapping the memory window, to access the peer memory. The alignment and + * size may be used for translating the memory window, for the peer to access + * memory on the local system. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_mw_get_range(struct ntb_dev *ntb, int idx, + phys_addr_t *base, resource_size_t *size, + resource_size_t *align, resource_size_t *align_size) +{ + return ntb->ops->mw_get_range(ntb, idx, base, size, + align, align_size); +} + +/** + * ntb_mw_set_trans() - set the translation of a memory window + * @ntb: NTB device context. + * @idx: Memory window number. + * @addr: The dma address local memory to expose to the peer. + * @size: The size of the local memory to expose to the peer. + * + * Set the translation of a memory window. The peer may access local memory + * through the window starting at the address, up to the size. The address + * must be aligned to the alignment specified by ntb_mw_get_range(). The size + * must be aligned to the size alignment specified by ntb_mw_get_range(). + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_mw_set_trans(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size) +{ + return ntb->ops->mw_set_trans(ntb, idx, addr, size); +} + +/** + * ntb_mw_clear_trans() - clear the translation of a memory window + * @ntb: NTB device context. + * @idx: Memory window number. + * + * Clear the translation of a memory window. The peer may no longer access + * local memory through the window. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx) +{ + if (!ntb->ops->mw_clear_trans) + return ntb->ops->mw_set_trans(ntb, idx, 0, 0); + + return ntb->ops->mw_clear_trans(ntb, idx); +} + +/** + * ntb_link_is_up() - get the current ntb link state + * @ntb: NTB device context. + * @speed: OUT - The link speed expressed as PCIe generation number. + * @width: OUT - The link width expressed as the number of PCIe lanes. + * + * Set the translation of a memory window. The peer may access local memory + * through the window starting at the address, up to the size. The address + * must be aligned to the alignment specified by ntb_mw_get_range(). The size + * must be aligned to the size alignment specified by ntb_mw_get_range(). + * + * Return: One if the link is up, zero if the link is down, otherwise a + * negative value indicating the error number. + */ +static inline int ntb_link_is_up(struct ntb_dev *ntb, + enum ntb_speed *speed, enum ntb_width *width) +{ + return ntb->ops->link_is_up(ntb, speed, width); +} + +/** + * ntb_link_enable() - enable the link on the secondary side of the ntb + * @ntb: NTB device context. + * @max_speed: The maximum link speed expressed as PCIe generation number. + * @max_width: The maximum link width expressed as the number of PCIe lanes. + * + * Enable the link on the secondary side of the ntb. This can only be done + * from the primary side of the ntb in primary or b2b topology. The ntb device + * should train the link to its maximum speed and width, or the requested speed + * and width, whichever is smaller, if supported. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_link_enable(struct ntb_dev *ntb, + enum ntb_speed max_speed, + enum ntb_width max_width) +{ + return ntb->ops->link_enable(ntb, max_speed, max_width); +} + +/** + * ntb_link_disable() - disable the link on the secondary side of the ntb + * @ntb: NTB device context. + * + * Disable the link on the secondary side of the ntb. This can only be + * done from the primary side of the ntb in primary or b2b topology. The ntb + * device should disable the link. Returning from this call must indicate that + * a barrier has passed, though with no more writes may pass in either + * direction across the link, except if this call returns an error number. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_link_disable(struct ntb_dev *ntb) +{ + return ntb->ops->link_disable(ntb); +} + +/** + * ntb_db_is_unsafe() - check if it is safe to use hardware doorbell + * @ntb: NTB device context. + * + * It is possible for some ntb hardware to be affected by errata. Hardware + * drivers can advise clients to avoid using doorbells. Clients may ignore + * this advice, though caution is recommended. + * + * Return: Zero if it is safe to use doorbells, or One if it is not safe. + */ +static inline int ntb_db_is_unsafe(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_is_unsafe) + return 0; + + return ntb->ops->db_is_unsafe(ntb); +} + +/** + * ntb_db_valid_mask() - get a mask of doorbell bits supported by the ntb + * @ntb: NTB device context. + * + * Hardware may support different number or arrangement of doorbell bits. + * + * Return: A mask of doorbell bits supported by the ntb. + */ +static inline u64 ntb_db_valid_mask(struct ntb_dev *ntb) +{ + return ntb->ops->db_valid_mask(ntb); +} + +/** + * ntb_db_vector_count() - get the number of doorbell interrupt vectors + * @ntb: NTB device context. + * + * Hardware may support different number of interrupt vectors. + * + * Return: The number of doorbell interrupt vectors. + */ +static inline int ntb_db_vector_count(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_vector_count) + return 1; + + return ntb->ops->db_vector_count(ntb); +} + +/** + * ntb_db_vector_mask() - get a mask of doorbell bits serviced by a vector + * @ntb: NTB device context. + * @vector: Doorbell vector number. + * + * Each interrupt vector may have a different number or arrangement of bits. + * + * Return: A mask of doorbell bits serviced by a vector. + */ +static inline u64 ntb_db_vector_mask(struct ntb_dev *ntb, int vector) +{ + if (!ntb->ops->db_vector_mask) + return ntb_db_valid_mask(ntb); + + return ntb->ops->db_vector_mask(ntb, vector); +} + +/** + * ntb_db_read() - read the local doorbell register + * @ntb: NTB device context. + * + * Read the local doorbell register, and return the bits that are set. + * + * Return: The bits currently set in the local doorbell register. + */ +static inline u64 ntb_db_read(struct ntb_dev *ntb) +{ + return ntb->ops->db_read(ntb); +} + +/** + * ntb_db_set() - set bits in the local doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to set. + * + * Set bits in the local doorbell register, which may generate a local doorbell + * interrupt. Bits that were already set must remain set. + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_set(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_set) + return -EINVAL; + + return ntb->ops->db_set(ntb, db_bits); +} + +/** + * ntb_db_clear() - clear bits in the local doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the local doorbell register, arming the bits for the next + * doorbell. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->db_clear(ntb, db_bits); +} + +/** + * ntb_db_read_mask() - read the local doorbell mask + * @ntb: NTB device context. + * + * Read the local doorbell mask register, and return the bits that are set. + * + * This is unusual, though hardware is likely to support it. + * + * Return: The bits currently set in the local doorbell mask register. + */ +static inline u64 ntb_db_read_mask(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_read_mask) + return 0; + + return ntb->ops->db_read_mask(ntb); +} + +/** + * ntb_db_set_mask() - set bits in the local doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell mask bits to set. + * + * Set bits in the local doorbell mask register, preventing doorbell interrupts + * from being generated for those doorbell bits. Bits that were already set + * must remain set. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->db_set_mask(ntb, db_bits); +} + +/** + * ntb_db_clear_mask() - clear bits in the local doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the local doorbell mask register, allowing doorbell interrupts + * from being generated for those doorbell bits. If a doorbell bit is already + * set at the time the mask is cleared, and the corresponding mask bit is + * changed from set to clear, then the ntb driver must ensure that + * ntb_db_event() is called. If the hardware does not generate the interrupt + * on clearing the mask bit, then the driver must call ntb_db_event() anyway. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->db_clear_mask(ntb, db_bits); +} + +/** + * ntb_peer_db_addr() - address and size of the peer doorbell register + * @ntb: NTB device context. + * @db_addr: OUT - The address of the peer doorbell register. + * @db_size: OUT - The number of bytes to write the peer doorbell register. + * + * Return the address of the peer doorbell register. This may be used, for + * example, by drivers that offload memory copy operations to a dma engine. + * The drivers may wish to ring the peer doorbell at the completion of memory + * copy operations. For efficiency, and to simplify ordering of operations + * between the dma memory copies and the ringing doorbell, the driver may + * append one additional dma memory copy with the doorbell register as the + * destination, after the memory copy operations. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_addr(struct ntb_dev *ntb, + phys_addr_t *db_addr, + resource_size_t *db_size) +{ + return ntb->ops->peer_db_addr(ntb, db_addr, db_size); +} + +/** + * ntb_peer_db_read() - read the peer doorbell register + * @ntb: NTB device context. + * + * Read the peer doorbell register, and return the bits that are set. + * + * This is unusual, and hardware may not support it. + * + * Return: The bits currently set in the peer doorbell register. + */ +static inline u64 ntb_peer_db_read(struct ntb_dev *ntb) +{ + if (!ntb->ops->peer_db_read) + return 0; + + return ntb->ops->peer_db_read(ntb); +} + +/** + * ntb_peer_db_set() - set bits in the peer doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to set. + * + * Set bits in the peer doorbell register, which may generate a peer doorbell + * interrupt. Bits that were already set must remain set. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) +{ + return ntb->ops->peer_db_set(ntb, db_bits); +} + +/** + * ntb_peer_db_clear() - clear bits in the local doorbell register + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the peer doorbell register, arming the bits for the next + * doorbell. + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_clear) + return -EINVAL; + + return ntb->ops->peer_db_clear(ntb, db_bits); +} + +/** + * ntb_peer_db_read_mask() - read the peer doorbell mask + * @ntb: NTB device context. + * + * Read the peer doorbell mask register, and return the bits that are set. + * + * This is unusual, and hardware may not support it. + * + * Return: The bits currently set in the peer doorbell mask register. + */ +static inline u64 ntb_peer_db_read_mask(struct ntb_dev *ntb) +{ + if (!ntb->ops->db_read_mask) + return 0; + + return ntb->ops->peer_db_read_mask(ntb); +} + +/** + * ntb_peer_db_set_mask() - set bits in the peer doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell mask bits to set. + * + * Set bits in the peer doorbell mask register, preventing doorbell interrupts + * from being generated for those doorbell bits. Bits that were already set + * must remain set. + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_set_mask) + return -EINVAL; + + return ntb->ops->peer_db_set_mask(ntb, db_bits); +} + +/** + * ntb_peer_db_clear_mask() - clear bits in the peer doorbell mask + * @ntb: NTB device context. + * @db_bits: Doorbell bits to clear. + * + * Clear bits in the peer doorbell mask register, allowing doorbell interrupts + * from being generated for those doorbell bits. If the hardware does not + * generate the interrupt on clearing the mask bit, then the driver should not + * implement this function! + * + * This is unusual, and hardware may not support it. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) +{ + if (!ntb->ops->db_clear_mask) + return -EINVAL; + + return ntb->ops->peer_db_clear_mask(ntb, db_bits); +} + +/** + * ntb_spad_is_unsafe() - check if it is safe to use the hardware scratchpads + * @ntb: NTB device context. + * + * It is possible for some ntb hardware to be affected by errata. Hardware + * drivers can advise clients to avoid using scratchpads. Clients may ignore + * this advice, though caution is recommended. + * + * Return: Zero if it is safe to use scratchpads, or One if it is not safe. + */ +static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb) +{ + if (!ntb->ops->spad_is_unsafe) + return 0; + + return ntb->ops->spad_is_unsafe(ntb); +} + +/** + * ntb_mw_count() - get the number of scratchpads + * @ntb: NTB device context. + * + * Hardware and topology may support a different number of scratchpads. + * + * Return: the number of scratchpads. + */ +static inline int ntb_spad_count(struct ntb_dev *ntb) +{ + return ntb->ops->spad_count(ntb); +} + +/** + * ntb_spad_read() - read the local scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * + * Read the local scratchpad register, and return the value. + * + * Return: The value of the local scratchpad register. + */ +static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx) +{ + return ntb->ops->spad_read(ntb, idx); +} + +/** + * ntb_spad_write() - write the local scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * @val: Scratchpad value. + * + * Write the value to the local scratchpad register. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) +{ + return ntb->ops->spad_write(ntb, idx, val); +} + +/** + * ntb_peer_spad_addr() - address of the peer scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * @spad_addr: OUT - The address of the peer scratchpad register. + * + * Return the address of the peer doorbell register. This may be used, for + * example, by drivers that offload memory copy operations to a dma engine. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx, + phys_addr_t *spad_addr) +{ + return ntb->ops->peer_spad_addr(ntb, idx, spad_addr); +} + +/** + * ntb_peer_spad_read() - read the peer scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * + * Read the peer scratchpad register, and return the value. + * + * Return: The value of the local scratchpad register. + */ +static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx) +{ + return ntb->ops->peer_spad_read(ntb, idx); +} + +/** + * ntb_peer_spad_write() - write the peer scratchpad register + * @ntb: NTB device context. + * @idx: Scratchpad index. + * @val: Scratchpad value. + * + * Write the value to the peer scratchpad register. + * + * Return: Zero on success, otherwise an error number. + */ +static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val) +{ + return ntb->ops->peer_spad_write(ntb, idx, val); +} + +#endif -- cgit v1.2.3 From e26a5843f7f5014ae4460030ca4de029a3ac35d3 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Thu, 9 Apr 2015 10:33:20 -0400 Subject: NTB: Split ntb_hw_intel and ntb_transport drivers Change ntb_hw_intel to use the new NTB hardware abstraction layer. Split ntb_transport into its own driver. Change it to use the new NTB hardware abstraction layer. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- Documentation/ntb.txt | 26 + MAINTAINERS | 8 + drivers/net/ntb_netdev.c | 54 +- drivers/ntb/Kconfig | 37 +- drivers/ntb/Makefile | 6 +- drivers/ntb/hw/Kconfig | 1 + drivers/ntb/hw/Makefile | 1 + drivers/ntb/hw/intel/Kconfig | 7 + drivers/ntb/hw/intel/Makefile | 1 + drivers/ntb/hw/intel/ntb_hw_intel.c | 3075 +++++++++++++++++++---------------- drivers/ntb/hw/intel/ntb_hw_intel.h | 607 ++++--- drivers/ntb/ntb_transport.c | 936 ++++++----- include/linux/ntb_transport.h | 25 +- 13 files changed, 2589 insertions(+), 2195 deletions(-) create mode 100644 drivers/ntb/hw/Kconfig create mode 100644 drivers/ntb/hw/Makefile create mode 100644 drivers/ntb/hw/intel/Kconfig create mode 100644 drivers/ntb/hw/intel/Makefile (limited to 'include') diff --git a/Documentation/ntb.txt b/Documentation/ntb.txt index 9d46dc9712a8..725ba1e6c127 100644 --- a/Documentation/ntb.txt +++ b/Documentation/ntb.txt @@ -26,7 +26,33 @@ as ntb hardware, or hardware drivers, are inserted and removed. The registration uses the Linux Device framework, so it should feel familiar to anyone who has written a pci driver. +### NTB Transport Client (ntb\_transport) and NTB Netdev (ntb\_netdev) + +The primary client for NTB is the Transport client, used in tandem with NTB +Netdev. These drivers function together to create a logical link to the peer, +across the ntb, to exchange packets of network data. The Transport client +establishes a logical link to the peer, and creates queue pairs to exchange +messages and data. The NTB Netdev then creates an ethernet device using a +Transport queue pair. Network data is copied between socket buffers and the +Transport queue pair buffer. The Transport client may be used for other things +besides Netdev, however no other applications have yet been written. + ## NTB Hardware Drivers NTB hardware drivers should register devices with the NTB core driver. After registering, clients probe and remove functions will be called. + +### NTB Intel Hardware Driver (ntb\_hw\_intel) + +The Intel hardware driver supports NTB on Xeon and Atom CPUs. + +Module Parameters: + +* b2b\_mw\_idx - If the peer ntb is to be accessed via a memory window, then use + this memory window to access the peer ntb. A value of zero or positive + starts from the first mw idx, and a negative value starts from the last + mw idx. Both sides MUST set the same value here! The default value is + `-1`. +* b2b\_mw\_share - If the peer ntb is to be accessed via a memory window, and if + the memory window is large enough, still allow the client to use the + second half of the memory window for address translation to the peer. diff --git a/MAINTAINERS b/MAINTAINERS index e2fc9eec2e16..a682805d6d56 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7007,6 +7007,14 @@ F: drivers/net/ntb_netdev.c F: include/linux/ntb.h F: include/linux/ntb_transport.h +NTB INTEL DRIVER +M: Jon Mason +M: Dave Jiang +S: Supported +W: https://github.com/jonmason/ntb/wiki +T: git git://github.com/jonmason/ntb.git +F: drivers/ntb/hw/intel/ + NTFS FILESYSTEM M: Anton Altaparmakov L: linux-ntfs-dev@lists.sourceforge.net diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index 6d3bfa62f5ec..3cc316cb7e6b 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +42,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Intel PCIe NTB Network Linux driver + * PCIe NTB Network Linux driver * * Contact Information: * Jon Mason @@ -49,6 +51,7 @@ #include #include #include +#include #include #define NTB_NETDEV_VER "0.7" @@ -70,26 +73,19 @@ struct ntb_netdev { static LIST_HEAD(dev_list); -static void ntb_netdev_event_handler(void *data, int status) +static void ntb_netdev_event_handler(void *data, int link_is_up) { struct net_device *ndev = data; struct ntb_netdev *dev = netdev_priv(ndev); - netdev_dbg(ndev, "Event %x, Link %x\n", status, + netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up, ntb_transport_link_query(dev->qp)); - switch (status) { - case NTB_LINK_DOWN: + if (link_is_up) { + if (ntb_transport_link_query(dev->qp)) + netif_carrier_on(ndev); + } else { netif_carrier_off(ndev); - break; - case NTB_LINK_UP: - if (!ntb_transport_link_query(dev->qp)) - return; - - netif_carrier_on(ndev); - break; - default: - netdev_warn(ndev, "Unsupported event type %d\n", status); } } @@ -160,8 +156,6 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb, struct ntb_netdev *dev = netdev_priv(ndev); int rc; - netdev_dbg(ndev, "%s: skb len %d\n", __func__, skb->len); - rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len); if (rc) goto err; @@ -322,20 +316,26 @@ static const struct ntb_queue_handlers ntb_netdev_handlers = { .event_handler = ntb_netdev_event_handler, }; -static int ntb_netdev_probe(struct pci_dev *pdev) +static int ntb_netdev_probe(struct device *client_dev) { + struct ntb_dev *ntb; struct net_device *ndev; + struct pci_dev *pdev; struct ntb_netdev *dev; int rc; - ndev = alloc_etherdev(sizeof(struct ntb_netdev)); + ntb = dev_ntb(client_dev->parent); + pdev = ntb->pdev; + if (!pdev) + return -ENODEV; + + ndev = alloc_etherdev(sizeof(*dev)); if (!ndev) return -ENOMEM; dev = netdev_priv(ndev); dev->ndev = ndev; dev->pdev = pdev; - BUG_ON(!dev->pdev); ndev->features = NETIF_F_HIGHDMA; ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; @@ -349,7 +349,8 @@ static int ntb_netdev_probe(struct pci_dev *pdev) ndev->netdev_ops = &ntb_netdev_ops; ndev->ethtool_ops = &ntb_ethtool_ops; - dev->qp = ntb_transport_create_queue(ndev, pdev, &ntb_netdev_handlers); + dev->qp = ntb_transport_create_queue(ndev, client_dev, + &ntb_netdev_handlers); if (!dev->qp) { rc = -EIO; goto err; @@ -372,12 +373,17 @@ err: return rc; } -static void ntb_netdev_remove(struct pci_dev *pdev) +static void ntb_netdev_remove(struct device *client_dev) { + struct ntb_dev *ntb; struct net_device *ndev; + struct pci_dev *pdev; struct ntb_netdev *dev; bool found = false; + ntb = dev_ntb(client_dev->parent); + pdev = ntb->pdev; + list_for_each_entry(dev, &dev_list, list) { if (dev->pdev == pdev) { found = true; @@ -396,7 +402,7 @@ static void ntb_netdev_remove(struct pci_dev *pdev) free_netdev(ndev); } -static struct ntb_client ntb_netdev_client = { +static struct ntb_transport_client ntb_netdev_client = { .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .probe = ntb_netdev_probe, @@ -407,7 +413,7 @@ static int __init ntb_netdev_init_module(void) { int rc; - rc = ntb_register_client_dev(KBUILD_MODNAME); + rc = ntb_transport_register_client_dev(KBUILD_MODNAME); if (rc) return rc; return ntb_transport_register_client(&ntb_netdev_client); @@ -417,6 +423,6 @@ module_init(ntb_netdev_init_module); static void __exit ntb_netdev_exit_module(void) { ntb_transport_unregister_client(&ntb_netdev_client); - ntb_unregister_client_dev(KBUILD_MODNAME); + ntb_transport_unregister_client_dev(KBUILD_MODNAME); } module_exit(ntb_netdev_exit_module); diff --git a/drivers/ntb/Kconfig b/drivers/ntb/Kconfig index f69df793dbe2..53b042429673 100644 --- a/drivers/ntb/Kconfig +++ b/drivers/ntb/Kconfig @@ -1,13 +1,26 @@ -config NTB - tristate "Intel Non-Transparent Bridge support" - depends on PCI - depends on X86 - help - The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus - connecting 2 systems. When configured, writes to the device's PCI - mapped memory will be mirrored to a buffer on the remote system. The - ntb Linux driver uses this point-to-point communication as a method to - transfer data from one system to the other. - - If unsure, say N. +menuconfig NTB + tristate "Non-Transparent Bridge support" + depends on PCI + help + The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus + connecting 2 systems. When configured, writes to the device's PCI + mapped memory will be mirrored to a buffer on the remote system. The + ntb Linux driver uses this point-to-point communication as a method to + transfer data from one system to the other. + If unsure, say N. + +if NTB + +source "drivers/ntb/hw/Kconfig" + +config NTB_TRANSPORT + tristate "NTB Transport Client" + help + This is a transport driver that enables connected systems to exchange + messages over the ntb hardware. The transport exposes a queue pair api + to client drivers. + + If unsure, say N. + +endif # NTB diff --git a/drivers/ntb/Makefile b/drivers/ntb/Makefile index 712e953a8fda..b9fa663ecfec 100644 --- a/drivers/ntb/Makefile +++ b/drivers/ntb/Makefile @@ -1,4 +1,2 @@ -obj-$(CONFIG_NTB) += ntb.o -obj-$(CONFIG_NTB) += ntb_hw_intel.o - -ntb_hw_intel-objs := hw/intel/ntb_hw_intel.o ntb_transport.o +obj-$(CONFIG_NTB) += ntb.o hw/ +obj-$(CONFIG_NTB_TRANSPORT) += ntb_transport.o diff --git a/drivers/ntb/hw/Kconfig b/drivers/ntb/hw/Kconfig new file mode 100644 index 000000000000..4d5535c4cddf --- /dev/null +++ b/drivers/ntb/hw/Kconfig @@ -0,0 +1 @@ +source "drivers/ntb/hw/intel/Kconfig" diff --git a/drivers/ntb/hw/Makefile b/drivers/ntb/hw/Makefile new file mode 100644 index 000000000000..175d7c92a569 --- /dev/null +++ b/drivers/ntb/hw/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NTB_INTEL) += intel/ diff --git a/drivers/ntb/hw/intel/Kconfig b/drivers/ntb/hw/intel/Kconfig new file mode 100644 index 000000000000..91f995e33ac6 --- /dev/null +++ b/drivers/ntb/hw/intel/Kconfig @@ -0,0 +1,7 @@ +config NTB_INTEL + tristate "Intel Non-Transparent Bridge support" + depends on X86_64 + help + This driver supports Intel NTB on capable Xeon and Atom hardware. + + If unsure, say N. diff --git a/drivers/ntb/hw/intel/Makefile b/drivers/ntb/hw/intel/Makefile new file mode 100644 index 000000000000..1b434568d2ad --- /dev/null +++ b/drivers/ntb/hw/intel/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_NTB_INTEL) += ntb_hw_intel.o diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 044534a995f1..686091756ba4 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,6 +47,7 @@ * Contact Information: * Jon Mason */ + #include #include #include @@ -53,99 +56,97 @@ #include #include #include +#include + #include "ntb_hw_intel.h" -#define NTB_NAME "Intel(R) PCI-E Non-Transparent Bridge Driver" -#define NTB_VER "1.0" +#define NTB_NAME "ntb_hw_intel" +#define NTB_DESC "Intel(R) PCI-E Non-Transparent Bridge Driver" +#define NTB_VER "2.0" -MODULE_DESCRIPTION(NTB_NAME); +MODULE_DESCRIPTION(NTB_DESC); MODULE_VERSION(NTB_VER); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel Corporation"); -enum { - NTB_CONN_TRANSPARENT = 0, - NTB_CONN_B2B, - NTB_CONN_RP, -}; - -enum { - NTB_DEV_USD = 0, - NTB_DEV_DSD, -}; - -enum { - SNB_HW = 0, - BWD_HW, -}; - +#define bar0_off(base, bar) ((base) + ((bar) << 2)) +#define bar2_off(base, bar) bar0_off(base, (bar) - 2) + +static int b2b_mw_idx = -1; +module_param(b2b_mw_idx, int, 0644); +MODULE_PARM_DESC(b2b_mw_idx, "Use this mw idx to access the peer ntb. A " + "value of zero or positive starts from first mw idx, and a " + "negative value starts from last mw idx. Both sides MUST " + "set the same value here!"); + +static unsigned int b2b_mw_share; +module_param(b2b_mw_share, uint, 0644); +MODULE_PARM_DESC(b2b_mw_share, "If the b2b mw is large enough, configure the " + "ntb so that the peer ntb only occupies the first half of " + "the mw, so the second half can still be used as a mw. Both " + "sides MUST set the same value here!"); + +static const struct intel_ntb_reg bwd_reg; +static const struct intel_ntb_alt_reg bwd_pri_reg; +static const struct intel_ntb_alt_reg bwd_sec_reg; +static const struct intel_ntb_alt_reg bwd_b2b_reg; +static const struct intel_ntb_xlat_reg bwd_pri_xlat; +static const struct intel_ntb_xlat_reg bwd_sec_xlat; +static const struct intel_ntb_reg snb_reg; +static const struct intel_ntb_alt_reg snb_pri_reg; +static const struct intel_ntb_alt_reg snb_sec_reg; +static const struct intel_ntb_alt_reg snb_b2b_reg; +static const struct intel_ntb_xlat_reg snb_pri_xlat; +static const struct intel_ntb_xlat_reg snb_sec_xlat; +static const struct intel_b2b_addr snb_b2b_usd_addr; +static const struct intel_b2b_addr snb_b2b_dsd_addr; + +static const struct ntb_dev_ops intel_ntb_ops; + +static const struct file_operations intel_ntb_debugfs_info; static struct dentry *debugfs_dir; -#define BWD_LINK_RECOVERY_TIME 500 - -/* Translate memory window 0,1,2 to BAR 2,4,5 */ -#define MW_TO_BAR(mw) (mw == 0 ? 2 : (mw == 1 ? 4 : 5)) - -static const struct pci_device_id ntb_pci_tbl[] = { - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, - {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, - {0} -}; -MODULE_DEVICE_TABLE(pci, ntb_pci_tbl); - -static int is_ntb_xeon(struct ntb_device *ndev) +#ifndef ioread64 +#ifdef readq +#define ioread64 readq +#else +#define ioread64 _ioread64 +static inline u64 _ioread64(void __iomem *mmio) { - switch (ndev->pdev->device) { - case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: - case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: - case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: - case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: - case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: - case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: - case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: - case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - return 1; - default: - return 0; - } + u64 low, high; - return 0; + low = ioread32(mmio); + high = ioread32(mmio + sizeof(u32)); + return low | (high << 32); +} +#endif +#endif + +#ifndef iowrite64 +#ifdef writeq +#define iowrite64 writeq +#else +#define iowrite64 _iowrite64 +static inline void _iowrite64(u64 val, void __iomem *mmio) +{ + iowrite32(val, mmio); + iowrite32(val >> 32, mmio + sizeof(u32)); } +#endif +#endif -static int is_ntb_atom(struct ntb_device *ndev) +static inline int pdev_is_bwd(struct pci_dev *pdev) { - switch (ndev->pdev->device) { + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD: return 1; - default: - return 0; } - return 0; } -static void ntb_set_errata_flags(struct ntb_device *ndev) +static inline int pdev_is_snb(struct pci_dev *pdev) { - switch (ndev->pdev->device) { - /* - * this workaround applies to all platform up to IvyBridge - * Haswell has splitbar support and use a different workaround - */ + switch (pdev->device) { case PCI_DEVICE_ID_INTEL_NTB_SS_JSF: case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: @@ -158,1737 +159,1957 @@ static void ntb_set_errata_flags(struct ntb_device *ndev) case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: - ndev->wa_flags |= WA_SNB_ERR; - break; + return 1; } + return 0; } -/** - * ntb_register_event_callback() - register event callback - * @ndev: pointer to ntb_device instance - * @func: callback function to register - * - * This function registers a callback for any HW driver events such as link - * up/down, power management notices and etc. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_event_callback(struct ntb_device *ndev, - void (*func)(void *handle, - enum ntb_hw_event event)) +static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev) { - if (ndev->event_cb) - return -EINVAL; - - ndev->event_cb = func; - - return 0; + ndev->unsafe_flags = 0; + ndev->unsafe_flags_ignore = 0; + + /* Only B2B has a workaround to avoid SDOORBELL */ + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) + if (!ntb_topo_is_b2b(ndev->ntb.topo)) + ndev->unsafe_flags |= NTB_UNSAFE_DB; + + /* No low level workaround to avoid SB01BASE */ + if (ndev->hwerr_flags & NTB_HWERR_SB01BASE_LOCKUP) { + ndev->unsafe_flags |= NTB_UNSAFE_DB; + ndev->unsafe_flags |= NTB_UNSAFE_SPAD; + } } -/** - * ntb_unregister_event_callback() - unregisters the event callback - * @ndev: pointer to ntb_device instance - * - * This function unregisters the existing callback from transport - */ -void ntb_unregister_event_callback(struct ntb_device *ndev) +static inline int ndev_is_unsafe(struct intel_ntb_dev *ndev, + unsigned long flag) { - ndev->event_cb = NULL; + return !!(flag & ndev->unsafe_flags & ~ndev->unsafe_flags_ignore); } -static void ntb_irq_work(unsigned long data) +static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev, + unsigned long flag) { - struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; - int rc; + flag &= ndev->unsafe_flags; + ndev->unsafe_flags_ignore |= flag; - rc = db_cb->callback(db_cb->data, db_cb->db_num); - if (rc) - tasklet_schedule(&db_cb->irq_work); - else { - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; - - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); - } + return !!flag; } -/** - * ntb_register_db_callback() - register a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * @data: pointer to be returned to caller with every callback - * @func: callback function to register - * - * This function registers a callback function for the doorbell interrupt - * on the primary side. The function will unmask the doorbell as well to - * allow interrupt. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*func)(void *data, int db_num)) +static int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx) { - unsigned long mask; - - if (idx >= ndev->max_cbs || ndev->db_cb[idx].callback) { - dev_warn(&ndev->pdev->dev, "Invalid Index.\n"); + if (idx < 0 || idx > ndev->mw_count) return -EINVAL; - } + return ndev->reg->mw_bar[idx]; +} - ndev->db_cb[idx].callback = func; - ndev->db_cb[idx].data = data; - ndev->db_cb[idx].ndev = ndev; +static inline int ndev_db_addr(struct intel_ntb_dev *ndev, + phys_addr_t *db_addr, resource_size_t *db_size, + phys_addr_t reg_addr, unsigned long reg) +{ + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); - tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, - (unsigned long) &ndev->db_cb[idx]); + if (db_addr) { + *db_addr = reg_addr + reg; + dev_dbg(ndev_dev(ndev), "Peer db addr %llx\n", *db_addr); + } - /* unmask interrupt */ - mask = readw(ndev->reg_ofs.ldb_mask); - clear_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); + if (db_size) { + *db_size = ndev->reg->db_size; + dev_dbg(ndev_dev(ndev), "Peer db size %llx\n", *db_size); + } return 0; } -/** - * ntb_unregister_db_callback() - unregister a callback for doorbell interrupt - * @ndev: pointer to ntb_device instance - * @idx: doorbell index to register callback, zero based - * - * This function unregisters a callback function for the doorbell interrupt - * on the primary side. The function will also mask the said doorbell. - */ -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) +static inline u64 ndev_db_read(struct intel_ntb_dev *ndev, + void __iomem *mmio) { - unsigned long mask; + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); - if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback) - return; + return ndev->reg->db_ioread(mmio); +} + +static inline int ndev_db_write(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio) +{ + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(idx * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; - tasklet_disable(&ndev->db_cb[idx].irq_work); + ndev->reg->db_iowrite(db_bits, mmio); - ndev->db_cb[idx].callback = NULL; + return 0; } -/** - * ntb_find_transport() - find the transport pointer - * @transport: pointer to pci device - * - * Given the pci device pointer, return the transport pointer passed in when - * the transport attached when it was inited. - * - * RETURNS: pointer to transport. - */ -void *ntb_find_transport(struct pci_dev *pdev) +static inline int ndev_db_set_mask(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio) { - struct ntb_device *ndev = pci_get_drvdata(pdev); - return ndev->ntb_transport; -} + unsigned long irqflags; -/** - * ntb_register_transport() - Register NTB transport with NTB HW driver - * @transport: transport identifier - * - * This function allows a transport to reserve the hardware driver for - * NTB usage. - * - * RETURNS: pointer to ntb_device, NULL on error. - */ -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, void *transport) -{ - struct ntb_device *ndev = pci_get_drvdata(pdev); + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; - if (ndev->ntb_transport) - return NULL; + spin_lock_irqsave(&ndev->db_mask_lock, irqflags); + { + ndev->db_mask |= db_bits; + ndev->reg->db_iowrite(ndev->db_mask, mmio); + } + spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags); - ndev->ntb_transport = transport; - return ndev; + return 0; } -/** - * ntb_unregister_transport() - Unregister the transport with the NTB HW driver - * @ndev - ntb_device of the transport to be freed - * - * This function unregisters the transport from the HW driver and performs any - * necessary cleanups. - */ -void ntb_unregister_transport(struct ntb_device *ndev) +static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits, + void __iomem *mmio) { - int i; + unsigned long irqflags; - if (!ndev->ntb_transport) - return; + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_DB)); + + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; - for (i = 0; i < ndev->max_cbs; i++) - ntb_unregister_db_callback(ndev, i); + spin_lock_irqsave(&ndev->db_mask_lock, irqflags); + { + ndev->db_mask &= ~db_bits; + ndev->reg->db_iowrite(ndev->db_mask, mmio); + } + spin_unlock_irqrestore(&ndev->db_mask_lock, irqflags); - ntb_unregister_event_callback(ndev); - ndev->ntb_transport = NULL; + return 0; } -/** - * ntb_write_local_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. This writes over the data mirrored to the local scratchpad register - * by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector) { - if (idx >= ndev->limits.max_spads) - return -EINVAL; + u64 shift, mask; - dev_dbg(&ndev->pdev->dev, "Writing %x to local scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_read + idx * 4); + shift = ndev->db_vec_shift; + mask = BIT_ULL(shift) - 1; - return 0; + return mask << (shift * db_vector); } -/** - * ntb_read_local_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This allows the local system to read data - * written and mirrored to the scratchpad register by the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +static inline int ndev_spad_addr(struct intel_ntb_dev *ndev, int idx, + phys_addr_t *spad_addr, phys_addr_t reg_addr, + unsigned long reg) { - if (idx >= ndev->limits.max_spads) + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + + if (idx < 0 || idx >= ndev->spad_count) return -EINVAL; - *val = readl(ndev->reg_ofs.spad_write + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from local scratch pad index %d\n", *val, idx); + if (spad_addr) { + *spad_addr = reg_addr + reg + (idx << 2); + dev_dbg(ndev_dev(ndev), "Peer spad addr %llx\n", *spad_addr); + } return 0; } -/** - * ntb_write_remote_spad() - write to the secondary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to the scratchpad register, 0 based - * @val: the data value to put into the register - * - * This function allows writing of a 32bit value to the indexed scratchpad - * register. The register resides on the secondary (external) side. This allows - * the local system to write data to be mirrored to the remote systems - * scratchpad register. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val) +static inline u32 ndev_spad_read(struct intel_ntb_dev *ndev, int idx, + void __iomem *mmio) { - if (idx >= ndev->limits.max_spads) - return -EINVAL; + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); - dev_dbg(&ndev->pdev->dev, "Writing %x to remote scratch pad index %d\n", - val, idx); - writel(val, ndev->reg_ofs.spad_write + idx * 4); + if (idx < 0 || idx >= ndev->spad_count) + return 0; - return 0; + return ioread32(mmio + (idx << 2)); } -/** - * ntb_read_remote_spad() - read from the primary scratchpad register - * @ndev: pointer to ntb_device instance - * @idx: index to scratchpad register, 0 based - * @val: pointer to 32bit integer for storing the register value - * - * This function allows reading of the 32bit scratchpad register on - * the primary (internal) side. This alloows the local system to read the data - * it wrote to be mirrored on the remote system. - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val) +static inline int ndev_spad_write(struct intel_ntb_dev *ndev, int idx, u32 val, + void __iomem *mmio) { - if (idx >= ndev->limits.max_spads) + WARN_ON_ONCE(ndev_is_unsafe(ndev, NTB_UNSAFE_SPAD)); + + if (idx < 0 || idx >= ndev->spad_count) return -EINVAL; - *val = readl(ndev->reg_ofs.spad_read + idx * 4); - dev_dbg(&ndev->pdev->dev, - "Reading %x from remote scratch pad index %d\n", *val, idx); + iowrite32(val, mmio + (idx << 2)); return 0; } -/** - * ntb_get_mw_base() - get addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base address of the memory window specified. - * - * RETURNS: address, or NULL on error. - */ -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw) +static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec) { - if (mw >= ntb_max_mw(ndev)) - return 0; + u64 vec_mask; + + vec_mask = ndev_vec_mask(ndev, vec); + + dev_dbg(ndev_dev(ndev), "vec %d vec_mask %llx\n", vec, vec_mask); - return pci_resource_start(ndev->pdev, MW_TO_BAR(mw)); + ndev->last_ts = jiffies; + + if (vec_mask & ndev->db_link_mask) { + if (ndev->reg->poll_link(ndev)) + ntb_link_event(&ndev->ntb); + } + + if (vec_mask & ndev->db_valid_mask) + ntb_db_event(&ndev->ntb, vec); + + return IRQ_HANDLED; } -/** - * ntb_get_mw_vbase() - get virtual addr for the NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the base virtual address of the memory window - * specified. - * - * RETURNS: pointer to virtual address, or NULL on error. - */ -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw) +static irqreturn_t ndev_vec_isr(int irq, void *dev) { - if (mw >= ntb_max_mw(ndev)) - return NULL; + struct intel_ntb_vec *nvec = dev; - return ndev->mw[mw].vbase; + return ndev_interrupt(nvec->ndev, nvec->num); } -/** - * ntb_get_mw_size() - return size of NTB memory window - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * - * This function provides the physical size of the memory window specified - * - * RETURNS: the size of the memory window or zero on error - */ -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw) +static irqreturn_t ndev_irq_isr(int irq, void *dev) { - if (mw >= ntb_max_mw(ndev)) - return 0; + struct intel_ntb_dev *ndev = dev; - return ndev->mw[mw].bar_sz; + return ndev_interrupt(ndev, irq - ndev_pdev(ndev)->irq); } -/** - * ntb_set_mw_addr - set the memory window address - * @ndev: pointer to ntb_device instance - * @mw: memory window number - * @addr: base address for data - * - * This function sets the base physical address of the memory window. This - * memory address is where data from the remote system will be transfered into - * or out of depending on how the transport is configured. - */ -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr) +static int ndev_init_isr(struct intel_ntb_dev *ndev, + int msix_min, int msix_max, + int msix_shift, int total_shift) { - if (mw >= ntb_max_mw(ndev)) - return; + struct pci_dev *pdev; + int rc, i, msix_count; - dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr, - MW_TO_BAR(mw)); + pdev = ndev_pdev(ndev); - ndev->mw[mw].phys_addr = addr; + /* Mask all doorbell interrupts */ + ndev->db_mask = ndev->db_valid_mask; + ndev->reg->db_iowrite(ndev->db_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); - switch (MW_TO_BAR(mw)) { - case NTB_BAR_23: - writeq(addr, ndev->reg_ofs.bar2_xlat); - break; - case NTB_BAR_4: - if (ndev->split_bar) - writel(addr, ndev->reg_ofs.bar4_xlat); - else - writeq(addr, ndev->reg_ofs.bar4_xlat); - break; - case NTB_BAR_5: - writel(addr, ndev->reg_ofs.bar5_xlat); - break; + /* Try to set up msix irq */ + + ndev->vec = kcalloc(msix_max, sizeof(*ndev->vec), GFP_KERNEL); + if (!ndev->vec) + goto err_msix_vec_alloc; + + ndev->msix = kcalloc(msix_max, sizeof(*ndev->msix), GFP_KERNEL); + if (!ndev->msix) + goto err_msix_alloc; + + for (i = 0; i < msix_max; ++i) + ndev->msix[i].entry = i; + + msix_count = pci_enable_msix_range(pdev, ndev->msix, + msix_min, msix_max); + if (msix_count < 0) + goto err_msix_enable; + + for (i = 0; i < msix_count; ++i) { + ndev->vec[i].ndev = ndev; + ndev->vec[i].num = i; + rc = request_irq(ndev->msix[i].vector, ndev_vec_isr, 0, + "ndev_vec_isr", &ndev->vec[i]); + if (rc) + goto err_msix_request; } -} -/** - * ntb_ring_doorbell() - Set the doorbell on the secondary/external side - * @ndev: pointer to ntb_device instance - * @db: doorbell to ring - * - * This function allows triggering of a doorbell on the secondary/external - * side that will initiate an interrupt on the remote host - * - * RETURNS: An appropriate -ERRNO error value on error, or zero for success. - */ -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db) -{ - dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db); + dev_dbg(ndev_dev(ndev), "Using msix interrupts\n"); + ndev->db_vec_count = msix_count; + ndev->db_vec_shift = msix_shift; + return 0; - if (ndev->hw_type == BWD_HW) - writeq((u64) 1 << db, ndev->reg_ofs.rdb); - else - writew(((1 << ndev->bits_per_vector) - 1) << - (db * ndev->bits_per_vector), ndev->reg_ofs.rdb); -} +err_msix_request: + while (i-- > 0) + free_irq(ndev->msix[i].vector, ndev); + pci_disable_msix(pdev); +err_msix_enable: + kfree(ndev->msix); +err_msix_alloc: + kfree(ndev->vec); +err_msix_vec_alloc: + ndev->msix = NULL; + ndev->vec = NULL; -static void bwd_recover_link(struct ntb_device *ndev) -{ - u32 status; + /* Try to set up msi irq */ - /* Driver resets the NTB ModPhy lanes - magic! */ - writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6); - writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4); - writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6); + rc = pci_enable_msi(pdev); + if (rc) + goto err_msi_enable; - /* Driver waits 100ms to allow the NTB ModPhy to settle */ - msleep(100); + rc = request_irq(pdev->irq, ndev_irq_isr, 0, + "ndev_irq_isr", ndev); + if (rc) + goto err_msi_request; - /* Clear AER Errors, write to clear */ - status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status); - status &= PCI_ERR_COR_REP_ROLL; - writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET); + dev_dbg(ndev_dev(ndev), "Using msi interrupts\n"); + ndev->db_vec_count = 1; + ndev->db_vec_shift = total_shift; + return 0; - /* Clear unexpected electrical idle event in LTSSM, write to clear */ - status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status); - status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; - writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET); +err_msi_request: + pci_disable_msi(pdev); +err_msi_enable: - /* Clear DeSkew Buffer error, write to clear */ - status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET); - dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status); - status |= BWD_DESKEWSTS_DBERR; - writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET); + /* Try to set up intx irq */ - status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status); - status &= BWD_IBIST_ERR_OFLOW; - writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); + pci_intx(pdev, 1); - /* Releases the NTB state machine to allow the link to retrain */ - status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status); - status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; - writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); + rc = request_irq(pdev->irq, ndev_irq_isr, IRQF_SHARED, + "ndev_irq_isr", ndev); + if (rc) + goto err_intx_request; + + dev_dbg(ndev_dev(ndev), "Using intx interrupts\n"); + ndev->db_vec_count = 1; + ndev->db_vec_shift = total_shift; + return 0; + +err_intx_request: + return rc; } -static void ntb_link_event(struct ntb_device *ndev, int link_state) +static void ndev_deinit_isr(struct intel_ntb_dev *ndev) { - unsigned int event; + struct pci_dev *pdev; + int i; - if (ndev->link_status == link_state) - return; + pdev = ndev_pdev(ndev); - if (link_state == NTB_LINK_UP) { - u16 status; - - dev_info(&ndev->pdev->dev, "Link Up\n"); - ndev->link_status = NTB_LINK_UP; - event = NTB_EVENT_HW_LINK_UP; - - if (is_ntb_atom(ndev) || - ndev->conn_type == NTB_CONN_TRANSPARENT) - status = readw(ndev->reg_ofs.lnk_stat); - else { - int rc = pci_read_config_word(ndev->pdev, - SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return; - } + /* Mask all doorbell interrupts */ + ndev->db_mask = ndev->db_valid_mask; + ndev->reg->db_iowrite(ndev->db_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); - ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4; - ndev->link_speed = (status & NTB_LINK_SPEED_MASK); - dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n", - ndev->link_width, ndev->link_speed); + if (ndev->msix) { + i = ndev->db_vec_count; + while (i--) + free_irq(ndev->msix[i].vector, &ndev->vec[i]); + pci_disable_msix(pdev); + kfree(ndev->msix); + kfree(ndev->vec); } else { - dev_info(&ndev->pdev->dev, "Link Down\n"); - ndev->link_status = NTB_LINK_DOWN; - event = NTB_EVENT_HW_LINK_DOWN; - /* Don't modify link width/speed, we need it in link recovery */ + free_irq(pdev->irq, ndev); + if (pci_dev_msi_enabled(pdev)) + pci_disable_msi(pdev); } - - /* notify the upper layer if we have an event change */ - if (ndev->event_cb) - ndev->event_cb(ndev->ntb_transport, event); } -static int ntb_link_status(struct ntb_device *ndev) +static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) { - int link_state; + struct intel_ntb_dev *ndev; + void __iomem *mmio; + char *buf; + size_t buf_size; + ssize_t ret, off; + union { u64 v64; u32 v32; u16 v16; } u; - if (is_ntb_atom(ndev)) { - u32 ntb_cntl; + ndev = filp->private_data; + mmio = ndev->self_mmio; - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - if (ntb_cntl & BWD_CNTL_LINK_DOWN) - link_state = NTB_LINK_DOWN; - else - link_state = NTB_LINK_UP; - } else { - u16 status; - int rc; + buf_size = min(count, 0x800ul); - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status); - if (rc) - return rc; + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (status & NTB_LINK_STATUS_ACTIVE) - link_state = NTB_LINK_UP; - else - link_state = NTB_LINK_DOWN; - } + off = 0; - ntb_link_event(ndev, link_state); + off += scnprintf(buf + off, buf_size - off, + "NTB Device Information:\n"); - return 0; -} + off += scnprintf(buf + off, buf_size - off, + "Connection Topology -\t%s\n", + ntb_topo_string(ndev->ntb.topo)); -static void bwd_link_recovery(struct work_struct *work) -{ - struct ntb_device *ndev = container_of(work, struct ntb_device, - lr_timer.work); - u32 status32; + off += scnprintf(buf + off, buf_size - off, + "B2B Offset -\t\t%#lx\n", ndev->b2b_off); + off += scnprintf(buf + off, buf_size - off, + "B2B MW Idx -\t\t%d\n", ndev->b2b_idx); + off += scnprintf(buf + off, buf_size - off, + "BAR4 Split -\t\t%s\n", + ndev->bar4_split ? "yes" : "no"); - bwd_recover_link(ndev); - /* There is a potential race between the 2 NTB devices recovering at the - * same time. If the times are the same, the link will not recover and - * the driver will be stuck in this loop forever. Add a random interval - * to the recovery time to prevent this race. - */ - msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME); - - status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) - goto retry; - - status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET); - if (status32 & BWD_IBIST_ERR_OFLOW) - goto retry; - - status32 = readl(ndev->reg_ofs.lnk_cntl); - if (!(status32 & BWD_CNTL_LINK_DOWN)) { - unsigned char speed, width; - u16 status16; - - status16 = readw(ndev->reg_ofs.lnk_stat); - width = (status16 & NTB_LINK_WIDTH_MASK) >> 4; - speed = (status16 & NTB_LINK_SPEED_MASK); - if (ndev->link_width != width || ndev->link_speed != speed) - goto retry; + off += scnprintf(buf + off, buf_size - off, + "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); + off += scnprintf(buf + off, buf_size - off, + "LNK STA -\t\t%#06x\n", ndev->lnk_sta); + + if (!ndev->reg->link_is_up(ndev)) { + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tDown\n"); + } else { + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tUp\n"); + off += scnprintf(buf + off, buf_size - off, + "Link Speed -\t\tPCI-E Gen %u\n", + NTB_LNK_STA_SPEED(ndev->lnk_sta)); + off += scnprintf(buf + off, buf_size - off, + "Link Width -\t\tx%u\n", + NTB_LNK_STA_WIDTH(ndev->lnk_sta)); } - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); - return; + off += scnprintf(buf + off, buf_size - off, + "Memory Window Count -\t%u\n", ndev->mw_count); + off += scnprintf(buf + off, buf_size - off, + "Scratchpad Count -\t%u\n", ndev->spad_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Count -\t%u\n", ndev->db_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); + + off += scnprintf(buf + off, buf_size - off, + "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask -\t\t%#llx\n", u.v64); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Bell -\t\t%#llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Incoming XLAT:\n"); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 2)); + off += scnprintf(buf + off, buf_size - off, + "XLAT23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_xlat, 4)); + off += scnprintf(buf + off, buf_size - off, + "XLAT45 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 2)); + off += scnprintf(buf + off, buf_size - off, + "LMT23 -\t\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + bar2_off(ndev->xlat_reg->bar2_limit, 4)); + off += scnprintf(buf + off, buf_size - off, + "LMT45 -\t\t\t%#018llx\n", u.v64); + + if (pdev_is_snb(ndev->ntb.pdev)) { + if (ntb_topo_is_b2b(ndev->ntb.topo)) { + off += scnprintf(buf + off, buf_size - off, + "\nNTB Outgoing B2B XLAT:\n"); + + u.v64 = ioread64(mmio + SNB_PBAR23XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_PBAR45XLAT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B XLAT45 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_PBAR23LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_PBAR45LMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "B2B LMT45 -\t\t%#018llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Secondary BAR:\n"); + + u.v64 = ioread64(mmio + SNB_SBAR0BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR01 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_SBAR23BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR23 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SNB_SBAR45BASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "SBAR45 -\t\t%#018llx\n", u.v64); + } + + off += scnprintf(buf + off, buf_size - off, + "\nSNB NTB Statistics:\n"); + + u.v16 = ioread16(mmio + SNB_USMEMMISS_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "Upstream Memory Miss -\t%u\n", u.v16); + + off += scnprintf(buf + off, buf_size - off, + "\nSNB NTB Hardware Errors:\n"); + + if (!pci_read_config_word(ndev->ntb.pdev, + SNB_DEVSTS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "DEVSTS -\t\t%#06x\n", u.v16); + + if (!pci_read_config_word(ndev->ntb.pdev, + SNB_LINK_STATUS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "LNKSTS -\t\t%#06x\n", u.v16); -retry: - schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT); + if (!pci_read_config_dword(ndev->ntb.pdev, + SNB_UNCERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "UNCERRSTS -\t\t%#06x\n", u.v32); + + if (!pci_read_config_dword(ndev->ntb.pdev, + SNB_CORERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "CORERRSTS -\t\t%#06x\n", u.v32); + } + + ret = simple_read_from_buffer(ubuf, count, offp, buf, off); + kfree(buf); + return ret; } -/* BWD doesn't have link status interrupt, poll on that platform */ -static void bwd_link_poll(struct work_struct *work) +static void ndev_init_debugfs(struct intel_ntb_dev *ndev) { - struct ntb_device *ndev = container_of(work, struct ntb_device, - hb_timer.work); - unsigned long ts = jiffies; - - /* If we haven't gotten an interrupt in a while, check the BWD link - * status bit - */ - if (ts > ndev->last_ts + NTB_HB_TIMEOUT) { - int rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, - "Error determining link status\n"); - - /* Check to see if a link error is the cause of the link down */ - if (ndev->link_status == NTB_LINK_DOWN) { - u32 status32 = readl(ndev->reg_base + - BWD_LTSSMSTATEJMP_OFFSET); - if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) { - schedule_delayed_work(&ndev->lr_timer, 0); - return; - } - } + if (!debugfs_dir) { + ndev->debugfs_dir = NULL; + ndev->debugfs_info = NULL; + } else { + ndev->debugfs_dir = + debugfs_create_dir(ndev_name(ndev), debugfs_dir); + if (!ndev->debugfs_dir) + ndev->debugfs_info = NULL; + else + ndev->debugfs_info = + debugfs_create_file("info", S_IRUSR, + ndev->debugfs_dir, ndev, + &intel_ntb_debugfs_info); } +} - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); +static void ndev_deinit_debugfs(struct intel_ntb_dev *ndev) +{ + debugfs_remove_recursive(ndev->debugfs_dir); } -static int ntb_xeon_setup(struct ntb_device *ndev) +static int intel_ntb_mw_count(struct ntb_dev *ntb) { - switch (ndev->conn_type) { - case NTB_CONN_B2B: - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_spads = SNB_MAX_B2B_SPADS; + return ntb_ndev(ntb)->mw_count; +} - /* There is a Xeon hardware errata related to writes to - * SDOORBELL or B2BDOORBELL in conjunction with inbound access - * to NTB MMIO Space, which may hang the system. To workaround - * this use the second memory window to access the interrupt and - * scratch pad registers on the remote system. - */ - if (ndev->wa_flags & WA_SNB_ERR) { - if (!ndev->mw[ndev->limits.max_mw - 1].bar_sz) - return -EINVAL; - - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.spad_write = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_SPAD_OFFSET; - ndev->reg_ofs.rdb = - ndev->mw[ndev->limits.max_mw - 1].vbase + - SNB_PDOORBELL_OFFSET; - - /* Set the Limit register to 4k, the minimum size, to - * prevent an illegal access - */ - writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + - SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - - ndev->limits.max_mw = SNB_ERRATA_MAX_MW; - } else { - /* HW Errata on bit 14 of b2bdoorbell register. Writes - * will not be mirrored to the remote system. Shrink - * the number of bits by one, since bit 14 is the last - * bit. - */ - ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; - ndev->reg_ofs.spad_write = ndev->reg_base + - SNB_B2B_SPAD_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + - SNB_B2B_DOORBELL_OFFSET; - - /* Disable the Limit register, just incase it is set to - * something silly. A 64bit write should handle it - * regardless of whether it has a split BAR or not. - */ - writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); - /* HW errata on the Limit registers. They can only be - * written when the base register is 4GB aligned and - * < 32bit. This should already be the case based on - * the driver defaults, but write the Limit registers - * first just in case. - */ - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - else - ndev->limits.max_mw = SNB_MAX_MW; - } +static int intel_ntb_mw_get_range(struct ntb_dev *ntb, int idx, + phys_addr_t *base, + resource_size_t *size, + resource_size_t *align, + resource_size_t *align_size) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + int bar; - /* The Xeon errata workaround requires setting SBAR Base - * addresses to known values, so that the PBAR XLAT can be - * pointed at SBAR0 of the remote system. - */ - if (ndev->dev_type == NTB_DEV_USD) { - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_DSD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_DSD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_USD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - } else { - writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base + - SNB_PBAR2XLAT_OFFSET); - if (ndev->wa_flags & WA_SNB_ERR) - writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - else { - if (ndev->split_bar) { - writel(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - writel(SNB_MBAR5_USD_ADDR, - ndev->reg_base + - SNB_PBAR5XLAT_OFFSET); - } else - writeq(SNB_MBAR4_USD_ADDR, - ndev->reg_base + - SNB_PBAR4XLAT_OFFSET); - - /* - * B2B_XLAT_OFFSET is a 64bit register, but can - * only take 32bit writes - */ - writel(SNB_MBAR01_USD_ADDR & 0xffffffff, - ndev->reg_base + SNB_B2B_XLAT_OFFSETL); - writel(SNB_MBAR01_USD_ADDR >> 32, - ndev->reg_base + SNB_B2B_XLAT_OFFSETU); - } - writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base + - SNB_SBAR0BASE_OFFSET); - writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base + - SNB_SBAR2BASE_OFFSET); - if (ndev->split_bar) { - writel(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); - writel(SNB_MBAR5_DSD_ADDR, ndev->reg_base + - SNB_SBAR5BASE_OFFSET); - } else - writeq(SNB_MBAR4_DSD_ADDR, ndev->reg_base + - SNB_SBAR4BASE_OFFSET); + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; - } - break; - case NTB_CONN_RP: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-RP disabled due to hardware errata.\n"); - return -EINVAL; - } + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - /* Note: The SDOORBELL is the cause of the errata. You REALLY - * don't want to touch it. - */ - ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET; - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_SBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - case NTB_CONN_TRANSPARENT: - if (ndev->wa_flags & WA_SNB_ERR) { - dev_err(&ndev->pdev->dev, - "NTB-TRANSPARENT disabled due to hardware errata.\n"); - return -EINVAL; - } + if (base) + *base = pci_resource_start(ndev->ntb.pdev, bar) + + (idx == ndev->b2b_idx ? ndev->b2b_off : 0); - /* Scratch pads need to have exclusive access from the primary - * or secondary side. Halve the num spads so that each side can - * have an equal amount. - */ - ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; - ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET; - /* Offset the start of the spads to correspond to whether it is - * primary or secondary - */ - ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET + - ndev->limits.max_spads * 4; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET; - - if (ndev->split_bar) { - ndev->reg_ofs.bar5_xlat = - ndev->reg_base + SNB_PBAR5XLAT_OFFSET; - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; - } else - ndev->limits.max_mw = SNB_MAX_MW; - break; - default: - /* - * we should never hit this. the detect function should've - * take cared of everything. - */ - return -EINVAL; - } + if (size) + *size = pci_resource_len(ndev->ntb.pdev, bar) - + (idx == ndev->b2b_idx ? ndev->b2b_off : 0); - ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; + if (align) + *align = pci_resource_len(ndev->ntb.pdev, bar); - ndev->limits.msix_cnt = SNB_MSIX_CNT; - ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; + if (align_size) + *align_size = 1; return 0; } -static int ntb_bwd_setup(struct ntb_device *ndev) +static int intel_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size) { - int rc; - u32 val; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + unsigned long base_reg, xlat_reg, limit_reg; + resource_size_t bar_size, mw_size; + void __iomem *mmio; + u64 base, limit, reg_val; + int bar; - ndev->hw_type = BWD_HW; + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &val); - if (rc) - return rc; + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; - switch ((val & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + bar_size = pci_resource_len(ndev->ntb.pdev, bar); + + if (idx == ndev->b2b_idx) + mw_size = bar_size - ndev->b2b_off; + else + mw_size = bar_size; + + /* hardware requires that addr is aligned to bar size */ + if (addr & (bar_size - 1)) return -EINVAL; + + /* make sure the range fits in the usable mw size */ + if (size > mw_size) + return -EINVAL; + + mmio = ndev->self_mmio; + base_reg = bar0_off(ndev->xlat_reg->bar0_base, bar); + xlat_reg = bar2_off(ndev->xlat_reg->bar2_xlat, bar); + limit_reg = bar2_off(ndev->xlat_reg->bar2_limit, bar); + + if (bar < 4 || !ndev->bar4_split) { + base = ioread64(mmio + base_reg); + + /* Set the limit if supported, if size is not mw_size */ + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = 0; + + /* set and verify setting the translation address */ + iowrite64(addr, mmio + xlat_reg); + reg_val = ioread64(mmio + xlat_reg); + if (reg_val != addr) { + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + /* set and verify setting the limit */ + iowrite64(limit, mmio + limit_reg); + reg_val = ioread64(mmio + limit_reg); + if (reg_val != limit) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + } else { + /* split bar addr range must all be 32 bit */ + if (addr & (~0ull << 32)) + return -EINVAL; + if ((addr + size) & (~0ull << 32)) + return -EINVAL; + + base = ioread32(mmio + base_reg); + + /* Set the limit if supported, if size is not mw_size */ + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = 0; + + /* set and verify setting the translation address */ + iowrite32(addr, mmio + xlat_reg); + reg_val = ioread32(mmio + xlat_reg); + if (reg_val != addr) { + iowrite32(0, mmio + xlat_reg); + return -EIO; + } + + /* set and verify setting the limit */ + iowrite32(limit, mmio + limit_reg); + reg_val = ioread32(mmio + limit_reg); + if (reg_val != limit) { + iowrite32(base, mmio + limit_reg); + iowrite32(0, mmio + xlat_reg); + return -EIO; + } } - if (val & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; + return 0; +} - /* Initiate PCI-E link training */ - rc = pci_write_config_dword(ndev->pdev, NTB_PPD_OFFSET, - val | BWD_PPD_INIT_LINK); - if (rc) - return rc; +static int intel_ntb_link_is_up(struct ntb_dev *ntb, + enum ntb_speed *speed, + enum ntb_width *width) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET; - ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET; - ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET; - ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET; - ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET; - ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET; - ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET; - ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET; - ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET; - ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET; - ndev->limits.max_mw = BWD_MAX_MW; - ndev->limits.max_spads = BWD_MAX_SPADS; - ndev->limits.max_db_bits = BWD_MAX_DB_BITS; - ndev->limits.msix_cnt = BWD_MSIX_CNT; - ndev->bits_per_vector = BWD_DB_BITS_PER_VEC; - - /* Since bwd doesn't have a link interrupt, setup a poll timer */ - INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll); - INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery); - schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT); + if (ndev->reg->link_is_up(ndev)) { + if (speed) + *speed = NTB_LNK_STA_SPEED(ndev->lnk_sta); + if (width) + *width = NTB_LNK_STA_WIDTH(ndev->lnk_sta); + return 1; + } else { + /* TODO MAYBE: is it possible to observe the link speed and + * width while link is training? */ + if (speed) + *speed = NTB_SPEED_NONE; + if (width) + *width = NTB_WIDTH_NONE; + return 0; + } +} + +static int intel_ntb_link_enable(struct ntb_dev *ntb, + enum ntb_speed max_speed, + enum ntb_width max_width) +{ + struct intel_ntb_dev *ndev; + u32 ntb_ctl; + + ndev = container_of(ntb, struct intel_ntb_dev, ntb); + + if (ndev->ntb.topo == NTB_TOPO_SEC) + return -EINVAL; + + dev_dbg(ndev_dev(ndev), + "Enabling link with max_speed %d max_width %d\n", + max_speed, max_width); + if (max_speed != NTB_SPEED_AUTO) + dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed); + if (max_width != NTB_WIDTH_AUTO) + dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width); + + ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); + ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; + ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; + if (ndev->bar4_split) + ntb_ctl |= NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP; + iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); return 0; } -static int ntb_device_setup(struct ntb_device *ndev) +static int intel_ntb_link_disable(struct ntb_dev *ntb) { - int rc; + struct intel_ntb_dev *ndev; + u32 ntb_cntl; - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_setup(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_bwd_setup(ndev); - else - rc = -ENODEV; + ndev = container_of(ntb, struct intel_ntb_dev, ntb); - if (rc) - return rc; + if (ndev->ntb.topo == NTB_TOPO_SEC) + return -EINVAL; - if (ndev->conn_type == NTB_CONN_B2B) - /* Enable Bus Master and Memory Space on the secondary side */ - writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, - ndev->reg_ofs.spci_cmd); + dev_dbg(ndev_dev(ndev), "Disabling link\n"); + + /* Bring NTB link down */ + ntb_cntl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_cntl &= ~(NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP); + ntb_cntl &= ~(NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP); + if (ndev->bar4_split) + ntb_cntl &= ~(NTB_CTL_P2S_BAR5_SNOOP | NTB_CTL_S2P_BAR5_SNOOP); + ntb_cntl |= NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK; + iowrite32(ntb_cntl, ndev->self_mmio + ndev->reg->ntb_ctl); return 0; } -static void ntb_device_free(struct ntb_device *ndev) +static int intel_ntb_db_is_unsafe(struct ntb_dev *ntb) { - if (is_ntb_atom(ndev)) { - cancel_delayed_work_sync(&ndev->hb_timer); - cancel_delayed_work_sync(&ndev->lr_timer); - } + return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_DB); } -static irqreturn_t bwd_callback_msix_irq(int irq, void *data) +static u64 intel_ntb_db_valid_mask(struct ntb_dev *ntb) { - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; + return ntb_ndev(ntb)->db_valid_mask; +} - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); +static int intel_ntb_db_vector_count(struct ntb_dev *ntb) +{ + struct intel_ntb_dev *ndev; - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); + ndev = container_of(ntb, struct intel_ntb_dev, ntb); - tasklet_schedule(&db_cb->irq_work); + return ndev->db_vec_count; +} - /* No need to check for the specific HB irq, any interrupt means - * we're connected. - */ - ndev->last_ts = jiffies; +static u64 intel_ntb_db_vector_mask(struct ntb_dev *ntb, int db_vector) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb); + if (db_vector < 0 || db_vector > ndev->db_vec_count) + return 0; - return IRQ_HANDLED; + return ndev->db_valid_mask & ndev_vec_mask(ndev, db_vector); } -static irqreturn_t xeon_callback_msix_irq(int irq, void *data) +static u64 intel_ntb_db_read(struct ntb_dev *ntb) { - struct ntb_db_cb *db_cb = data; - struct ntb_device *ndev = db_cb->ndev; - unsigned long mask; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, - db_cb->db_num); + return ndev_db_read(ndev, + ndev->self_mmio + + ndev->self_reg->db_bell); +} - mask = readw(ndev->reg_ofs.ldb_mask); - set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); - writew(mask, ndev->reg_ofs.ldb_mask); +static int intel_ntb_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - tasklet_schedule(&db_cb->irq_work); + return ndev_db_write(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_bell); +} - /* On Sandybridge, there are 16 bits in the interrupt register - * but only 4 vectors. So, 5 bits are assigned to the first 3 - * vectors, with the 4th having a single bit for link - * interrupts. - */ - writew(((1 << ndev->bits_per_vector) - 1) << - (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb); +static int intel_ntb_db_set_mask(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - return IRQ_HANDLED; + return ndev_db_set_mask(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_mask); } -/* Since we do not have a HW doorbell in BWD, this is only used in JF/JT */ -static irqreturn_t xeon_event_msix_irq(int irq, void *dev) +static int intel_ntb_db_clear_mask(struct ntb_dev *ntb, u64 db_bits) { - struct ntb_device *ndev = dev; - int rc; - - dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for Events\n", irq); + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - rc = ntb_link_status(ndev); - if (rc) - dev_err(&ndev->pdev->dev, "Error determining link status\n"); + return ndev_db_clear_mask(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_mask); +} - /* bit 15 is always the link bit */ - writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); +static int intel_ntb_peer_db_addr(struct ntb_dev *ntb, + phys_addr_t *db_addr, + resource_size_t *db_size) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - return IRQ_HANDLED; + return ndev_db_addr(ndev, db_addr, db_size, ndev->peer_addr, + ndev->peer_reg->db_bell); } -static irqreturn_t ntb_interrupt(int irq, void *dev) +static int intel_ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) { - struct ntb_device *ndev = dev; - unsigned int i = 0; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - if (is_ntb_atom(ndev)) { - u64 ldb = readq(ndev->reg_ofs.ldb); + return ndev_db_write(ndev, db_bits, + ndev->peer_mmio + + ndev->peer_reg->db_bell); +} - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb); +static int intel_ntb_spad_is_unsafe(struct ntb_dev *ntb) +{ + return ndev_ignore_unsafe(ntb_ndev(ntb), NTB_UNSAFE_SPAD); +} - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - bwd_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } else { - u16 ldb = readw(ndev->reg_ofs.ldb); +static int intel_ntb_spad_count(struct ntb_dev *ntb) +{ + struct intel_ntb_dev *ndev; - dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb); + ndev = container_of(ntb, struct intel_ntb_dev, ntb); - if (ldb & SNB_DB_HW_LINK) { - xeon_event_msix_irq(irq, dev); - ldb &= ~SNB_DB_HW_LINK; - } + return ndev->spad_count; +} - while (ldb) { - i = __ffs(ldb); - ldb &= ldb - 1; - xeon_callback_msix_irq(irq, &ndev->db_cb[i]); - } - } +static u32 intel_ntb_spad_read(struct ntb_dev *ntb, int idx) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - return IRQ_HANDLED; + return ndev_spad_read(ndev, idx, + ndev->self_mmio + + ndev->self_reg->spad); } -static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries) +static int intel_ntb_spad_write(struct ntb_dev *ntb, + int idx, u32 val) { - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - if (msix_entries < ndev->limits.msix_cnt) - return -ENOSPC; + return ndev_spad_write(ndev, idx, val, + ndev->self_mmio + + ndev->self_reg->spad); +} - rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries); - if (rc < 0) - return rc; +static int intel_ntb_peer_spad_addr(struct ntb_dev *ntb, int idx, + phys_addr_t *spad_addr) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); + return ndev_spad_addr(ndev, idx, spad_addr, ndev->peer_addr, + ndev->peer_reg->spad); +} - if (i == msix_entries - 1) { - rc = request_irq(msix->vector, - xeon_event_msix_irq, 0, - "ntb-event-msix", ndev); - if (rc) - goto err; - } else { - rc = request_irq(msix->vector, - xeon_callback_msix_irq, 0, - "ntb-callback-msix", - &ndev->db_cb[i]); - if (rc) - goto err; - } - } +static u32 intel_ntb_peer_spad_read(struct ntb_dev *ntb, int idx) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries - 1; + return ndev_spad_read(ndev, idx, + ndev->peer_mmio + + ndev->peer_reg->spad); +} - return 0; +static int intel_ntb_peer_spad_write(struct ntb_dev *ntb, + int idx, u32 val) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); -err: - while (--i >= 0) { - /* Code never reaches here for entry nr 'ndev->num_msix - 1' */ - msix = &ndev->msix_entries[i]; - free_irq(msix->vector, &ndev->db_cb[i]); - } + return ndev_spad_write(ndev, idx, val, + ndev->peer_mmio + + ndev->peer_reg->spad); +} - pci_disable_msix(pdev); - ndev->num_msix = 0; +/* BWD */ - return rc; +static u64 bwd_db_ioread(void __iomem *mmio) +{ + return ioread64(mmio); +} + +static void bwd_db_iowrite(u64 bits, void __iomem *mmio) +{ + iowrite64(bits, mmio); } -static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries) +static int bwd_poll_link(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; - struct msix_entry *msix; - int rc, i; + u32 ntb_ctl; - msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries, - 1, msix_entries); - if (msix_entries < 0) - return msix_entries; + ntb_ctl = ioread32(ndev->self_mmio + BWD_NTBCNTL_OFFSET); - for (i = 0; i < msix_entries; i++) { - msix = &ndev->msix_entries[i]; - WARN_ON(!msix->vector); + if (ntb_ctl == ndev->ntb_ctl) + return 0; - rc = request_irq(msix->vector, bwd_callback_msix_irq, 0, - "ntb-callback-msix", &ndev->db_cb[i]); - if (rc) - goto err; - } + ndev->ntb_ctl = ntb_ctl; - ndev->num_msix = msix_entries; - ndev->max_cbs = msix_entries; + ndev->lnk_sta = ioread32(ndev->self_mmio + BWD_LINK_STATUS_OFFSET); - return 0; + return 1; +} -err: - while (--i >= 0) - free_irq(msix->vector, &ndev->db_cb[i]); +static int bwd_link_is_up(struct intel_ntb_dev *ndev) +{ + return BWD_NTB_CTL_ACTIVE(ndev->ntb_ctl); +} - pci_disable_msix(pdev); - ndev->num_msix = 0; +static int bwd_link_is_err(struct intel_ntb_dev *ndev) +{ + if (ioread32(ndev->self_mmio + BWD_LTSSMSTATEJMP_OFFSET) + & BWD_LTSSMSTATEJMP_FORCEDETECT) + return 1; - return rc; + if (ioread32(ndev->self_mmio + BWD_IBSTERRRCRVSTS0_OFFSET) + & BWD_IBIST_ERR_OFLOW) + return 1; + + return 0; } -static int ntb_setup_msix(struct ntb_device *ndev) +static inline enum ntb_topo bwd_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd) { - struct pci_dev *pdev = ndev->pdev; - int msix_entries; - int rc, i; + switch (ppd & BWD_PPD_TOPO_MASK) { + case BWD_PPD_TOPO_B2B_USD: + dev_dbg(ndev_dev(ndev), "PPD %d B2B USD\n", ppd); + return NTB_TOPO_B2B_USD; + + case BWD_PPD_TOPO_B2B_DSD: + dev_dbg(ndev_dev(ndev), "PPD %d B2B DSD\n", ppd); + return NTB_TOPO_B2B_DSD; + + case BWD_PPD_TOPO_PRI_USD: + case BWD_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ + case BWD_PPD_TOPO_SEC_USD: + case BWD_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ + dev_dbg(ndev_dev(ndev), "PPD %d non B2B disabled\n", ppd); + return NTB_TOPO_NONE; + } - msix_entries = pci_msix_vec_count(pdev); - if (msix_entries < 0) { - rc = msix_entries; - goto err; - } else if (msix_entries > ndev->limits.msix_cnt) { - rc = -EINVAL; - goto err; + dev_dbg(ndev_dev(ndev), "PPD %d invalid\n", ppd); + return NTB_TOPO_NONE; +} + +static void bwd_link_hb(struct work_struct *work) +{ + struct intel_ntb_dev *ndev = hb_ndev(work); + unsigned long poll_ts; + void __iomem *mmio; + u32 status32; + + poll_ts = ndev->last_ts + BWD_LINK_HB_TIMEOUT; + + /* Delay polling the link status if an interrupt was received, + * unless the cached link status says the link is down. + */ + if (time_after(poll_ts, jiffies) && bwd_link_is_up(ndev)) { + schedule_delayed_work(&ndev->hb_timer, poll_ts - jiffies); + return; } - ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries, - GFP_KERNEL); - if (!ndev->msix_entries) { - rc = -ENOMEM; - goto err; + if (bwd_poll_link(ndev)) + ntb_link_event(&ndev->ntb); + + if (bwd_link_is_up(ndev) || !bwd_link_is_err(ndev)) { + schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT); + return; } - for (i = 0; i < msix_entries; i++) - ndev->msix_entries[i].entry = i; + /* Link is down with error: recover the link! */ - if (is_ntb_atom(ndev)) - rc = ntb_setup_bwd_msix(ndev, msix_entries); - else - rc = ntb_setup_snb_msix(ndev, msix_entries); - if (rc) - goto err1; + mmio = ndev->self_mmio; - return 0; + /* Driver resets the NTB ModPhy lanes - magic! */ + iowrite8(0xe0, mmio + BWD_MODPHY_PCSREG6); + iowrite8(0x40, mmio + BWD_MODPHY_PCSREG4); + iowrite8(0x60, mmio + BWD_MODPHY_PCSREG4); + iowrite8(0x60, mmio + BWD_MODPHY_PCSREG6); -err1: - kfree(ndev->msix_entries); -err: - dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n"); - return rc; + /* Driver waits 100ms to allow the NTB ModPhy to settle */ + msleep(100); + + /* Clear AER Errors, write to clear */ + status32 = ioread32(mmio + BWD_ERRCORSTS_OFFSET); + dev_dbg(ndev_dev(ndev), "ERRCORSTS = %x\n", status32); + status32 &= PCI_ERR_COR_REP_ROLL; + iowrite32(status32, mmio + BWD_ERRCORSTS_OFFSET); + + /* Clear unexpected electrical idle event in LTSSM, write to clear */ + status32 = ioread32(mmio + BWD_LTSSMERRSTS0_OFFSET); + dev_dbg(ndev_dev(ndev), "LTSSMERRSTS0 = %x\n", status32); + status32 |= BWD_LTSSMERRSTS0_UNEXPECTEDEI; + iowrite32(status32, mmio + BWD_LTSSMERRSTS0_OFFSET); + + /* Clear DeSkew Buffer error, write to clear */ + status32 = ioread32(mmio + BWD_DESKEWSTS_OFFSET); + dev_dbg(ndev_dev(ndev), "DESKEWSTS = %x\n", status32); + status32 |= BWD_DESKEWSTS_DBERR; + iowrite32(status32, mmio + BWD_DESKEWSTS_OFFSET); + + status32 = ioread32(mmio + BWD_IBSTERRRCRVSTS0_OFFSET); + dev_dbg(ndev_dev(ndev), "IBSTERRRCRVSTS0 = %x\n", status32); + status32 &= BWD_IBIST_ERR_OFLOW; + iowrite32(status32, mmio + BWD_IBSTERRRCRVSTS0_OFFSET); + + /* Releases the NTB state machine to allow the link to retrain */ + status32 = ioread32(mmio + BWD_LTSSMSTATEJMP_OFFSET); + dev_dbg(ndev_dev(ndev), "LTSSMSTATEJMP = %x\n", status32); + status32 &= ~BWD_LTSSMSTATEJMP_FORCEDETECT; + iowrite32(status32, mmio + BWD_LTSSMSTATEJMP_OFFSET); + + /* There is a potential race between the 2 NTB devices recovering at the + * same time. If the times are the same, the link will not recover and + * the driver will be stuck in this loop forever. Add a random interval + * to the recovery time to prevent this race. + */ + schedule_delayed_work(&ndev->hb_timer, BWD_LINK_RECOVERY_TIME + + prandom_u32() % BWD_LINK_RECOVERY_TIME); } -static int ntb_setup_msi(struct ntb_device *ndev) +static int bwd_init_isr(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; int rc; - rc = pci_enable_msi(pdev); + rc = ndev_init_isr(ndev, 1, BWD_DB_MSIX_VECTOR_COUNT, + BWD_DB_MSIX_VECTOR_SHIFT, BWD_DB_TOTAL_SHIFT); if (rc) return rc; - rc = request_irq(pdev->irq, ntb_interrupt, 0, "ntb-msi", ndev); - if (rc) { - pci_disable_msi(pdev); - dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); - return rc; - } + /* BWD doesn't have link status interrupt, poll on that platform */ + ndev->last_ts = jiffies; + INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_hb); + schedule_delayed_work(&ndev->hb_timer, BWD_LINK_HB_TIMEOUT); return 0; } -static int ntb_setup_intx(struct ntb_device *ndev) +static void bwd_deinit_isr(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; - int rc; + cancel_delayed_work_sync(&ndev->hb_timer); + ndev_deinit_isr(ndev); +} - /* Verify intx is enabled */ - pci_intx(pdev, 1); +static int bwd_init_ntb(struct intel_ntb_dev *ndev) +{ + ndev->mw_count = BWD_MW_COUNT; + ndev->spad_count = BWD_SPAD_COUNT; + ndev->db_count = BWD_DB_COUNT; - rc = request_irq(pdev->irq, ntb_interrupt, IRQF_SHARED, "ntb-intx", - ndev); - if (rc) - return rc; + switch (ndev->ntb.topo) { + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + ndev->self_reg = &bwd_pri_reg; + ndev->peer_reg = &bwd_b2b_reg; + ndev->xlat_reg = &bwd_sec_xlat; + + /* Enable Bus Master and Memory Space on the secondary side */ + iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->self_mmio + BWD_SPCICMD_OFFSET); + + break; + + default: + return -EINVAL; + } + + ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; return 0; } -static int ntb_setup_interrupts(struct ntb_device *ndev) +static int bwd_init_dev(struct intel_ntb_dev *ndev) { + u32 ppd; int rc; - /* On BWD, disable all interrupts. On SNB, disable all but Link - * Interrupt. The rest will be unmasked as callbacks are registered. - */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else { - u16 var = 1 << SNB_LINK_DB; - writew(~var, ndev->reg_ofs.ldb_mask); - } - - rc = ntb_setup_msix(ndev); - if (!rc) - goto done; + rc = pci_read_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, &ppd); + if (rc) + return -EIO; - ndev->bits_per_vector = 1; - ndev->max_cbs = ndev->limits.max_db_bits; + ndev->ntb.topo = bwd_ppd_topo(ndev, ppd); + if (ndev->ntb.topo == NTB_TOPO_NONE) + return -EINVAL; - rc = ntb_setup_msi(ndev); - if (!rc) - goto done; + rc = bwd_init_ntb(ndev); + if (rc) + return rc; - rc = ntb_setup_intx(ndev); - if (rc) { - dev_err(&ndev->pdev->dev, "no usable interrupts\n"); + rc = bwd_init_isr(ndev); + if (rc) return rc; + + if (ndev->ntb.topo != NTB_TOPO_SEC) { + /* Initiate PCI-E link training */ + rc = pci_write_config_dword(ndev->ntb.pdev, BWD_PPD_OFFSET, + ppd | BWD_PPD_INIT_LINK); + if (rc) + return rc; } -done: return 0; } -static void ntb_free_interrupts(struct ntb_device *ndev) +static void bwd_deinit_dev(struct intel_ntb_dev *ndev) { - struct pci_dev *pdev = ndev->pdev; + bwd_deinit_isr(ndev); +} - /* mask interrupts */ - if (is_ntb_atom(ndev)) - writeq(~0, ndev->reg_ofs.ldb_mask); - else - writew(~0, ndev->reg_ofs.ldb_mask); +/* SNB */ - if (ndev->num_msix) { - struct msix_entry *msix; - u32 i; +static u64 snb_db_ioread(void __iomem *mmio) +{ + return (u64)ioread16(mmio); +} - for (i = 0; i < ndev->num_msix; i++) { - msix = &ndev->msix_entries[i]; - if (is_ntb_xeon(ndev) && i == ndev->num_msix - 1) - free_irq(msix->vector, ndev); - else - free_irq(msix->vector, &ndev->db_cb[i]); - } - pci_disable_msix(pdev); - kfree(ndev->msix_entries); - } else { - free_irq(pdev->irq, ndev); +static void snb_db_iowrite(u64 bits, void __iomem *mmio) +{ + iowrite16((u16)bits, mmio); +} - if (pci_dev_msi_enabled(pdev)) - pci_disable_msi(pdev); - } +static int snb_poll_link(struct intel_ntb_dev *ndev) +{ + u16 reg_val; + int rc; + + ndev->reg->db_iowrite(ndev->db_link_mask, + ndev->self_mmio + + ndev->self_reg->db_bell); + + rc = pci_read_config_word(ndev->ntb.pdev, + SNB_LINK_STATUS_OFFSET, ®_val); + if (rc) + return 0; + + if (reg_val == ndev->lnk_sta) + return 0; + + ndev->lnk_sta = reg_val; + + return 1; } -static int ntb_create_callbacks(struct ntb_device *ndev) +static int snb_link_is_up(struct intel_ntb_dev *ndev) { - int i; + return NTB_LNK_STA_ACTIVE(ndev->lnk_sta); +} - /* Chicken-egg issue. We won't know how many callbacks are necessary - * until we see how many MSI-X vectors we get, but these pointers need - * to be passed into the MSI-X register function. So, we allocate the - * max, knowing that they might not all be used, to work around this. - */ - ndev->db_cb = kcalloc(ndev->limits.max_db_bits, - sizeof(struct ntb_db_cb), - GFP_KERNEL); - if (!ndev->db_cb) - return -ENOMEM; +static inline enum ntb_topo snb_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd) +{ + switch (ppd & SNB_PPD_TOPO_MASK) { + case SNB_PPD_TOPO_B2B_USD: + return NTB_TOPO_B2B_USD; + + case SNB_PPD_TOPO_B2B_DSD: + return NTB_TOPO_B2B_DSD; + + case SNB_PPD_TOPO_PRI_USD: + case SNB_PPD_TOPO_PRI_DSD: /* accept bogus PRI_DSD */ + return NTB_TOPO_PRI; - for (i = 0; i < ndev->limits.max_db_bits; i++) { - ndev->db_cb[i].db_num = i; - ndev->db_cb[i].ndev = ndev; + case SNB_PPD_TOPO_SEC_USD: + case SNB_PPD_TOPO_SEC_DSD: /* accept bogus SEC_DSD */ + return NTB_TOPO_SEC; } - return 0; + return NTB_TOPO_NONE; } -static void ntb_free_callbacks(struct ntb_device *ndev) +static inline int snb_ppd_bar4_split(struct intel_ntb_dev *ndev, u8 ppd) { - int i; + if (ppd & SNB_PPD_SPLIT_BAR_MASK) { + dev_dbg(ndev_dev(ndev), "PPD %d split bar\n", ppd); + return 1; + } + return 0; +} - for (i = 0; i < ndev->limits.max_db_bits; i++) - ntb_unregister_db_callback(ndev, i); +static int snb_init_isr(struct intel_ntb_dev *ndev) +{ + return ndev_init_isr(ndev, SNB_DB_MSIX_VECTOR_COUNT, + SNB_DB_MSIX_VECTOR_COUNT, + SNB_DB_MSIX_VECTOR_SHIFT, + SNB_DB_TOTAL_SHIFT); +} - kfree(ndev->db_cb); +static void snb_deinit_isr(struct intel_ntb_dev *ndev) +{ + ndev_deinit_isr(ndev); } -static ssize_t ntb_debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) +static int snb_setup_b2b_mw(struct intel_ntb_dev *ndev, + const struct intel_b2b_addr *addr, + const struct intel_b2b_addr *peer_addr) { - struct ntb_device *ndev; - char *buf; - ssize_t ret, offset, out_count; + struct pci_dev *pdev; + void __iomem *mmio; + resource_size_t bar_size; + phys_addr_t bar_addr; + int b2b_bar; + u8 bar_sz; + + pdev = ndev_pdev(ndev); + mmio = ndev->self_mmio; + + if (ndev->b2b_idx >= ndev->mw_count) { + dev_dbg(ndev_dev(ndev), "not using b2b mw\n"); + b2b_bar = 0; + ndev->b2b_off = 0; + } else { + b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx); + if (b2b_bar < 0) + return -EIO; - out_count = 500; + dev_dbg(ndev_dev(ndev), "using b2b mw bar %d\n", b2b_bar); - buf = kmalloc(out_count, GFP_KERNEL); - if (!buf) - return -ENOMEM; + bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar); - ndev = filp->private_data; - offset = 0; - offset += snprintf(buf + offset, out_count - offset, - "NTB Device Information:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Connection Type - \t\t%s\n", - ndev->conn_type == NTB_CONN_TRANSPARENT ? - "Transparent" : (ndev->conn_type == NTB_CONN_B2B) ? - "Back to back" : "Root Port"); - offset += snprintf(buf + offset, out_count - offset, - "Device Type - \t\t\t%s\n", - ndev->dev_type == NTB_DEV_USD ? - "DSD/USP" : "USD/DSP"); - offset += snprintf(buf + offset, out_count - offset, - "Max Number of Callbacks - \t%u\n", - ntb_max_cbs(ndev)); - offset += snprintf(buf + offset, out_count - offset, - "Link Status - \t\t\t%s\n", - ntb_hw_link_status(ndev) ? "Up" : "Down"); - if (ntb_hw_link_status(ndev)) { - offset += snprintf(buf + offset, out_count - offset, - "Link Speed - \t\t\tPCI-E Gen %u\n", - ndev->link_speed); - offset += snprintf(buf + offset, out_count - offset, - "Link Width - \t\t\tx%u\n", - ndev->link_width); - } + dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size); - if (is_ntb_xeon(ndev)) { - u32 status32; - u16 status16; - int rc; - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Device Statistics:\n"); - offset += snprintf(buf + offset, out_count - offset, - "Upstream Memory Miss - \t%u\n", - readw(ndev->reg_base + - SNB_USMEMMISS_OFFSET)); - - offset += snprintf(buf + offset, out_count - offset, - "\nNTB Hardware Errors:\n"); - - rc = pci_read_config_word(ndev->pdev, SNB_DEVSTS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "DEVSTS - \t%#06x\n", status16); - - rc = pci_read_config_word(ndev->pdev, SNB_LINK_STATUS_OFFSET, - &status16); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "LNKSTS - \t%#06x\n", status16); - - rc = pci_read_config_dword(ndev->pdev, SNB_UNCERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "UNCERRSTS - \t%#010x\n", status32); - - rc = pci_read_config_dword(ndev->pdev, SNB_CORERRSTS_OFFSET, - &status32); - if (!rc) - offset += snprintf(buf + offset, out_count - offset, - "CORERRSTS - \t%#010x\n", status32); + if (b2b_mw_share && SNB_B2B_MIN_SIZE <= bar_size >> 1) { + dev_dbg(ndev_dev(ndev), + "b2b using first half of bar\n"); + ndev->b2b_off = bar_size >> 1; + } else if (SNB_B2B_MIN_SIZE <= bar_size) { + dev_dbg(ndev_dev(ndev), + "b2b using whole bar\n"); + ndev->b2b_off = 0; + --ndev->mw_count; + } else { + dev_dbg(ndev_dev(ndev), + "b2b bar size is too small\n"); + return -EIO; + } } - if (offset > out_count) - offset = out_count; + /* Reset the secondary bar sizes to match the primary bar sizes, + * except disable or halve the size of the b2b secondary bar. + * + * Note: code for each specific bar size register, because the register + * offsets are not in a consistent order (bar5sz comes after ppd, odd). + */ + pci_read_config_byte(pdev, SNB_PBAR23SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR23SZ %#x\n", bar_sz); + if (b2b_bar == 2) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR23SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR23SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR23SZ %#x\n", bar_sz); + + if (!ndev->bar4_split) { + pci_read_config_byte(pdev, SNB_PBAR45SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR45SZ %#x\n", bar_sz); + if (b2b_bar == 4) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR45SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR45SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR45SZ %#x\n", bar_sz); + } else { + pci_read_config_byte(pdev, SNB_PBAR4SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR4SZ %#x\n", bar_sz); + if (b2b_bar == 4) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR4SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR4SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR4SZ %#x\n", bar_sz); + + pci_read_config_byte(pdev, SNB_PBAR5SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "PBAR5SZ %#x\n", bar_sz); + if (b2b_bar == 5) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + pci_write_config_byte(pdev, SNB_SBAR5SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SNB_SBAR5SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "SBAR5SZ %#x\n", bar_sz); + } - ret = simple_read_from_buffer(ubuf, count, offp, buf, offset); - kfree(buf); - return ret; -} + /* SBAR01 hit by first part of the b2b bar */ + if (b2b_bar == 0) + bar_addr = addr->bar0_addr; + else if (b2b_bar == 2) + bar_addr = addr->bar2_addr64; + else if (b2b_bar == 4 && !ndev->bar4_split) + bar_addr = addr->bar4_addr64; + else if (b2b_bar == 4) + bar_addr = addr->bar4_addr32; + else if (b2b_bar == 5) + bar_addr = addr->bar5_addr32; + else + return -EIO; -static const struct file_operations ntb_debugfs_info = { - .owner = THIS_MODULE, - .open = simple_open, - .read = ntb_debugfs_read, -}; + dev_dbg(ndev_dev(ndev), "SBAR01 %#018llx\n", bar_addr); + iowrite64(bar_addr, mmio + SNB_SBAR0BASE_OFFSET); -static void ntb_setup_debugfs(struct ntb_device *ndev) -{ - if (!debugfs_initialized()) - return; + /* Other SBAR are normally hit by the PBAR xlat, except for b2b bar. + * The b2b bar is either disabled above, or configured half-size, and + * it starts at the PBAR xlat + offset. + */ - if (!debugfs_dir) - debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR23BASE_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR23BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR23 %#018llx\n", bar_addr); + + if (!ndev->bar4_split) { + bar_addr = addr->bar4_addr64 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR45BASE_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR45BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR45 %#018llx\n", bar_addr); + } else { + bar_addr = addr->bar4_addr32 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR4BASE_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR4BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR4 %#010llx\n", bar_addr); + + bar_addr = addr->bar5_addr32 + + (b2b_bar == 5 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR5BASE_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR5BASE_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR5 %#010llx\n", bar_addr); + } - ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev), - debugfs_dir); - if (ndev->debugfs_dir) - ndev->debugfs_info = debugfs_create_file("info", S_IRUSR, - ndev->debugfs_dir, - ndev, - &ntb_debugfs_info); -} + /* setup incoming bar limits == base addrs (zero length windows) */ -static void ntb_free_debugfs(struct ntb_device *ndev) -{ - debugfs_remove_recursive(ndev->debugfs_dir); + bar_addr = addr->bar2_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR23LMT_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR23LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR23LMT %#018llx\n", bar_addr); - if (debugfs_dir && simple_empty(debugfs_dir)) { - debugfs_remove_recursive(debugfs_dir); - debugfs_dir = NULL; + if (!ndev->bar4_split) { + bar_addr = addr->bar4_addr64 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SNB_SBAR45LMT_OFFSET); + bar_addr = ioread64(mmio + SNB_SBAR45LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR45LMT %#018llx\n", bar_addr); + } else { + bar_addr = addr->bar4_addr32 + + (b2b_bar == 4 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR4LMT_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR4LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR4LMT %#010llx\n", bar_addr); + + bar_addr = addr->bar5_addr32 + + (b2b_bar == 5 ? ndev->b2b_off : 0); + iowrite32(bar_addr, mmio + SNB_SBAR5LMT_OFFSET); + bar_addr = ioread32(mmio + SNB_SBAR5LMT_OFFSET); + dev_dbg(ndev_dev(ndev), "SBAR5LMT %#05llx\n", bar_addr); } -} -static void ntb_hw_link_up(struct ntb_device *ndev) -{ - if (ndev->conn_type == NTB_CONN_TRANSPARENT) - ntb_link_event(ndev, NTB_LINK_UP); - else { - u32 ntb_cntl; + /* zero incoming translation addrs */ + iowrite64(0, mmio + SNB_SBAR23XLAT_OFFSET); - /* Let's bring the NTB link up */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); - ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; - ntb_cntl |= NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP; - if (ndev->split_bar) - ntb_cntl |= NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP; + if (!ndev->bar4_split) { + iowrite64(0, mmio + SNB_SBAR45XLAT_OFFSET); + } else { + iowrite32(0, mmio + SNB_SBAR4XLAT_OFFSET); + iowrite32(0, mmio + SNB_SBAR5XLAT_OFFSET); + } - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + /* zero outgoing translation limits (whole bar size windows) */ + iowrite64(0, mmio + SNB_PBAR23LMT_OFFSET); + if (!ndev->bar4_split) { + iowrite64(0, mmio + SNB_PBAR45LMT_OFFSET); + } else { + iowrite32(0, mmio + SNB_PBAR4LMT_OFFSET); + iowrite32(0, mmio + SNB_PBAR5LMT_OFFSET); } -} -static void ntb_hw_link_down(struct ntb_device *ndev) -{ - u32 ntb_cntl; + /* set outgoing translation offsets */ + bar_addr = peer_addr->bar2_addr64; + iowrite64(bar_addr, mmio + SNB_PBAR23XLAT_OFFSET); + bar_addr = ioread64(mmio + SNB_PBAR23XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR23XLAT %#018llx\n", bar_addr); + + if (!ndev->bar4_split) { + bar_addr = peer_addr->bar4_addr64; + iowrite64(bar_addr, mmio + SNB_PBAR45XLAT_OFFSET); + bar_addr = ioread64(mmio + SNB_PBAR45XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR45XLAT %#018llx\n", bar_addr); + } else { + bar_addr = peer_addr->bar4_addr32; + iowrite32(bar_addr, mmio + SNB_PBAR4XLAT_OFFSET); + bar_addr = ioread32(mmio + SNB_PBAR4XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR4XLAT %#010llx\n", bar_addr); + + bar_addr = peer_addr->bar5_addr32; + iowrite32(bar_addr, mmio + SNB_PBAR5XLAT_OFFSET); + bar_addr = ioread32(mmio + SNB_PBAR5XLAT_OFFSET); + dev_dbg(ndev_dev(ndev), "PBAR5XLAT %#010llx\n", bar_addr); + } - if (ndev->conn_type == NTB_CONN_TRANSPARENT) { - ntb_link_event(ndev, NTB_LINK_DOWN); - return; + /* set the translation offset for b2b registers */ + if (b2b_bar == 0) + bar_addr = peer_addr->bar0_addr; + else if (b2b_bar == 2) + bar_addr = peer_addr->bar2_addr64; + else if (b2b_bar == 4 && !ndev->bar4_split) + bar_addr = peer_addr->bar4_addr64; + else if (b2b_bar == 4) + bar_addr = peer_addr->bar4_addr32; + else if (b2b_bar == 5) + bar_addr = peer_addr->bar5_addr32; + else + return -EIO; + + /* B2B_XLAT_OFFSET is 64bit, but can only take 32bit writes */ + dev_dbg(ndev_dev(ndev), "B2BXLAT %#018llx\n", bar_addr); + iowrite32(bar_addr, mmio + SNB_B2B_XLAT_OFFSETL); + iowrite32(bar_addr >> 32, mmio + SNB_B2B_XLAT_OFFSETU); + + if (b2b_bar) { + /* map peer ntb mmio config space registers */ + ndev->peer_mmio = pci_iomap(pdev, b2b_bar, + SNB_B2B_MIN_SIZE); + if (!ndev->peer_mmio) + return -EIO; } - /* Bring NTB link down */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); - ntb_cntl &= ~(NTB_CNTL_P2S_BAR4_SNOOP | NTB_CNTL_S2P_BAR4_SNOOP); - if (ndev->split_bar) - ntb_cntl &= ~(NTB_CNTL_P2S_BAR5_SNOOP | - NTB_CNTL_S2P_BAR5_SNOOP); - ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + return 0; } -static void ntb_max_mw_detect(struct ntb_device *ndev) +static int snb_init_ntb(struct intel_ntb_dev *ndev) { - if (ndev->split_bar) - ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW; + int rc; + + if (ndev->bar4_split) + ndev->mw_count = HSX_SPLIT_BAR_MW_COUNT; else - ndev->limits.max_mw = SNB_MAX_MW; -} + ndev->mw_count = SNB_MW_COUNT; -static int ntb_xeon_detect(struct ntb_device *ndev) -{ - int rc, bars_mask; - u32 bars; - u8 ppd; + ndev->spad_count = SNB_SPAD_COUNT; + ndev->db_count = SNB_DB_COUNT; + ndev->db_link_mask = SNB_DB_LINK_BIT; - ndev->hw_type = SNB_HW; + switch (ndev->ntb.topo) { + case NTB_TOPO_PRI: + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { + dev_err(ndev_dev(ndev), "NTB Primary config disabled\n"); + return -EINVAL; + } + /* use half the spads for the peer */ + ndev->spad_count >>= 1; + ndev->self_reg = &snb_pri_reg; + ndev->peer_reg = &snb_sec_reg; + ndev->xlat_reg = &snb_sec_xlat; + break; - rc = pci_read_config_byte(ndev->pdev, NTB_PPD_OFFSET, &ppd); - if (rc) - return -EIO; + case NTB_TOPO_SEC: + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { + dev_err(ndev_dev(ndev), "NTB Secondary config disabled\n"); + return -EINVAL; + } + /* use half the spads for the peer */ + ndev->spad_count >>= 1; + ndev->self_reg = &snb_sec_reg; + ndev->peer_reg = &snb_pri_reg; + ndev->xlat_reg = &snb_pri_xlat; + break; - if (ppd & SNB_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_USD; - else - ndev->dev_type = NTB_DEV_DSD; + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + ndev->self_reg = &snb_pri_reg; + ndev->peer_reg = &snb_b2b_reg; + ndev->xlat_reg = &snb_sec_xlat; - ndev->split_bar = (ppd & SNB_PPD_SPLIT_BAR) ? 1 : 0; + if (ndev->hwerr_flags & NTB_HWERR_SDOORBELL_LOCKUP) { + ndev->peer_reg = &snb_pri_reg; - switch (ppd & SNB_PPD_CONN_TYPE) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - dev_info(&ndev->pdev->dev, "Conn Type = RP\n"); - ndev->conn_type = NTB_CONN_RP; - break; - case NTB_CONN_TRANSPARENT: - dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n"); - ndev->conn_type = NTB_CONN_TRANSPARENT; - /* - * This mode is default to USD/DSP. HW does not report - * properly in transparent mode as it has no knowledge of - * NTB. We will just force correct here. - */ - ndev->dev_type = NTB_DEV_USD; + if (b2b_mw_idx < 0) + ndev->b2b_idx = b2b_mw_idx + ndev->mw_count; + else + ndev->b2b_idx = b2b_mw_idx; - /* - * This is a way for transparent BAR to figure out if we - * are doing split BAR or not. There is no way for the hw - * on the transparent side to know and set the PPD. - */ - bars_mask = pci_select_bars(ndev->pdev, IORESOURCE_MEM); - bars = hweight32(bars_mask); - if (bars == (HSX_SPLITBAR_MAX_MW + 1)) - ndev->split_bar = 1; + dev_dbg(ndev_dev(ndev), + "setting up b2b mw idx %d means %d\n", + b2b_mw_idx, ndev->b2b_idx); + + } else if (ndev->hwerr_flags & NTB_HWERR_B2BDOORBELL_BIT14) { + dev_warn(ndev_dev(ndev), "Reduce doorbell count by 1\n"); + ndev->db_count -= 1; + } + + if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { + rc = snb_setup_b2b_mw(ndev, + &snb_b2b_dsd_addr, + &snb_b2b_usd_addr); + } else { + rc = snb_setup_b2b_mw(ndev, + &snb_b2b_usd_addr, + &snb_b2b_dsd_addr); + } + if (rc) + return rc; + + /* Enable Bus Master and Memory Space on the secondary side */ + iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->self_mmio + SNB_SPCICMD_OFFSET); break; + default: - dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", ppd); - return -ENODEV; + return -EINVAL; } - ntb_max_mw_detect(ndev); + ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; + + ndev->reg->db_iowrite(ndev->db_valid_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); return 0; } -static int ntb_atom_detect(struct ntb_device *ndev) +static int snb_init_dev(struct intel_ntb_dev *ndev) { - int rc; - u32 ppd; + struct pci_dev *pdev; + u8 ppd; + int rc, mem; + + /* There is a Xeon hardware errata related to writes to SDOORBELL or + * B2BDOORBELL in conjunction with inbound access to NTB MMIO Space, + * which may hang the system. To workaround this use the second memory + * window to access the interrupt and scratch pad registers on the + * remote system. + */ + ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP; - ndev->hw_type = BWD_HW; - ndev->limits.max_mw = BWD_MAX_MW; + /* There is a hardware errata related to accessing any register in + * SB01BASE in the presence of bidirectional traffic crossing the NTB. + */ + ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP; + + /* HW Errata on bit 14 of b2bdoorbell register. Writes will not be + * mirrored to the remote system. Shrink the number of bits by one, + * since bit 14 is the last bit. + */ + ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14; - rc = pci_read_config_dword(ndev->pdev, NTB_PPD_OFFSET, &ppd); + ndev->reg = &snb_reg; + + pdev = ndev_pdev(ndev); + + rc = pci_read_config_byte(pdev, SNB_PPD_OFFSET, &ppd); if (rc) - return rc; + return -EIO; - switch ((ppd & BWD_PPD_CONN_TYPE) >> 8) { - case NTB_CONN_B2B: - dev_info(&ndev->pdev->dev, "Conn Type = B2B\n"); - ndev->conn_type = NTB_CONN_B2B; - break; - case NTB_CONN_RP: - default: - dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n"); + ndev->ntb.topo = snb_ppd_topo(ndev, ppd); + dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd, + ntb_topo_string(ndev->ntb.topo)); + if (ndev->ntb.topo == NTB_TOPO_NONE) return -EINVAL; + + if (ndev->ntb.topo != NTB_TOPO_SEC) { + ndev->bar4_split = snb_ppd_bar4_split(ndev, ppd); + dev_dbg(ndev_dev(ndev), "ppd %#x bar4_split %d\n", + ppd, ndev->bar4_split); + } else { + /* This is a way for transparent BAR to figure out if we are + * doing split BAR or not. There is no way for the hw on the + * transparent side to know and set the PPD. + */ + mem = pci_select_bars(pdev, IORESOURCE_MEM); + ndev->bar4_split = hweight32(mem) == + HSX_SPLIT_BAR_MW_COUNT + 1; + dev_dbg(ndev_dev(ndev), "mem %#x bar4_split %d\n", + mem, ndev->bar4_split); } - if (ppd & BWD_PPD_DEV_TYPE) - ndev->dev_type = NTB_DEV_DSD; - else - ndev->dev_type = NTB_DEV_USD; + rc = snb_init_ntb(ndev); + if (rc) + return rc; - return 0; + return snb_init_isr(ndev); +} + +static void snb_deinit_dev(struct intel_ntb_dev *ndev) +{ + snb_deinit_isr(ndev); } -static int ntb_device_detect(struct ntb_device *ndev) +static int intel_ntb_init_pci(struct intel_ntb_dev *ndev, struct pci_dev *pdev) { int rc; - if (is_ntb_xeon(ndev)) - rc = ntb_xeon_detect(ndev); - else if (is_ntb_atom(ndev)) - rc = ntb_atom_detect(ndev); - else - rc = -ENODEV; + pci_set_drvdata(pdev, ndev); + + rc = pci_enable_device(pdev); + if (rc) + goto err_pci_enable; + + rc = pci_request_regions(pdev, NTB_NAME); + if (rc) + goto err_pci_regions; + + pci_set_master(pdev); + + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err_dma_mask; + dev_warn(ndev_dev(ndev), "Cannot DMA highmem\n"); + } - dev_info(&ndev->pdev->dev, "Device Type = %s\n", - ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP"); + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (rc) + goto err_dma_mask; + dev_warn(ndev_dev(ndev), "Cannot DMA consistent highmem\n"); + } + + ndev->self_mmio = pci_iomap(pdev, 0, 0); + if (!ndev->self_mmio) { + rc = -EIO; + goto err_mmio; + } + ndev->peer_mmio = ndev->self_mmio; return 0; + +err_mmio: +err_dma_mask: + pci_clear_master(pdev); + pci_release_regions(pdev); +err_pci_regions: + pci_disable_device(pdev); +err_pci_enable: + pci_set_drvdata(pdev, NULL); + return rc; } -static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static void intel_ntb_deinit_pci(struct intel_ntb_dev *ndev) { - struct ntb_device *ndev; - int rc, i; + struct pci_dev *pdev = ndev_pdev(ndev); - ndev = kzalloc(sizeof(struct ntb_device), GFP_KERNEL); - if (!ndev) - return -ENOMEM; + if (ndev->peer_mmio && ndev->peer_mmio != ndev->self_mmio) + pci_iounmap(pdev, ndev->peer_mmio); + pci_iounmap(pdev, ndev->self_mmio); - ndev->pdev = pdev; + pci_clear_master(pdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} - ntb_set_errata_flags(ndev); +static inline void ndev_init_struct(struct intel_ntb_dev *ndev, + struct pci_dev *pdev) +{ + ndev->ntb.pdev = pdev; + ndev->ntb.topo = NTB_TOPO_NONE; + ndev->ntb.ops = &intel_ntb_ops; - ndev->link_status = NTB_LINK_DOWN; - pci_set_drvdata(pdev, ndev); - ntb_setup_debugfs(ndev); + ndev->b2b_off = 0; + ndev->b2b_idx = INT_MAX; - rc = pci_enable_device(pdev); - if (rc) - goto err; + ndev->bar4_split = 0; - pci_set_master(ndev->pdev); + ndev->mw_count = 0; + ndev->spad_count = 0; + ndev->db_count = 0; + ndev->db_vec_count = 0; + ndev->db_vec_shift = 0; - rc = ntb_device_detect(ndev); - if (rc) - goto err; + ndev->ntb_ctl = 0; + ndev->lnk_sta = 0; - ndev->mw = kcalloc(ndev->limits.max_mw, sizeof(struct ntb_mw), - GFP_KERNEL); - if (!ndev->mw) { - rc = -ENOMEM; - goto err1; - } + ndev->db_valid_mask = 0; + ndev->db_link_mask = 0; + ndev->db_mask = 0; - if (ndev->split_bar) - rc = pci_request_selected_regions(pdev, NTB_SPLITBAR_MASK, - KBUILD_MODNAME); - else - rc = pci_request_selected_regions(pdev, NTB_BAR_MASK, - KBUILD_MODNAME); + spin_lock_init(&ndev->db_mask_lock); +} - if (rc) - goto err2; +static int intel_ntb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_ntb_dev *ndev; + int rc; - ndev->reg_base = pci_ioremap_bar(pdev, NTB_BAR_MMIO); - if (!ndev->reg_base) { - dev_warn(&pdev->dev, "Cannot remap BAR 0\n"); - rc = -EIO; - goto err3; - } + if (pdev_is_bwd(pdev)) { + ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); + if (!ndev) { + rc = -ENOMEM; + goto err_ndev; + } - for (i = 0; i < ndev->limits.max_mw; i++) { - ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i)); + ndev_init_struct(ndev, pdev); - /* - * with the errata we need to steal last of the memory - * windows for workarounds and they point to MMIO registers. - */ - if ((ndev->wa_flags & WA_SNB_ERR) && - (i == (ndev->limits.max_mw - 1))) { - ndev->mw[i].vbase = - ioremap_nocache(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } else { - ndev->mw[i].vbase = - ioremap_wc(pci_resource_start(pdev, - MW_TO_BAR(i)), - ndev->mw[i].bar_sz); - } + rc = intel_ntb_init_pci(ndev, pdev); + if (rc) + goto err_init_pci; + + rc = bwd_init_dev(ndev); + if (rc) + goto err_init_dev; - dev_info(&pdev->dev, "MW %d size %llu\n", i, - (unsigned long long) ndev->mw[i].bar_sz); - if (!ndev->mw[i].vbase) { - dev_warn(&pdev->dev, "Cannot remap BAR %d\n", - MW_TO_BAR(i)); - rc = -EIO; - goto err4; + } else if (pdev_is_snb(pdev)) { + ndev = kzalloc(sizeof(*ndev), GFP_KERNEL); + if (!ndev) { + rc = -ENOMEM; + goto err_ndev; } - } - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) - goto err4; + ndev_init_struct(ndev, pdev); - dev_warn(&pdev->dev, "Cannot DMA highmem\n"); - } + rc = intel_ntb_init_pci(ndev, pdev); + if (rc) + goto err_init_pci; - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + rc = snb_init_dev(ndev); if (rc) - goto err4; + goto err_init_dev; - dev_warn(&pdev->dev, "Cannot DMA consistent highmem\n"); + } else { + rc = -EINVAL; + goto err_ndev; } - rc = ntb_device_setup(ndev); - if (rc) - goto err4; - - rc = ntb_create_callbacks(ndev); - if (rc) - goto err5; + ndev_reset_unsafe_flags(ndev); - rc = ntb_setup_interrupts(ndev); - if (rc) - goto err6; + ndev->reg->poll_link(ndev); - /* The scratchpad registers keep the values between rmmod/insmod, - * blast them now - */ - for (i = 0; i < ndev->limits.max_spads; i++) { - ntb_write_local_spad(ndev, i, 0); - ntb_write_remote_spad(ndev, i, 0); - } + ndev_init_debugfs(ndev); - rc = ntb_transport_init(pdev); + rc = ntb_register_device(&ndev->ntb); if (rc) - goto err7; - - ntb_hw_link_up(ndev); + goto err_register; return 0; -err7: - ntb_free_interrupts(ndev); -err6: - ntb_free_callbacks(ndev); -err5: - ntb_device_free(ndev); -err4: - for (i--; i >= 0; i--) - iounmap(ndev->mw[i].vbase); - iounmap(ndev->reg_base); -err3: - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); -err2: - kfree(ndev->mw); -err1: - pci_disable_device(pdev); -err: - ntb_free_debugfs(ndev); +err_register: + ndev_deinit_debugfs(ndev); + if (pdev_is_bwd(pdev)) + bwd_deinit_dev(ndev); + else if (pdev_is_snb(pdev)) + snb_deinit_dev(ndev); +err_init_dev: + intel_ntb_deinit_pci(ndev); +err_init_pci: kfree(ndev); - - dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME); +err_ndev: return rc; } -static void ntb_pci_remove(struct pci_dev *pdev) +static void intel_ntb_pci_remove(struct pci_dev *pdev) { - struct ntb_device *ndev = pci_get_drvdata(pdev); - int i; + struct intel_ntb_dev *ndev = pci_get_drvdata(pdev); + + ntb_unregister_device(&ndev->ntb); + ndev_deinit_debugfs(ndev); + if (pdev_is_bwd(pdev)) + bwd_deinit_dev(ndev); + else if (pdev_is_snb(pdev)) + snb_deinit_dev(ndev); + intel_ntb_deinit_pci(ndev); + kfree(ndev); +} - ntb_hw_link_down(ndev); +static const struct intel_ntb_reg bwd_reg = { + .poll_link = bwd_poll_link, + .link_is_up = bwd_link_is_up, + .db_ioread = bwd_db_ioread, + .db_iowrite = bwd_db_iowrite, + .db_size = sizeof(u64), + .ntb_ctl = BWD_NTBCNTL_OFFSET, + .mw_bar = {2, 4}, +}; - ntb_transport_free(ndev->ntb_transport); +static const struct intel_ntb_alt_reg bwd_pri_reg = { + .db_bell = BWD_PDOORBELL_OFFSET, + .db_mask = BWD_PDBMSK_OFFSET, + .spad = BWD_SPAD_OFFSET, +}; - ntb_free_interrupts(ndev); - ntb_free_callbacks(ndev); - ntb_device_free(ndev); +static const struct intel_ntb_alt_reg bwd_b2b_reg = { + .db_bell = BWD_B2B_DOORBELL_OFFSET, + .spad = BWD_B2B_SPAD_OFFSET, +}; - /* need to reset max_mw limits so we can unmap properly */ - if (ndev->hw_type == SNB_HW) - ntb_max_mw_detect(ndev); +static const struct intel_ntb_xlat_reg bwd_sec_xlat = { + /* FIXME : .bar0_base = BWD_SBAR0BASE_OFFSET, */ + /* FIXME : .bar2_limit = BWD_SBAR2LMT_OFFSET, */ + .bar2_xlat = BWD_SBAR2XLAT_OFFSET, +}; - for (i = 0; i < ndev->limits.max_mw; i++) - iounmap(ndev->mw[i].vbase); +static const struct intel_ntb_reg snb_reg = { + .poll_link = snb_poll_link, + .link_is_up = snb_link_is_up, + .db_ioread = snb_db_ioread, + .db_iowrite = snb_db_iowrite, + .db_size = sizeof(u32), + .ntb_ctl = SNB_NTBCNTL_OFFSET, + .mw_bar = {2, 4, 5}, +}; - kfree(ndev->mw); - iounmap(ndev->reg_base); - if (ndev->split_bar) - pci_release_selected_regions(pdev, NTB_SPLITBAR_MASK); - else - pci_release_selected_regions(pdev, NTB_BAR_MASK); - pci_disable_device(pdev); - ntb_free_debugfs(ndev); - kfree(ndev); -} +static const struct intel_ntb_alt_reg snb_pri_reg = { + .db_bell = SNB_PDOORBELL_OFFSET, + .db_mask = SNB_PDBMSK_OFFSET, + .spad = SNB_SPAD_OFFSET, +}; + +static const struct intel_ntb_alt_reg snb_sec_reg = { + .db_bell = SNB_SDOORBELL_OFFSET, + .db_mask = SNB_SDBMSK_OFFSET, + /* second half of the scratchpads */ + .spad = SNB_SPAD_OFFSET + (SNB_SPAD_COUNT << 1), +}; -static struct pci_driver ntb_pci_driver = { +static const struct intel_ntb_alt_reg snb_b2b_reg = { + .db_bell = SNB_B2B_DOORBELL_OFFSET, + .spad = SNB_B2B_SPAD_OFFSET, +}; + +static const struct intel_ntb_xlat_reg snb_pri_xlat = { + /* Note: no primary .bar0_base visible to the secondary side. + * + * The secondary side cannot get the base address stored in primary + * bars. The base address is necessary to set the limit register to + * any value other than zero, or unlimited. + * + * WITHOUT THE BASE ADDRESS, THE SECONDARY SIDE CANNOT DISABLE the + * window by setting the limit equal to base, nor can it limit the size + * of the memory window by setting the limit to base + size. + */ + .bar2_limit = SNB_PBAR23LMT_OFFSET, + .bar2_xlat = SNB_PBAR23XLAT_OFFSET, +}; + +static const struct intel_ntb_xlat_reg snb_sec_xlat = { + .bar0_base = SNB_SBAR0BASE_OFFSET, + .bar2_limit = SNB_SBAR23LMT_OFFSET, + .bar2_xlat = SNB_SBAR23XLAT_OFFSET, +}; + +static const struct intel_b2b_addr snb_b2b_usd_addr = { + .bar2_addr64 = SNB_B2B_BAR2_USD_ADDR64, + .bar4_addr64 = SNB_B2B_BAR4_USD_ADDR64, + .bar4_addr32 = SNB_B2B_BAR4_USD_ADDR32, + .bar5_addr32 = SNB_B2B_BAR5_USD_ADDR32, +}; + +static const struct intel_b2b_addr snb_b2b_dsd_addr = { + .bar2_addr64 = SNB_B2B_BAR2_DSD_ADDR64, + .bar4_addr64 = SNB_B2B_BAR4_DSD_ADDR64, + .bar4_addr32 = SNB_B2B_BAR4_DSD_ADDR32, + .bar5_addr32 = SNB_B2B_BAR5_DSD_ADDR32, +}; + +/* operations for primary side of local ntb */ +static const struct ntb_dev_ops intel_ntb_ops = { + .mw_count = intel_ntb_mw_count, + .mw_get_range = intel_ntb_mw_get_range, + .mw_set_trans = intel_ntb_mw_set_trans, + .link_is_up = intel_ntb_link_is_up, + .link_enable = intel_ntb_link_enable, + .link_disable = intel_ntb_link_disable, + .db_is_unsafe = intel_ntb_db_is_unsafe, + .db_valid_mask = intel_ntb_db_valid_mask, + .db_vector_count = intel_ntb_db_vector_count, + .db_vector_mask = intel_ntb_db_vector_mask, + .db_read = intel_ntb_db_read, + .db_clear = intel_ntb_db_clear, + .db_set_mask = intel_ntb_db_set_mask, + .db_clear_mask = intel_ntb_db_clear_mask, + .peer_db_addr = intel_ntb_peer_db_addr, + .peer_db_set = intel_ntb_peer_db_set, + .spad_is_unsafe = intel_ntb_spad_is_unsafe, + .spad_count = intel_ntb_spad_count, + .spad_read = intel_ntb_spad_read, + .spad_write = intel_ntb_spad_write, + .peer_spad_addr = intel_ntb_peer_spad_addr, + .peer_spad_read = intel_ntb_peer_spad_read, + .peer_spad_write = intel_ntb_peer_spad_write, +}; + +static const struct file_operations intel_ntb_debugfs_info = { + .owner = THIS_MODULE, + .open = simple_open, + .read = ndev_debugfs_read, +}; + +static const struct pci_device_id intel_ntb_pci_tbl[] = { + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl); + +static struct pci_driver intel_ntb_pci_driver = { .name = KBUILD_MODNAME, - .id_table = ntb_pci_tbl, - .probe = ntb_pci_probe, - .remove = ntb_pci_remove, + .id_table = intel_ntb_pci_tbl, + .probe = intel_ntb_pci_probe, + .remove = intel_ntb_pci_remove, }; -module_pci_driver(ntb_pci_driver); +static int __init intel_ntb_pci_driver_init(void) +{ + if (debugfs_initialized()) + debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + return pci_register_driver(&intel_ntb_pci_driver); +} +module_init(intel_ntb_pci_driver_init); + +static void __exit intel_ntb_pci_driver_exit(void) +{ + pci_unregister_driver(&intel_ntb_pci_driver); + + debugfs_remove_recursive(debugfs_dir); +} +module_exit(intel_ntb_pci_driver_exit); + diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 935610454f70..fec689dc95cf 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,341 +47,296 @@ * Contact Information: * Jon Mason */ -#include - -#define NTB_LINK_STATUS_ACTIVE 0x2000 -#define NTB_LINK_SPEED_MASK 0x000f -#define NTB_LINK_WIDTH_MASK 0x03f0 - -#define SNB_MSIX_CNT 4 -#define SNB_MAX_B2B_SPADS 16 -#define SNB_MAX_COMPAT_SPADS 16 -/* Reserve the uppermost bit for link interrupt */ -#define SNB_MAX_DB_BITS 15 -#define SNB_LINK_DB 15 -#define SNB_DB_BITS_PER_VEC 5 -#define HSX_SPLITBAR_MAX_MW 3 -#define SNB_MAX_MW 2 -#define SNB_ERRATA_MAX_MW 1 - -#define SNB_DB_HW_LINK 0x8000 - -#define SNB_UNCERRSTS_OFFSET 0x014C -#define SNB_CORERRSTS_OFFSET 0x0158 -#define SNB_LINK_STATUS_OFFSET 0x01A2 -#define SNB_PCICMD_OFFSET 0x0504 -#define SNB_DEVCTRL_OFFSET 0x0598 -#define SNB_DEVSTS_OFFSET 0x059A -#define SNB_SLINK_STATUS_OFFSET 0x05A2 - -#define SNB_PBAR2LMT_OFFSET 0x0000 -#define SNB_PBAR4LMT_OFFSET 0x0008 -#define SNB_PBAR5LMT_OFFSET 0x000C -#define SNB_PBAR2XLAT_OFFSET 0x0010 -#define SNB_PBAR4XLAT_OFFSET 0x0018 -#define SNB_PBAR5XLAT_OFFSET 0x001C -#define SNB_SBAR2LMT_OFFSET 0x0020 -#define SNB_SBAR4LMT_OFFSET 0x0028 -#define SNB_SBAR5LMT_OFFSET 0x002C -#define SNB_SBAR2XLAT_OFFSET 0x0030 -#define SNB_SBAR4XLAT_OFFSET 0x0038 -#define SNB_SBAR5XLAT_OFFSET 0x003C -#define SNB_SBAR0BASE_OFFSET 0x0040 -#define SNB_SBAR2BASE_OFFSET 0x0048 -#define SNB_SBAR4BASE_OFFSET 0x0050 -#define SNB_SBAR5BASE_OFFSET 0x0054 -#define SNB_NTBCNTL_OFFSET 0x0058 -#define SNB_SBDF_OFFSET 0x005C -#define SNB_PDOORBELL_OFFSET 0x0060 -#define SNB_PDBMSK_OFFSET 0x0062 -#define SNB_SDOORBELL_OFFSET 0x0064 -#define SNB_SDBMSK_OFFSET 0x0066 -#define SNB_USMEMMISS_OFFSET 0x0070 -#define SNB_SPAD_OFFSET 0x0080 -#define SNB_SPADSEMA4_OFFSET 0x00c0 -#define SNB_WCCNTRL_OFFSET 0x00e0 -#define SNB_B2B_SPAD_OFFSET 0x0100 -#define SNB_B2B_DOORBELL_OFFSET 0x0140 -#define SNB_B2B_XLAT_OFFSETL 0x0144 -#define SNB_B2B_XLAT_OFFSETU 0x0148 -/* - * The addresses are setup so the 32bit BARs can function. Thus - * the addresses are all in 32bit space - */ -#define SNB_MBAR01_USD_ADDR 0x000000002100000CULL -#define SNB_MBAR23_USD_ADDR 0x000000004100000CULL -#define SNB_MBAR4_USD_ADDR 0x000000008100000CULL -#define SNB_MBAR5_USD_ADDR 0x00000000A100000CULL -#define SNB_MBAR01_DSD_ADDR 0x000000002000000CULL -#define SNB_MBAR23_DSD_ADDR 0x000000004000000CULL -#define SNB_MBAR4_DSD_ADDR 0x000000008000000CULL -#define SNB_MBAR5_DSD_ADDR 0x00000000A000000CULL - -#define BWD_MSIX_CNT 34 -#define BWD_MAX_SPADS 16 -#define BWD_MAX_DB_BITS 34 -#define BWD_DB_BITS_PER_VEC 1 -#define BWD_MAX_MW 2 - -#define BWD_PCICMD_OFFSET 0xb004 -#define BWD_MBAR23_OFFSET 0xb018 -#define BWD_MBAR45_OFFSET 0xb020 -#define BWD_DEVCTRL_OFFSET 0xb048 -#define BWD_LINK_STATUS_OFFSET 0xb052 -#define BWD_ERRCORSTS_OFFSET 0xb110 - -#define BWD_SBAR2XLAT_OFFSET 0x0008 -#define BWD_SBAR4XLAT_OFFSET 0x0010 -#define BWD_PDOORBELL_OFFSET 0x0020 -#define BWD_PDBMSK_OFFSET 0x0028 -#define BWD_NTBCNTL_OFFSET 0x0060 -#define BWD_EBDF_OFFSET 0x0064 -#define BWD_SPAD_OFFSET 0x0080 -#define BWD_SPADSEMA_OFFSET 0x00c0 -#define BWD_STKYSPAD_OFFSET 0x00c4 -#define BWD_PBAR2XLAT_OFFSET 0x8008 -#define BWD_PBAR4XLAT_OFFSET 0x8010 -#define BWD_B2B_DOORBELL_OFFSET 0x8020 -#define BWD_B2B_SPAD_OFFSET 0x8080 -#define BWD_B2B_SPADSEMA_OFFSET 0x80c0 -#define BWD_B2B_STKYSPAD_OFFSET 0x80c4 - -#define BWD_MODPHY_PCSREG4 0x1c004 -#define BWD_MODPHY_PCSREG6 0x1c006 - -#define BWD_IP_BASE 0xC000 -#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) -#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) +#ifndef NTB_HW_INTEL_H +#define NTB_HW_INTEL_H + +#include +#include + +#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 +#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 +#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 +#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E + +/* SNB hardware (and JSF, IVT, HSX) */ + +#define SNB_PBAR23LMT_OFFSET 0x0000 +#define SNB_PBAR45LMT_OFFSET 0x0008 +#define SNB_PBAR4LMT_OFFSET 0x0008 +#define SNB_PBAR5LMT_OFFSET 0x000c +#define SNB_PBAR23XLAT_OFFSET 0x0010 +#define SNB_PBAR45XLAT_OFFSET 0x0018 +#define SNB_PBAR4XLAT_OFFSET 0x0018 +#define SNB_PBAR5XLAT_OFFSET 0x001c +#define SNB_SBAR23LMT_OFFSET 0x0020 +#define SNB_SBAR45LMT_OFFSET 0x0028 +#define SNB_SBAR4LMT_OFFSET 0x0028 +#define SNB_SBAR5LMT_OFFSET 0x002c +#define SNB_SBAR23XLAT_OFFSET 0x0030 +#define SNB_SBAR45XLAT_OFFSET 0x0038 +#define SNB_SBAR4XLAT_OFFSET 0x0038 +#define SNB_SBAR5XLAT_OFFSET 0x003c +#define SNB_SBAR0BASE_OFFSET 0x0040 +#define SNB_SBAR23BASE_OFFSET 0x0048 +#define SNB_SBAR45BASE_OFFSET 0x0050 +#define SNB_SBAR4BASE_OFFSET 0x0050 +#define SNB_SBAR5BASE_OFFSET 0x0054 +#define SNB_SBDF_OFFSET 0x005c +#define SNB_NTBCNTL_OFFSET 0x0058 +#define SNB_PDOORBELL_OFFSET 0x0060 +#define SNB_PDBMSK_OFFSET 0x0062 +#define SNB_SDOORBELL_OFFSET 0x0064 +#define SNB_SDBMSK_OFFSET 0x0066 +#define SNB_USMEMMISS_OFFSET 0x0070 +#define SNB_SPAD_OFFSET 0x0080 +#define SNB_PBAR23SZ_OFFSET 0x00d0 +#define SNB_PBAR45SZ_OFFSET 0x00d1 +#define SNB_PBAR4SZ_OFFSET 0x00d1 +#define SNB_SBAR23SZ_OFFSET 0x00d2 +#define SNB_SBAR45SZ_OFFSET 0x00d3 +#define SNB_SBAR4SZ_OFFSET 0x00d3 +#define SNB_PPD_OFFSET 0x00d4 +#define SNB_PBAR5SZ_OFFSET 0x00d5 +#define SNB_SBAR5SZ_OFFSET 0x00d6 +#define SNB_WCCNTRL_OFFSET 0x00e0 +#define SNB_UNCERRSTS_OFFSET 0x014c +#define SNB_CORERRSTS_OFFSET 0x0158 +#define SNB_LINK_STATUS_OFFSET 0x01a2 +#define SNB_SPCICMD_OFFSET 0x0504 +#define SNB_DEVCTRL_OFFSET 0x0598 +#define SNB_DEVSTS_OFFSET 0x059a +#define SNB_SLINK_STATUS_OFFSET 0x05a2 +#define SNB_B2B_SPAD_OFFSET 0x0100 +#define SNB_B2B_DOORBELL_OFFSET 0x0140 +#define SNB_B2B_XLAT_OFFSETL 0x0144 +#define SNB_B2B_XLAT_OFFSETU 0x0148 +#define SNB_PPD_CONN_MASK 0x03 +#define SNB_PPD_CONN_TRANSPARENT 0x00 +#define SNB_PPD_CONN_B2B 0x01 +#define SNB_PPD_CONN_RP 0x02 +#define SNB_PPD_DEV_MASK 0x10 +#define SNB_PPD_DEV_USD 0x00 +#define SNB_PPD_DEV_DSD 0x10 +#define SNB_PPD_SPLIT_BAR_MASK 0x40 + +#define SNB_PPD_TOPO_MASK (SNB_PPD_CONN_MASK | SNB_PPD_DEV_MASK) +#define SNB_PPD_TOPO_PRI_USD (SNB_PPD_CONN_RP | SNB_PPD_DEV_USD) +#define SNB_PPD_TOPO_PRI_DSD (SNB_PPD_CONN_RP | SNB_PPD_DEV_DSD) +#define SNB_PPD_TOPO_SEC_USD (SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_USD) +#define SNB_PPD_TOPO_SEC_DSD (SNB_PPD_CONN_TRANSPARENT | SNB_PPD_DEV_DSD) +#define SNB_PPD_TOPO_B2B_USD (SNB_PPD_CONN_B2B | SNB_PPD_DEV_USD) +#define SNB_PPD_TOPO_B2B_DSD (SNB_PPD_CONN_B2B | SNB_PPD_DEV_DSD) + +#define SNB_MW_COUNT 2 +#define HSX_SPLIT_BAR_MW_COUNT 3 +#define SNB_DB_COUNT 15 +#define SNB_DB_LINK 15 +#define SNB_DB_LINK_BIT BIT_ULL(SNB_DB_LINK) +#define SNB_DB_MSIX_VECTOR_COUNT 4 +#define SNB_DB_MSIX_VECTOR_SHIFT 5 +#define SNB_DB_TOTAL_SHIFT 16 +#define SNB_SPAD_COUNT 16 + +/* BWD hardware */ + +#define BWD_SBAR2XLAT_OFFSET 0x0008 +#define BWD_PDOORBELL_OFFSET 0x0020 +#define BWD_PDBMSK_OFFSET 0x0028 +#define BWD_NTBCNTL_OFFSET 0x0060 +#define BWD_SPAD_OFFSET 0x0080 +#define BWD_PPD_OFFSET 0x00d4 +#define BWD_PBAR2XLAT_OFFSET 0x8008 +#define BWD_B2B_DOORBELL_OFFSET 0x8020 +#define BWD_B2B_SPAD_OFFSET 0x8080 +#define BWD_SPCICMD_OFFSET 0xb004 +#define BWD_LINK_STATUS_OFFSET 0xb052 +#define BWD_ERRCORSTS_OFFSET 0xb110 +#define BWD_IP_BASE 0xc000 +#define BWD_DESKEWSTS_OFFSET (BWD_IP_BASE + 0x3024) +#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180) #define BWD_LTSSMSTATEJMP_OFFSET (BWD_IP_BASE + 0x3040) #define BWD_IBSTERRRCRVSTS0_OFFSET (BWD_IP_BASE + 0x3324) +#define BWD_MODPHY_PCSREG4 0x1c004 +#define BWD_MODPHY_PCSREG6 0x1c006 + +#define BWD_PPD_INIT_LINK 0x0008 +#define BWD_PPD_CONN_MASK 0x0300 +#define BWD_PPD_CONN_TRANSPARENT 0x0000 +#define BWD_PPD_CONN_B2B 0x0100 +#define BWD_PPD_CONN_RP 0x0200 +#define BWD_PPD_DEV_MASK 0x1000 +#define BWD_PPD_DEV_USD 0x0000 +#define BWD_PPD_DEV_DSD 0x1000 +#define BWD_PPD_TOPO_MASK (BWD_PPD_CONN_MASK | BWD_PPD_DEV_MASK) +#define BWD_PPD_TOPO_PRI_USD (BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_USD) +#define BWD_PPD_TOPO_PRI_DSD (BWD_PPD_CONN_TRANSPARENT | BWD_PPD_DEV_DSD) +#define BWD_PPD_TOPO_SEC_USD (BWD_PPD_CONN_RP | BWD_PPD_DEV_USD) +#define BWD_PPD_TOPO_SEC_DSD (BWD_PPD_CONN_RP | BWD_PPD_DEV_DSD) +#define BWD_PPD_TOPO_B2B_USD (BWD_PPD_CONN_B2B | BWD_PPD_DEV_USD) +#define BWD_PPD_TOPO_B2B_DSD (BWD_PPD_CONN_B2B | BWD_PPD_DEV_DSD) + +#define BWD_MW_COUNT 2 +#define BWD_DB_COUNT 34 +#define BWD_DB_VALID_MASK (BIT_ULL(BWD_DB_COUNT) - 1) +#define BWD_DB_MSIX_VECTOR_COUNT 34 +#define BWD_DB_MSIX_VECTOR_SHIFT 1 +#define BWD_DB_TOTAL_SHIFT 34 +#define BWD_SPAD_COUNT 16 + +#define BWD_NTB_CTL_DOWN_BIT BIT(16) +#define BWD_NTB_CTL_ACTIVE(x) !(x & BWD_NTB_CTL_DOWN_BIT) + +#define BWD_DESKEWSTS_DBERR BIT(15) +#define BWD_LTSSMERRSTS0_UNEXPECTEDEI BIT(20) +#define BWD_LTSSMSTATEJMP_FORCEDETECT BIT(2) +#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF + +#define BWD_LINK_HB_TIMEOUT msecs_to_jiffies(1000) +#define BWD_LINK_RECOVERY_TIME msecs_to_jiffies(500) + +/* Ntb control and link status */ + +#define NTB_CTL_CFG_LOCK BIT(0) +#define NTB_CTL_DISABLE BIT(1) +#define NTB_CTL_S2P_BAR2_SNOOP BIT(2) +#define NTB_CTL_P2S_BAR2_SNOOP BIT(4) +#define NTB_CTL_S2P_BAR4_SNOOP BIT(6) +#define NTB_CTL_P2S_BAR4_SNOOP BIT(8) +#define NTB_CTL_S2P_BAR5_SNOOP BIT(12) +#define NTB_CTL_P2S_BAR5_SNOOP BIT(14) + +#define NTB_LNK_STA_ACTIVE_BIT 0x2000 +#define NTB_LNK_STA_SPEED_MASK 0x000f +#define NTB_LNK_STA_WIDTH_MASK 0x03f0 +#define NTB_LNK_STA_ACTIVE(x) (!!((x) & NTB_LNK_STA_ACTIVE_BIT)) +#define NTB_LNK_STA_SPEED(x) ((x) & NTB_LNK_STA_SPEED_MASK) +#define NTB_LNK_STA_WIDTH(x) (((x) & NTB_LNK_STA_WIDTH_MASK) >> 4) + +/* Use the following addresses for translation between b2b ntb devices in case + * the hardware default values are not reliable. */ +#define SNB_B2B_BAR0_USD_ADDR 0x1000000000000000ull +#define SNB_B2B_BAR2_USD_ADDR64 0x2000000000000000ull +#define SNB_B2B_BAR4_USD_ADDR64 0x4000000000000000ull +#define SNB_B2B_BAR4_USD_ADDR32 0x20000000u +#define SNB_B2B_BAR5_USD_ADDR32 0x40000000u +#define SNB_B2B_BAR0_DSD_ADDR 0x9000000000000000ull +#define SNB_B2B_BAR2_DSD_ADDR64 0xa000000000000000ull +#define SNB_B2B_BAR4_DSD_ADDR64 0xc000000000000000ull +#define SNB_B2B_BAR4_DSD_ADDR32 0xa0000000u +#define SNB_B2B_BAR5_DSD_ADDR32 0xc0000000u + +/* The peer ntb secondary config space is 32KB fixed size */ +#define SNB_B2B_MIN_SIZE 0x8000 + +/* flags to indicate hardware errata */ +#define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0) +#define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1) +#define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2) + +/* flags to indicate unsafe api */ +#define NTB_UNSAFE_DB BIT_ULL(0) +#define NTB_UNSAFE_SPAD BIT_ULL(1) + +struct intel_ntb_dev; + +struct intel_ntb_reg { + int (*poll_link)(struct intel_ntb_dev *ndev); + int (*link_is_up)(struct intel_ntb_dev *ndev); + u64 (*db_ioread)(void __iomem *mmio); + void (*db_iowrite)(u64 db_bits, void __iomem *mmio); + unsigned long ntb_ctl; + resource_size_t db_size; + int mw_bar[]; +}; -#define BWD_DESKEWSTS_DBERR (1 << 15) -#define BWD_LTSSMERRSTS0_UNEXPECTEDEI (1 << 20) -#define BWD_LTSSMSTATEJMP_FORCEDETECT (1 << 2) -#define BWD_IBIST_ERR_OFLOW 0x7FFF7FFF - -#define NTB_CNTL_CFG_LOCK (1 << 0) -#define NTB_CNTL_LINK_DISABLE (1 << 1) -#define NTB_CNTL_S2P_BAR23_SNOOP (1 << 2) -#define NTB_CNTL_P2S_BAR23_SNOOP (1 << 4) -#define NTB_CNTL_S2P_BAR4_SNOOP (1 << 6) -#define NTB_CNTL_P2S_BAR4_SNOOP (1 << 8) -#define NTB_CNTL_S2P_BAR5_SNOOP (1 << 12) -#define NTB_CNTL_P2S_BAR5_SNOOP (1 << 14) -#define BWD_CNTL_LINK_DOWN (1 << 16) - -#define NTB_PPD_OFFSET 0x00D4 -#define SNB_PPD_CONN_TYPE 0x0003 -#define SNB_PPD_DEV_TYPE 0x0010 -#define SNB_PPD_SPLIT_BAR (1 << 6) -#define BWD_PPD_INIT_LINK 0x0008 -#define BWD_PPD_CONN_TYPE 0x0300 -#define BWD_PPD_DEV_TYPE 0x1000 -#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF 0x3725 -#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF 0x3726 -#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF 0x3727 -#define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB 0x3C0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB 0x3C0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB 0x3C0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT 0x0E0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT 0x0E0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT 0x0E0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX 0x2F0D -#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E -#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F -#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E - -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(val & 0xffffffff, addr); - writel(val >> 32, addr + 4); -} -#endif +struct intel_ntb_alt_reg { + unsigned long db_bell; + unsigned long db_mask; + unsigned long spad; +}; -#define NTB_BAR_MMIO 0 -#define NTB_BAR_23 2 -#define NTB_BAR_4 4 -#define NTB_BAR_5 5 - -#define NTB_BAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4)) -#define NTB_SPLITBAR_MASK ((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\ - (1 << NTB_BAR_4) | (1 << NTB_BAR_5)) - -#define NTB_HB_TIMEOUT msecs_to_jiffies(1000) - -enum ntb_hw_event { - NTB_EVENT_SW_EVENT0 = 0, - NTB_EVENT_SW_EVENT1, - NTB_EVENT_SW_EVENT2, - NTB_EVENT_HW_ERROR, - NTB_EVENT_HW_LINK_UP, - NTB_EVENT_HW_LINK_DOWN, +struct intel_ntb_xlat_reg { + unsigned long bar0_base; + unsigned long bar2_xlat; + unsigned long bar2_limit; }; -struct ntb_mw { - dma_addr_t phys_addr; - void __iomem *vbase; - resource_size_t bar_sz; +struct intel_b2b_addr { + phys_addr_t bar0_addr; + phys_addr_t bar2_addr64; + phys_addr_t bar4_addr64; + phys_addr_t bar4_addr32; + phys_addr_t bar5_addr32; }; -struct ntb_db_cb { - int (*callback)(void *data, int db_num); - unsigned int db_num; - void *data; - struct ntb_device *ndev; - struct tasklet_struct irq_work; +struct intel_ntb_vec { + struct intel_ntb_dev *ndev; + int num; }; -#define WA_SNB_ERR 0x00000001 - -struct ntb_device { - struct pci_dev *pdev; - struct msix_entry *msix_entries; - void __iomem *reg_base; - struct ntb_mw *mw; - struct { - unsigned char max_mw; - unsigned char max_spads; - unsigned char max_db_bits; - unsigned char msix_cnt; - } limits; - struct { - void __iomem *ldb; - void __iomem *ldb_mask; - void __iomem *rdb; - void __iomem *bar2_xlat; - void __iomem *bar4_xlat; - void __iomem *bar5_xlat; - void __iomem *spad_write; - void __iomem *spad_read; - void __iomem *lnk_cntl; - void __iomem *lnk_stat; - void __iomem *spci_cmd; - } reg_ofs; - struct ntb_transport *ntb_transport; - void (*event_cb)(void *handle, enum ntb_hw_event event); - - struct ntb_db_cb *db_cb; - unsigned char hw_type; - unsigned char conn_type; - unsigned char dev_type; - unsigned char num_msix; - unsigned char bits_per_vector; - unsigned char max_cbs; - unsigned char link_width; - unsigned char link_speed; - unsigned char link_status; - unsigned char split_bar; - - struct delayed_work hb_timer; - unsigned long last_ts; - - struct delayed_work lr_timer; - - struct dentry *debugfs_dir; - struct dentry *debugfs_info; - - unsigned int wa_flags; +struct intel_ntb_dev { + struct ntb_dev ntb; + + /* offset of peer bar0 in b2b bar */ + unsigned long b2b_off; + /* mw idx used to access peer bar0 */ + unsigned int b2b_idx; + + /* BAR45 is split into BAR4 and BAR5 */ + bool bar4_split; + + u32 ntb_ctl; + u32 lnk_sta; + + unsigned char mw_count; + unsigned char spad_count; + unsigned char db_count; + unsigned char db_vec_count; + unsigned char db_vec_shift; + + u64 db_valid_mask; + u64 db_link_mask; + u64 db_mask; + + /* synchronize rmw access of db_mask and hw reg */ + spinlock_t db_mask_lock; + + struct msix_entry *msix; + struct intel_ntb_vec *vec; + + const struct intel_ntb_reg *reg; + const struct intel_ntb_alt_reg *self_reg; + const struct intel_ntb_alt_reg *peer_reg; + const struct intel_ntb_xlat_reg *xlat_reg; + void __iomem *self_mmio; + void __iomem *peer_mmio; + phys_addr_t peer_addr; + + unsigned long last_ts; + struct delayed_work hb_timer; + + unsigned long hwerr_flags; + unsigned long unsafe_flags; + unsigned long unsafe_flags_ignore; + + struct dentry *debugfs_dir; + struct dentry *debugfs_info; }; -/** - * ntb_max_cbs() - return the max callbacks - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of callbacks - * - * RETURNS: the maximum number of callbacks - */ -static inline unsigned char ntb_max_cbs(struct ntb_device *ndev) -{ - return ndev->max_cbs; -} - -/** - * ntb_max_mw() - return the max number of memory windows - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the maximum number of memory windows - * - * RETURNS: the maximum number of memory windows - */ -static inline unsigned char ntb_max_mw(struct ntb_device *ndev) -{ - return ndev->limits.max_mw; -} - -/** - * ntb_hw_link_status() - return the hardware link status - * @ndev: pointer to ntb_device instance - * - * Returns true if the hardware is connected to the remote system - * - * RETURNS: true or false based on the hardware link state - */ -static inline bool ntb_hw_link_status(struct ntb_device *ndev) -{ - return ndev->link_status == NTB_LINK_UP; -} - -/** - * ntb_query_pdev() - return the pci_dev pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device - * - * RETURNS: a pointer to the ntb pci_dev - */ -static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev) -{ - return ndev->pdev; -} - -/** - * ntb_query_debugfs() - return the debugfs pointer - * @ndev: pointer to ntb_device instance - * - * Given the ntb pointer, return the debugfs directory pointer for the NTB - * hardware device - * - * RETURNS: a pointer to the debugfs directory - */ -static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev) -{ - return ndev->debugfs_dir; -} - -struct ntb_device *ntb_register_transport(struct pci_dev *pdev, - void *transport); -void ntb_unregister_transport(struct ntb_device *ndev); -void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr); -int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, int (*db_cb_func)(void *data, - int db_num)); -void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx); -int ntb_register_event_callback(struct ntb_device *ndev, - void (*event_cb_func)(void *handle, - enum ntb_hw_event event)); -void ntb_unregister_event_callback(struct ntb_device *ndev); -int ntb_get_max_spads(struct ntb_device *ndev); -int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val); -int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val); -resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw); -void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw); -u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw); -void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx); -void *ntb_find_transport(struct pci_dev *pdev); - -int ntb_transport_init(struct pci_dev *pdev); -void ntb_transport_free(void *transport); +#define ndev_pdev(ndev) ((ndev)->ntb.pdev) +#define ndev_name(ndev) pci_name(ndev_pdev(ndev)) +#define ndev_dev(ndev) (&ndev_pdev(ndev)->dev) +#define ntb_ndev(ntb) container_of(ntb, struct intel_ntb_dev, ntb) +#define hb_ndev(work) container_of(work, struct intel_ntb_dev, hb_timer.work) + +#endif diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index c5f26cda9f97..9faf1c6029af 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +42,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Intel PCIe NTB Linux driver + * PCIe NTB Transport Linux driver * * Contact Information: * Jon Mason @@ -56,9 +58,22 @@ #include #include #include -#include "hw/intel/ntb_hw_intel.h" +#include "linux/ntb.h" +#include "linux/ntb_transport.h" -#define NTB_TRANSPORT_VERSION 3 +#define NTB_TRANSPORT_VERSION 4 +#define NTB_TRANSPORT_VER "4" +#define NTB_TRANSPORT_NAME "ntb_transport" +#define NTB_TRANSPORT_DESC "Software Queue-Pair Transport over NTB" + +MODULE_DESCRIPTION(NTB_TRANSPORT_DESC); +MODULE_VERSION(NTB_TRANSPORT_VER); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Intel Corporation"); + +static unsigned long max_mw_size; +module_param(max_mw_size, ulong, 0644); +MODULE_PARM_DESC(max_mw_size, "Limit size of large memory windows"); static unsigned int transport_mtu = 0x401E; module_param(transport_mtu, uint, 0644); @@ -72,10 +87,12 @@ static unsigned int copy_bytes = 1024; module_param(copy_bytes, uint, 0644); MODULE_PARM_DESC(copy_bytes, "Threshold under which NTB will use the CPU to copy instead of DMA"); +static struct dentry *nt_debugfs_dir; + struct ntb_queue_entry { /* ntb_queue list reference */ struct list_head entry; - /* pointers to data to be transfered */ + /* pointers to data to be transferred */ void *cb_data; void *buf; unsigned int len; @@ -94,14 +111,16 @@ struct ntb_rx_info { }; struct ntb_transport_qp { - struct ntb_transport *transport; - struct ntb_device *ndev; + struct ntb_transport_ctx *transport; + struct ntb_dev *ndev; void *cb_data; struct dma_chan *dma_chan; bool client_ready; - bool qp_link; + bool link_is_up; + u8 qp_num; /* Only 64 QP's are allowed. 0-63 */ + u64 qp_bit; struct ntb_rx_info __iomem *rx_info; struct ntb_rx_info *remote_rx_info; @@ -127,6 +146,7 @@ struct ntb_transport_qp { unsigned int rx_max_entry; unsigned int rx_max_frame; dma_cookie_t last_cookie; + struct tasklet_struct rxc_db_work; void (*event_handler)(void *data, int status); struct delayed_work link_work; @@ -153,33 +173,44 @@ struct ntb_transport_qp { }; struct ntb_transport_mw { - size_t size; + phys_addr_t phys_addr; + resource_size_t phys_size; + resource_size_t xlat_align; + resource_size_t xlat_align_size; + void __iomem *vbase; + size_t xlat_size; + size_t buff_size; void *virt_addr; dma_addr_t dma_addr; }; struct ntb_transport_client_dev { struct list_head entry; + struct ntb_transport_ctx *nt; struct device dev; }; -struct ntb_transport { +struct ntb_transport_ctx { struct list_head entry; struct list_head client_devs; - struct ntb_device *ndev; - struct ntb_transport_mw *mw; - struct ntb_transport_qp *qps; - unsigned int max_qps; - unsigned long qp_bitmap; - bool transport_link; + struct ntb_dev *ndev; + + struct ntb_transport_mw *mw_vec; + struct ntb_transport_qp *qp_vec; + unsigned int mw_count; + unsigned int qp_count; + u64 qp_bitmap; + u64 qp_bitmap_free; + + bool link_is_up; struct delayed_work link_work; struct work_struct link_cleanup; }; enum { - DESC_DONE_FLAG = 1 << 0, - LINK_DOWN_FLAG = 1 << 1, + DESC_DONE_FLAG = BIT(0), + LINK_DOWN_FLAG = BIT(1), }; struct ntb_payload_header { @@ -200,68 +231,69 @@ enum { MAX_SPAD, }; -#define QP_TO_MW(ndev, qp) ((qp) % ntb_max_mw(ndev)) +#define dev_client_dev(__dev) \ + container_of((__dev), struct ntb_transport_client_dev, dev) + +#define drv_client(__drv) \ + container_of((__drv), struct ntb_transport_client, driver) + +#define QP_TO_MW(nt, qp) ((qp) % nt->mw_count) #define NTB_QP_DEF_NUM_ENTRIES 100 #define NTB_LINK_DOWN_TIMEOUT 10 -static int ntb_match_bus(struct device *dev, struct device_driver *drv) +static void ntb_transport_rxc_db(unsigned long data); +static const struct ntb_ctx_ops ntb_transport_ops; +static struct ntb_client ntb_transport_client; + +static int ntb_transport_bus_match(struct device *dev, + struct device_driver *drv) { return !strncmp(dev_name(dev), drv->name, strlen(drv->name)); } -static int ntb_client_probe(struct device *dev) +static int ntb_transport_bus_probe(struct device *dev) { - const struct ntb_client *drv = container_of(dev->driver, - struct ntb_client, driver); - struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev); + const struct ntb_transport_client *client; int rc = -EINVAL; get_device(dev); - if (drv && drv->probe) - rc = drv->probe(pdev); + + client = drv_client(dev->driver); + rc = client->probe(dev); if (rc) put_device(dev); return rc; } -static int ntb_client_remove(struct device *dev) +static int ntb_transport_bus_remove(struct device *dev) { - const struct ntb_client *drv = container_of(dev->driver, - struct ntb_client, driver); - struct pci_dev *pdev = container_of(dev->parent, struct pci_dev, dev); + const struct ntb_transport_client *client; - if (drv && drv->remove) - drv->remove(pdev); + client = drv_client(dev->driver); + client->remove(dev); put_device(dev); return 0; } -static struct bus_type ntb_bus_type = { - .name = "ntb_bus", - .match = ntb_match_bus, - .probe = ntb_client_probe, - .remove = ntb_client_remove, +static struct bus_type ntb_transport_bus = { + .name = "ntb_transport", + .match = ntb_transport_bus_match, + .probe = ntb_transport_bus_probe, + .remove = ntb_transport_bus_remove, }; static LIST_HEAD(ntb_transport_list); -static int ntb_bus_init(struct ntb_transport *nt) +static int ntb_bus_init(struct ntb_transport_ctx *nt) { - if (list_empty(&ntb_transport_list)) { - int rc = bus_register(&ntb_bus_type); - if (rc) - return rc; - } - list_add(&nt->entry, &ntb_transport_list); - return 0; } -static void ntb_bus_remove(struct ntb_transport *nt) +static void ntb_bus_remove(struct ntb_transport_ctx *nt) { struct ntb_transport_client_dev *client_dev, *cd; @@ -273,29 +305,26 @@ static void ntb_bus_remove(struct ntb_transport *nt) } list_del(&nt->entry); - - if (list_empty(&ntb_transport_list)) - bus_unregister(&ntb_bus_type); } -static void ntb_client_release(struct device *dev) +static void ntb_transport_client_release(struct device *dev) { struct ntb_transport_client_dev *client_dev; - client_dev = container_of(dev, struct ntb_transport_client_dev, dev); + client_dev = dev_client_dev(dev); kfree(client_dev); } /** - * ntb_unregister_client_dev - Unregister NTB client device + * ntb_transport_unregister_client_dev - Unregister NTB client device * @device_name: Name of NTB client device * * Unregister an NTB client device with the NTB transport layer */ -void ntb_unregister_client_dev(char *device_name) +void ntb_transport_unregister_client_dev(char *device_name) { struct ntb_transport_client_dev *client, *cd; - struct ntb_transport *nt; + struct ntb_transport_ctx *nt; list_for_each_entry(nt, &ntb_transport_list, entry) list_for_each_entry_safe(client, cd, &nt->client_devs, entry) @@ -305,18 +334,18 @@ void ntb_unregister_client_dev(char *device_name) device_unregister(&client->dev); } } -EXPORT_SYMBOL_GPL(ntb_unregister_client_dev); +EXPORT_SYMBOL_GPL(ntb_transport_unregister_client_dev); /** - * ntb_register_client_dev - Register NTB client device + * ntb_transport_register_client_dev - Register NTB client device * @device_name: Name of NTB client device * * Register an NTB client device with the NTB transport layer */ -int ntb_register_client_dev(char *device_name) +int ntb_transport_register_client_dev(char *device_name) { struct ntb_transport_client_dev *client_dev; - struct ntb_transport *nt; + struct ntb_transport_ctx *nt; int rc, i = 0; if (list_empty(&ntb_transport_list)) @@ -325,7 +354,7 @@ int ntb_register_client_dev(char *device_name) list_for_each_entry(nt, &ntb_transport_list, entry) { struct device *dev; - client_dev = kzalloc(sizeof(struct ntb_transport_client_dev), + client_dev = kzalloc(sizeof(*client_dev), GFP_KERNEL); if (!client_dev) { rc = -ENOMEM; @@ -336,9 +365,9 @@ int ntb_register_client_dev(char *device_name) /* setup and register client devices */ dev_set_name(dev, "%s%d", device_name, i); - dev->bus = &ntb_bus_type; - dev->release = ntb_client_release; - dev->parent = &ntb_query_pdev(nt->ndev)->dev; + dev->bus = &ntb_transport_bus; + dev->release = ntb_transport_client_release; + dev->parent = &nt->ndev->dev; rc = device_register(dev); if (rc) { @@ -353,11 +382,11 @@ int ntb_register_client_dev(char *device_name) return 0; err: - ntb_unregister_client_dev(device_name); + ntb_transport_unregister_client_dev(device_name); return rc; } -EXPORT_SYMBOL_GPL(ntb_register_client_dev); +EXPORT_SYMBOL_GPL(ntb_transport_register_client_dev); /** * ntb_transport_register_client - Register NTB client driver @@ -367,9 +396,9 @@ EXPORT_SYMBOL_GPL(ntb_register_client_dev); * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -int ntb_transport_register_client(struct ntb_client *drv) +int ntb_transport_register_client(struct ntb_transport_client *drv) { - drv->driver.bus = &ntb_bus_type; + drv->driver.bus = &ntb_transport_bus; if (list_empty(&ntb_transport_list)) return -ENODEV; @@ -386,7 +415,7 @@ EXPORT_SYMBOL_GPL(ntb_transport_register_client); * * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ -void ntb_transport_unregister_client(struct ntb_client *drv) +void ntb_transport_unregister_client(struct ntb_transport_client *drv) { driver_unregister(&drv->driver); } @@ -452,8 +481,8 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, "tx_max_entry - \t%u\n", qp->tx_max_entry); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "\nQP Link %s\n", (qp->qp_link == NTB_LINK_UP) ? - "Up" : "Down"); + "\nQP Link %s\n", + qp->link_is_up ? "Up" : "Down"); if (out_offset > out_count) out_offset = out_count; @@ -497,26 +526,31 @@ out: return entry; } -static void ntb_transport_setup_qp_mw(struct ntb_transport *nt, - unsigned int qp_num) +static int ntb_transport_setup_qp_mw(struct ntb_transport_ctx *nt, + unsigned int qp_num) { - struct ntb_transport_qp *qp = &nt->qps[qp_num]; + struct ntb_transport_qp *qp = &nt->qp_vec[qp_num]; + struct ntb_transport_mw *mw; unsigned int rx_size, num_qps_mw; - u8 mw_num, mw_max; + unsigned int mw_num, mw_count, qp_count; unsigned int i; - mw_max = ntb_max_mw(nt->ndev); - mw_num = QP_TO_MW(nt->ndev, qp_num); + mw_count = nt->mw_count; + qp_count = nt->qp_count; - WARN_ON(nt->mw[mw_num].virt_addr == NULL); + mw_num = QP_TO_MW(nt, qp_num); + mw = &nt->mw_vec[mw_num]; + + if (!mw->virt_addr) + return -ENOMEM; - if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max) - num_qps_mw = nt->max_qps / mw_max + 1; + if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count) + num_qps_mw = qp_count / mw_count + 1; else - num_qps_mw = nt->max_qps / mw_max; + num_qps_mw = qp_count / mw_count; - rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw; - qp->rx_buff = nt->mw[mw_num].virt_addr + qp_num / mw_max * rx_size; + rx_size = (unsigned int)mw->xlat_size / num_qps_mw; + qp->rx_buff = mw->virt_addr + rx_size * qp_num / mw_count; rx_size -= sizeof(struct ntb_rx_info); qp->remote_rx_info = qp->rx_buff + rx_size; @@ -530,49 +564,63 @@ static void ntb_transport_setup_qp_mw(struct ntb_transport *nt, /* setup the hdr offsets with 0's */ for (i = 0; i < qp->rx_max_entry; i++) { - void *offset = qp->rx_buff + qp->rx_max_frame * (i + 1) - - sizeof(struct ntb_payload_header); + void *offset = (qp->rx_buff + qp->rx_max_frame * (i + 1) - + sizeof(struct ntb_payload_header)); memset(offset, 0, sizeof(struct ntb_payload_header)); } qp->rx_pkts = 0; qp->tx_pkts = 0; qp->tx_index = 0; + + return 0; } -static void ntb_free_mw(struct ntb_transport *nt, int num_mw) +static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw) { - struct ntb_transport_mw *mw = &nt->mw[num_mw]; - struct pci_dev *pdev = ntb_query_pdev(nt->ndev); + struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; + struct pci_dev *pdev = nt->ndev->pdev; if (!mw->virt_addr) return; - dma_free_coherent(&pdev->dev, mw->size, mw->virt_addr, mw->dma_addr); + ntb_mw_clear_trans(nt->ndev, num_mw); + dma_free_coherent(&pdev->dev, mw->buff_size, + mw->virt_addr, mw->dma_addr); + mw->xlat_size = 0; + mw->buff_size = 0; mw->virt_addr = NULL; } -static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size) +static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw, + unsigned int size) { - struct ntb_transport_mw *mw = &nt->mw[num_mw]; - struct pci_dev *pdev = ntb_query_pdev(nt->ndev); + struct ntb_transport_mw *mw = &nt->mw_vec[num_mw]; + struct pci_dev *pdev = nt->ndev->pdev; + unsigned int xlat_size, buff_size; + int rc; + + xlat_size = round_up(size, mw->xlat_align_size); + buff_size = round_up(size, mw->xlat_align); /* No need to re-setup */ - if (mw->size == ALIGN(size, 4096)) + if (mw->xlat_size == xlat_size) return 0; - if (mw->size != 0) + if (mw->buff_size) ntb_free_mw(nt, num_mw); - /* Alloc memory for receiving data. Must be 4k aligned */ - mw->size = ALIGN(size, 4096); + /* Alloc memory for receiving data. Must be aligned */ + mw->xlat_size = xlat_size; + mw->buff_size = buff_size; - mw->virt_addr = dma_alloc_coherent(&pdev->dev, mw->size, &mw->dma_addr, - GFP_KERNEL); + mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size, + &mw->dma_addr, GFP_KERNEL); if (!mw->virt_addr) { - mw->size = 0; - dev_err(&pdev->dev, "Unable to allocate MW buffer of size %d\n", - (int) mw->size); + mw->xlat_size = 0; + mw->buff_size = 0; + dev_err(&pdev->dev, "Unable to alloc MW buff of size %d\n", + buff_size); return -ENOMEM; } @@ -582,34 +630,39 @@ static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size) * is a requirement of the hardware. It is recommended to setup CMA * for BAR sizes equal or greater than 4MB. */ - if (!IS_ALIGNED(mw->dma_addr, mw->size)) { - dev_err(&pdev->dev, "DMA memory %pad not aligned to BAR size\n", + if (!IS_ALIGNED(mw->dma_addr, mw->xlat_align)) { + dev_err(&pdev->dev, "DMA memory %pad is not aligned\n", &mw->dma_addr); ntb_free_mw(nt, num_mw); return -ENOMEM; } /* Notify HW the memory location of the receive buffer */ - ntb_set_mw_addr(nt->ndev, num_mw, mw->dma_addr); + rc = ntb_mw_set_trans(nt->ndev, num_mw, mw->dma_addr, mw->xlat_size); + if (rc) { + dev_err(&pdev->dev, "Unable to set mw%d translation", num_mw); + ntb_free_mw(nt, num_mw); + return -EIO; + } return 0; } static void ntb_qp_link_cleanup(struct ntb_transport_qp *qp) { - struct ntb_transport *nt = qp->transport; - struct pci_dev *pdev = ntb_query_pdev(nt->ndev); + struct ntb_transport_ctx *nt = qp->transport; + struct pci_dev *pdev = nt->ndev->pdev; - if (qp->qp_link == NTB_LINK_DOWN) { + if (qp->link_is_up) { cancel_delayed_work_sync(&qp->link_work); return; } - if (qp->event_handler) - qp->event_handler(qp->cb_data, NTB_LINK_DOWN); - dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); - qp->qp_link = NTB_LINK_DOWN; + qp->link_is_up = false; + + if (qp->event_handler) + qp->event_handler(qp->cb_data, qp->link_is_up); } static void ntb_qp_link_cleanup_work(struct work_struct *work) @@ -617,11 +670,11 @@ static void ntb_qp_link_cleanup_work(struct work_struct *work) struct ntb_transport_qp *qp = container_of(work, struct ntb_transport_qp, link_cleanup); - struct ntb_transport *nt = qp->transport; + struct ntb_transport_ctx *nt = qp->transport; ntb_qp_link_cleanup(qp); - if (nt->transport_link == NTB_LINK_UP) + if (nt->link_is_up) schedule_delayed_work(&qp->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } @@ -631,180 +684,132 @@ static void ntb_qp_link_down(struct ntb_transport_qp *qp) schedule_work(&qp->link_cleanup); } -static void ntb_transport_link_cleanup(struct ntb_transport *nt) +static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt) { + struct ntb_transport_qp *qp; + u64 qp_bitmap_alloc; int i; + qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; + /* Pass along the info to any clients */ - for (i = 0; i < nt->max_qps; i++) - if (!test_bit(i, &nt->qp_bitmap)) - ntb_qp_link_cleanup(&nt->qps[i]); + for (i = 0; i < nt->qp_count; i++) + if (qp_bitmap_alloc & BIT_ULL(i)) { + qp = &nt->qp_vec[i]; + ntb_qp_link_cleanup(qp); + cancel_work_sync(&qp->link_cleanup); + cancel_delayed_work_sync(&qp->link_work); + } - if (nt->transport_link == NTB_LINK_DOWN) + if (!nt->link_is_up) cancel_delayed_work_sync(&nt->link_work); - else - nt->transport_link = NTB_LINK_DOWN; /* The scratchpad registers keep the values if the remote side * goes down, blast them now to give them a sane value the next * time they are accessed */ for (i = 0; i < MAX_SPAD; i++) - ntb_write_local_spad(nt->ndev, i, 0); + ntb_spad_write(nt->ndev, i, 0); } static void ntb_transport_link_cleanup_work(struct work_struct *work) { - struct ntb_transport *nt = container_of(work, struct ntb_transport, - link_cleanup); + struct ntb_transport_ctx *nt = + container_of(work, struct ntb_transport_ctx, link_cleanup); ntb_transport_link_cleanup(nt); } -static void ntb_transport_event_callback(void *data, enum ntb_hw_event event) +static void ntb_transport_event_callback(void *data) { - struct ntb_transport *nt = data; + struct ntb_transport_ctx *nt = data; - switch (event) { - case NTB_EVENT_HW_LINK_UP: + if (ntb_link_is_up(nt->ndev, NULL, NULL) == 1) schedule_delayed_work(&nt->link_work, 0); - break; - case NTB_EVENT_HW_LINK_DOWN: + else schedule_work(&nt->link_cleanup); - break; - default: - BUG(); - } } static void ntb_transport_link_work(struct work_struct *work) { - struct ntb_transport *nt = container_of(work, struct ntb_transport, - link_work.work); - struct ntb_device *ndev = nt->ndev; - struct pci_dev *pdev = ntb_query_pdev(ndev); + struct ntb_transport_ctx *nt = + container_of(work, struct ntb_transport_ctx, link_work.work); + struct ntb_dev *ndev = nt->ndev; + struct pci_dev *pdev = ndev->pdev; + resource_size_t size; u32 val; - int rc, i; + int rc, i, spad; /* send the local info, in the opposite order of the way we read it */ - for (i = 0; i < ntb_max_mw(ndev); i++) { - rc = ntb_write_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), - ntb_get_mw_size(ndev, i) >> 32); - if (rc) { - dev_err(&pdev->dev, "Error writing %u to remote spad %d\n", - (u32)(ntb_get_mw_size(ndev, i) >> 32), - MW0_SZ_HIGH + (i * 2)); - goto out; - } + for (i = 0; i < nt->mw_count; i++) { + size = nt->mw_vec[i].phys_size; - rc = ntb_write_remote_spad(ndev, MW0_SZ_LOW + (i * 2), - (u32) ntb_get_mw_size(ndev, i)); - if (rc) { - dev_err(&pdev->dev, "Error writing %u to remote spad %d\n", - (u32) ntb_get_mw_size(ndev, i), - MW0_SZ_LOW + (i * 2)); - goto out; - } - } + if (max_mw_size && size > max_mw_size) + size = max_mw_size; - rc = ntb_write_remote_spad(ndev, NUM_MWS, ntb_max_mw(ndev)); - if (rc) { - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - ntb_max_mw(ndev), NUM_MWS); - goto out; - } + spad = MW0_SZ_HIGH + (i * 2); + ntb_peer_spad_write(ndev, spad, (u32)(size >> 32)); - rc = ntb_write_remote_spad(ndev, NUM_QPS, nt->max_qps); - if (rc) { - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - nt->max_qps, NUM_QPS); - goto out; + spad = MW0_SZ_LOW + (i * 2); + ntb_peer_spad_write(ndev, spad, (u32)size); } - rc = ntb_write_remote_spad(ndev, VERSION, NTB_TRANSPORT_VERSION); - if (rc) { - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - NTB_TRANSPORT_VERSION, VERSION); - goto out; - } + ntb_peer_spad_write(ndev, NUM_MWS, nt->mw_count); - /* Query the remote side for its info */ - rc = ntb_read_remote_spad(ndev, VERSION, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", VERSION); - goto out; - } + ntb_peer_spad_write(ndev, NUM_QPS, nt->qp_count); - if (val != NTB_TRANSPORT_VERSION) - goto out; - dev_dbg(&pdev->dev, "Remote version = %d\n", val); + ntb_peer_spad_write(ndev, VERSION, NTB_TRANSPORT_VERSION); - rc = ntb_read_remote_spad(ndev, NUM_QPS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_QPS); + /* Query the remote side for its info */ + val = ntb_peer_spad_read(ndev, VERSION); + dev_dbg(&pdev->dev, "Remote version = %d\n", val); + if (val != NTB_TRANSPORT_VERSION) goto out; - } - if (val != nt->max_qps) - goto out; + val = ntb_peer_spad_read(ndev, NUM_QPS); dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val); - - rc = ntb_read_remote_spad(ndev, NUM_MWS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_MWS); + if (val != nt->qp_count) goto out; - } - if (val != ntb_max_mw(ndev)) - goto out; + val = ntb_peer_spad_read(ndev, NUM_MWS); dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val); + if (val != nt->mw_count) + goto out; - for (i = 0; i < ntb_max_mw(ndev); i++) { + for (i = 0; i < nt->mw_count; i++) { u64 val64; - rc = ntb_read_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", - MW0_SZ_HIGH + (i * 2)); - goto out1; - } - - val64 = (u64) val << 32; - - rc = ntb_read_remote_spad(ndev, MW0_SZ_LOW + (i * 2), &val); - if (rc) { - dev_err(&pdev->dev, "Error reading remote spad %d\n", - MW0_SZ_LOW + (i * 2)); - goto out1; - } + val = ntb_peer_spad_read(ndev, MW0_SZ_HIGH + (i * 2)); + val64 = (u64)val << 32; + val = ntb_peer_spad_read(ndev, MW0_SZ_LOW + (i * 2)); val64 |= val; - dev_dbg(&pdev->dev, "Remote MW%d size = %llu\n", i, val64); + dev_dbg(&pdev->dev, "Remote MW%d size = %#llx\n", i, val64); rc = ntb_set_mw(nt, i, val64); if (rc) goto out1; } - nt->transport_link = NTB_LINK_UP; + nt->link_is_up = true; - for (i = 0; i < nt->max_qps; i++) { - struct ntb_transport_qp *qp = &nt->qps[i]; + for (i = 0; i < nt->qp_count; i++) { + struct ntb_transport_qp *qp = &nt->qp_vec[i]; ntb_transport_setup_qp_mw(nt, i); - if (qp->client_ready == NTB_LINK_UP) + if (qp->client_ready) schedule_delayed_work(&qp->link_work, 0); } return; out1: - for (i = 0; i < ntb_max_mw(ndev); i++) + for (i = 0; i < nt->mw_count; i++) ntb_free_mw(nt, i); out: - if (ntb_hw_link_status(ndev)) + if (ntb_link_is_up(ndev, NULL, NULL) == 1) schedule_delayed_work(&nt->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } @@ -814,73 +819,73 @@ static void ntb_qp_link_work(struct work_struct *work) struct ntb_transport_qp *qp = container_of(work, struct ntb_transport_qp, link_work.work); - struct pci_dev *pdev = ntb_query_pdev(qp->ndev); - struct ntb_transport *nt = qp->transport; - int rc, val; + struct pci_dev *pdev = qp->ndev->pdev; + struct ntb_transport_ctx *nt = qp->transport; + int val; - WARN_ON(nt->transport_link != NTB_LINK_UP); + WARN_ON(!nt->link_is_up); - rc = ntb_read_local_spad(nt->ndev, QP_LINKS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS); - return; - } + val = ntb_spad_read(nt->ndev, QP_LINKS); - rc = ntb_write_remote_spad(nt->ndev, QP_LINKS, val | 1 << qp->qp_num); - if (rc) - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - val | 1 << qp->qp_num, QP_LINKS); + ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num)); /* query remote spad for qp ready bits */ - rc = ntb_read_remote_spad(nt->ndev, QP_LINKS, &val); - if (rc) - dev_err(&pdev->dev, "Error reading remote spad %d\n", QP_LINKS); - + ntb_peer_spad_read(nt->ndev, QP_LINKS); dev_dbg(&pdev->dev, "Remote QP link status = %x\n", val); /* See if the remote side is up */ - if (1 << qp->qp_num & val) { - qp->qp_link = NTB_LINK_UP; - + if (val & BIT(qp->qp_num)) { dev_info(&pdev->dev, "qp %d: Link Up\n", qp->qp_num); + qp->link_is_up = true; + if (qp->event_handler) - qp->event_handler(qp->cb_data, NTB_LINK_UP); - } else if (nt->transport_link == NTB_LINK_UP) + qp->event_handler(qp->cb_data, qp->link_is_up); + } else if (nt->link_is_up) schedule_delayed_work(&qp->link_work, msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT)); } -static int ntb_transport_init_queue(struct ntb_transport *nt, +static int ntb_transport_init_queue(struct ntb_transport_ctx *nt, unsigned int qp_num) { struct ntb_transport_qp *qp; + struct ntb_transport_mw *mw; + phys_addr_t mw_base; + resource_size_t mw_size; unsigned int num_qps_mw, tx_size; - u8 mw_num, mw_max; + unsigned int mw_num, mw_count, qp_count; u64 qp_offset; - mw_max = ntb_max_mw(nt->ndev); - mw_num = QP_TO_MW(nt->ndev, qp_num); + mw_count = nt->mw_count; + qp_count = nt->qp_count; - qp = &nt->qps[qp_num]; + mw_num = QP_TO_MW(nt, qp_num); + mw = &nt->mw_vec[mw_num]; + + qp = &nt->qp_vec[qp_num]; qp->qp_num = qp_num; qp->transport = nt; qp->ndev = nt->ndev; - qp->qp_link = NTB_LINK_DOWN; - qp->client_ready = NTB_LINK_DOWN; + qp->link_is_up = false; + qp->client_ready = false; qp->event_handler = NULL; - if (nt->max_qps % mw_max && mw_num + 1 < nt->max_qps / mw_max) - num_qps_mw = nt->max_qps / mw_max + 1; + if (qp_count % mw_count && mw_num + 1 < qp_count / mw_count) + num_qps_mw = qp_count / mw_count + 1; else - num_qps_mw = nt->max_qps / mw_max; + num_qps_mw = qp_count / mw_count; + + mw_base = nt->mw_vec[mw_num].phys_addr; + mw_size = nt->mw_vec[mw_num].phys_size; - tx_size = (unsigned int) ntb_get_mw_size(qp->ndev, mw_num) / num_qps_mw; - qp_offset = qp_num / mw_max * tx_size; - qp->tx_mw = ntb_get_mw_vbase(nt->ndev, mw_num) + qp_offset; + tx_size = (unsigned int)mw_size / num_qps_mw; + qp_offset = tx_size * qp_num / mw_count; + + qp->tx_mw = nt->mw_vec[mw_num].vbase + qp_offset; if (!qp->tx_mw) return -EINVAL; - qp->tx_mw_phys = ntb_get_mw_base(qp->ndev, mw_num) + qp_offset; + qp->tx_mw_phys = mw_base + qp_offset; if (!qp->tx_mw_phys) return -EINVAL; @@ -891,16 +896,19 @@ static int ntb_transport_init_queue(struct ntb_transport *nt, qp->tx_max_frame = min(transport_mtu, tx_size / 2); qp->tx_max_entry = tx_size / qp->tx_max_frame; - if (ntb_query_debugfs(nt->ndev)) { + if (nt_debugfs_dir) { char debugfs_name[4]; snprintf(debugfs_name, 4, "qp%d", qp_num); qp->debugfs_dir = debugfs_create_dir(debugfs_name, - ntb_query_debugfs(nt->ndev)); + nt_debugfs_dir); qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR, qp->debugfs_dir, qp, &ntb_qp_debugfs_stats); + } else { + qp->debugfs_dir = NULL; + qp->debugfs_stats = NULL; } INIT_DELAYED_WORK(&qp->link_work, ntb_qp_link_work); @@ -914,46 +922,84 @@ static int ntb_transport_init_queue(struct ntb_transport *nt, INIT_LIST_HEAD(&qp->rx_free_q); INIT_LIST_HEAD(&qp->tx_free_q); + tasklet_init(&qp->rxc_db_work, ntb_transport_rxc_db, + (unsigned long)qp); + return 0; } -int ntb_transport_init(struct pci_dev *pdev) +static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) { - struct ntb_transport *nt; + struct ntb_transport_ctx *nt; + struct ntb_transport_mw *mw; + unsigned int mw_count, qp_count; + u64 qp_bitmap; int rc, i; - nt = kzalloc(sizeof(struct ntb_transport), GFP_KERNEL); + if (ntb_db_is_unsafe(ndev)) + dev_dbg(&ndev->dev, + "doorbell is unsafe, proceed anyway...\n"); + if (ntb_spad_is_unsafe(ndev)) + dev_dbg(&ndev->dev, + "scratchpad is unsafe, proceed anyway...\n"); + + nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) return -ENOMEM; - nt->ndev = ntb_register_transport(pdev, nt); - if (!nt->ndev) { - rc = -EIO; + nt->ndev = ndev; + + mw_count = ntb_mw_count(ndev); + + nt->mw_count = mw_count; + + nt->mw_vec = kcalloc(mw_count, sizeof(*nt->mw_vec), GFP_KERNEL); + if (!nt->mw_vec) { + rc = -ENOMEM; goto err; } - nt->mw = kcalloc(ntb_max_mw(nt->ndev), sizeof(struct ntb_transport_mw), - GFP_KERNEL); - if (!nt->mw) { - rc = -ENOMEM; - goto err1; + for (i = 0; i < mw_count; i++) { + mw = &nt->mw_vec[i]; + + rc = ntb_mw_get_range(ndev, i, &mw->phys_addr, &mw->phys_size, + &mw->xlat_align, &mw->xlat_align_size); + if (rc) + goto err1; + + mw->vbase = ioremap(mw->phys_addr, mw->phys_size); + if (!mw->vbase) { + rc = -ENOMEM; + goto err1; + } + + mw->buff_size = 0; + mw->xlat_size = 0; + mw->virt_addr = NULL; + mw->dma_addr = 0; } - if (max_num_clients) - nt->max_qps = min(ntb_max_cbs(nt->ndev), max_num_clients); - else - nt->max_qps = min(ntb_max_cbs(nt->ndev), ntb_max_mw(nt->ndev)); + qp_bitmap = ntb_db_valid_mask(ndev); + + qp_count = ilog2(qp_bitmap); + if (max_num_clients && max_num_clients < qp_count) + qp_count = max_num_clients; + else if (mw_count < qp_count) + qp_count = mw_count; + + qp_bitmap &= BIT_ULL(qp_count) - 1; + + nt->qp_count = qp_count; + nt->qp_bitmap = qp_bitmap; + nt->qp_bitmap_free = qp_bitmap; - nt->qps = kcalloc(nt->max_qps, sizeof(struct ntb_transport_qp), - GFP_KERNEL); - if (!nt->qps) { + nt->qp_vec = kcalloc(qp_count, sizeof(*nt->qp_vec), GFP_KERNEL); + if (!nt->qp_vec) { rc = -ENOMEM; goto err2; } - nt->qp_bitmap = ((u64) 1 << nt->max_qps) - 1; - - for (i = 0; i < nt->max_qps; i++) { + for (i = 0; i < qp_count; i++) { rc = ntb_transport_init_queue(nt, i); if (rc) goto err3; @@ -962,8 +1008,7 @@ int ntb_transport_init(struct pci_dev *pdev) INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work); INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup_work); - rc = ntb_register_event_callback(nt->ndev, - ntb_transport_event_callback); + rc = ntb_set_ctx(ndev, nt, &ntb_transport_ops); if (rc) goto err3; @@ -972,51 +1017,61 @@ int ntb_transport_init(struct pci_dev *pdev) if (rc) goto err4; - if (ntb_hw_link_status(nt->ndev)) - schedule_delayed_work(&nt->link_work, 0); + nt->link_is_up = false; + ntb_link_enable(ndev, NTB_SPEED_AUTO, NTB_WIDTH_AUTO); + ntb_link_event(ndev); return 0; err4: - ntb_unregister_event_callback(nt->ndev); + ntb_clear_ctx(ndev); err3: - kfree(nt->qps); + kfree(nt->qp_vec); err2: - kfree(nt->mw); + kfree(nt->mw_vec); err1: - ntb_unregister_transport(nt->ndev); + while (i--) { + mw = &nt->mw_vec[i]; + iounmap(mw->vbase); + } err: kfree(nt); return rc; } -void ntb_transport_free(void *transport) +static void ntb_transport_free(struct ntb_client *self, struct ntb_dev *ndev) { - struct ntb_transport *nt = transport; - struct ntb_device *ndev = nt->ndev; + struct ntb_transport_ctx *nt = ndev->ctx; + struct ntb_transport_qp *qp; + u64 qp_bitmap_alloc; int i; ntb_transport_link_cleanup(nt); + cancel_work_sync(&nt->link_cleanup); + cancel_delayed_work_sync(&nt->link_work); + + qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; /* verify that all the qp's are freed */ - for (i = 0; i < nt->max_qps; i++) { - if (!test_bit(i, &nt->qp_bitmap)) - ntb_transport_free_queue(&nt->qps[i]); - debugfs_remove_recursive(nt->qps[i].debugfs_dir); + for (i = 0; i < nt->qp_count; i++) { + qp = &nt->qp_vec[i]; + if (qp_bitmap_alloc & BIT_ULL(i)) + ntb_transport_free_queue(qp); + debugfs_remove_recursive(qp->debugfs_dir); } - ntb_bus_remove(nt); + ntb_link_disable(ndev); + ntb_clear_ctx(ndev); - cancel_delayed_work_sync(&nt->link_work); - - ntb_unregister_event_callback(ndev); + ntb_bus_remove(nt); - for (i = 0; i < ntb_max_mw(ndev); i++) + for (i = nt->mw_count; i--; ) { ntb_free_mw(nt, i); + iounmap(nt->mw_vec[i].vbase); + } - kfree(nt->qps); - kfree(nt->mw); - ntb_unregister_transport(ndev); + kfree(nt->qp_vec); + kfree(nt->mw_vec); kfree(nt); } @@ -1028,15 +1083,13 @@ static void ntb_rx_copy_callback(void *data) unsigned int len = entry->len; struct ntb_payload_header *hdr = entry->rx_hdr; - /* Ensure that the data is fully copied out before clearing the flag */ - wmb(); hdr->flags = 0; iowrite32(entry->index, &qp->rx_info->entry); ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q); - if (qp->rx_handler && qp->client_ready == NTB_LINK_UP) + if (qp->rx_handler && qp->client_ready) qp->rx_handler(qp, qp->cb_data, cb_data, len); } @@ -1047,6 +1100,9 @@ static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset) memcpy(buf, offset, len); + /* Ensure that the data is fully copied out before clearing the flag */ + wmb(); + ntb_rx_copy_callback(entry); } @@ -1071,8 +1127,8 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset, goto err_wait; device = chan->device; - pay_off = (size_t) offset & ~PAGE_MASK; - buff_off = (size_t) buf & ~PAGE_MASK; + pay_off = (size_t)offset & ~PAGE_MASK; + buff_off = (size_t)buf & ~PAGE_MASK; if (!is_dma_copy_aligned(device, pay_off, buff_off, len)) goto err_wait; @@ -1138,86 +1194,104 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp) struct ntb_payload_header *hdr; struct ntb_queue_entry *entry; void *offset; + int rc; offset = qp->rx_buff + qp->rx_max_frame * qp->rx_index; hdr = offset + qp->rx_max_frame - sizeof(struct ntb_payload_header); - entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); - if (!entry) { - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "no buffer - HDR ver %u, len %d, flags %x\n", - hdr->ver, hdr->len, hdr->flags); - qp->rx_err_no_buf++; - return -ENOMEM; - } + dev_dbg(&qp->ndev->pdev->dev, "qp %d: RX ver %u len %d flags %x\n", + qp->qp_num, hdr->ver, hdr->len, hdr->flags); if (!(hdr->flags & DESC_DONE_FLAG)) { - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, - &qp->rx_pend_q); + dev_dbg(&qp->ndev->pdev->dev, "done flag not set\n"); qp->rx_ring_empty++; return -EAGAIN; } - if (hdr->ver != (u32) qp->rx_pkts) { - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "qp %d: version mismatch, expected %llu - got %u\n", - qp->qp_num, qp->rx_pkts, hdr->ver); - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, - &qp->rx_pend_q); + if (hdr->flags & LINK_DOWN_FLAG) { + dev_dbg(&qp->ndev->pdev->dev, "link down flag set\n"); + ntb_qp_link_down(qp); + hdr->flags = 0; + iowrite32(qp->rx_index, &qp->rx_info->entry); + return 0; + } + + if (hdr->ver != (u32)qp->rx_pkts) { + dev_dbg(&qp->ndev->pdev->dev, + "version mismatch, expected %llu - got %u\n", + qp->rx_pkts, hdr->ver); qp->rx_err_ver++; return -EIO; } - if (hdr->flags & LINK_DOWN_FLAG) { - ntb_qp_link_down(qp); + entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); + if (!entry) { + dev_dbg(&qp->ndev->pdev->dev, "no receive buffer\n"); + qp->rx_err_no_buf++; + rc = -ENOMEM; goto err; } - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "rx offset %u, ver %u - %d payload received, buf size %d\n", - qp->rx_index, hdr->ver, hdr->len, entry->len); - - qp->rx_bytes += hdr->len; - qp->rx_pkts++; - if (hdr->len > entry->len) { - qp->rx_err_oflow++; - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, - "RX overflow! Wanted %d got %d\n", + dev_dbg(&qp->ndev->pdev->dev, + "receive buffer overflow! Wanted %d got %d\n", hdr->len, entry->len); + qp->rx_err_oflow++; + rc = -EIO; goto err; } + dev_dbg(&qp->ndev->pdev->dev, + "RX OK index %u ver %u size %d into buf size %d\n", + qp->rx_index, hdr->ver, hdr->len, entry->len); + + qp->rx_bytes += hdr->len; + qp->rx_pkts++; + entry->index = qp->rx_index; entry->rx_hdr = hdr; ntb_async_rx(entry, offset, hdr->len); -out: qp->rx_index++; qp->rx_index %= qp->rx_max_entry; return 0; err: - ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q); - /* Ensure that the data is fully copied out before clearing the flag */ - wmb(); + /* FIXME: if this syncrhonous update of the rx_index gets ahead of + * asyncrhonous ntb_rx_copy_callback of previous entry, there are three + * scenarios: + * + * 1) The peer might miss this update, but observe the update + * from the memcpy completion callback. In this case, the buffer will + * not be freed on the peer to be reused for a different packet. The + * successful rx of a later packet would clear the condition, but the + * condition could persist if several rx fail in a row. + * + * 2) The peer may observe this update before the asyncrhonous copy of + * prior packets is completed. The peer may overwrite the buffers of + * the prior packets before they are copied. + * + * 3) Both: the peer may observe the update, and then observe the index + * decrement by the asynchronous completion callback. Who knows what + * badness that will cause. + */ hdr->flags = 0; iowrite32(qp->rx_index, &qp->rx_info->entry); - goto out; + return rc; } -static int ntb_transport_rxc_db(void *data, int db_num) +static void ntb_transport_rxc_db(unsigned long data) { - struct ntb_transport_qp *qp = data; + struct ntb_transport_qp *qp = (void *)data; int rc, i; - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%s: doorbell %d received\n", - __func__, db_num); + dev_dbg(&qp->ndev->pdev->dev, "%s: doorbell %d received\n", + __func__, qp->qp_num); /* Limit the number of packets processed in a single interrupt to * provide fairness to others @@ -1231,7 +1305,21 @@ static int ntb_transport_rxc_db(void *data, int db_num) if (qp->dma_chan) dma_async_issue_pending(qp->dma_chan); - return i; + if (i == qp->rx_max_entry) { + /* there is more work to do */ + tasklet_schedule(&qp->rxc_db_work); + } else if (ntb_db_read(qp->ndev) & BIT_ULL(qp->qp_num)) { + /* the doorbell bit is set: clear it */ + ntb_db_clear(qp->ndev, BIT_ULL(qp->qp_num)); + /* ntb_db_read ensures ntb_db_clear write is committed */ + ntb_db_read(qp->ndev); + + /* an interrupt may have arrived between finishing + * ntb_process_rxc and clearing the doorbell bit: + * there might be some more work to do. + */ + tasklet_schedule(&qp->rxc_db_work); + } } static void ntb_tx_copy_callback(void *data) @@ -1240,11 +1328,9 @@ static void ntb_tx_copy_callback(void *data) struct ntb_transport_qp *qp = entry->qp; struct ntb_payload_header __iomem *hdr = entry->tx_hdr; - /* Ensure that the data is fully copied out before setting the flags */ - wmb(); iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags); - ntb_ring_doorbell(qp->ndev, qp->qp_num); + ntb_peer_db_set(qp->ndev, BIT_ULL(qp->qp_num)); /* The entry length can only be zero if the packet is intended to be a * "link down" or similar. Since no payload is being sent in these @@ -1265,6 +1351,9 @@ static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset) { memcpy_toio(offset, entry->buf, entry->len); + /* Ensure that the data is fully copied out before setting the flags */ + wmb(); + ntb_tx_copy_callback(entry); } @@ -1288,7 +1377,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, entry->tx_hdr = hdr; iowrite32(entry->len, &hdr->len); - iowrite32((u32) qp->tx_pkts, &hdr->ver); + iowrite32((u32)qp->tx_pkts, &hdr->ver); if (!chan) goto err; @@ -1298,8 +1387,8 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, device = chan->device; dest = qp->tx_mw_phys + qp->tx_max_frame * qp->tx_index; - buff_off = (size_t) buf & ~PAGE_MASK; - dest_off = (size_t) dest & ~PAGE_MASK; + buff_off = (size_t)buf & ~PAGE_MASK; + dest_off = (size_t)dest & ~PAGE_MASK; if (!is_dma_copy_aligned(device, buff_off, dest_off, len)) goto err; @@ -1347,9 +1436,6 @@ err: static int ntb_process_tx(struct ntb_transport_qp *qp, struct ntb_queue_entry *entry) { - dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%lld - tx %u, entry len %d flags %x buff %p\n", - qp->tx_pkts, qp->tx_index, entry->len, entry->flags, - entry->buf); if (qp->tx_index == qp->remote_rx_info->entry) { qp->tx_ring_full++; return -EAGAIN; @@ -1376,14 +1462,14 @@ static int ntb_process_tx(struct ntb_transport_qp *qp, static void ntb_send_link_down(struct ntb_transport_qp *qp) { - struct pci_dev *pdev = ntb_query_pdev(qp->ndev); + struct pci_dev *pdev = qp->ndev->pdev; struct ntb_queue_entry *entry; int i, rc; - if (qp->qp_link == NTB_LINK_DOWN) + if (!qp->link_is_up) return; - qp->qp_link = NTB_LINK_DOWN; + qp->link_is_up = false; dev_info(&pdev->dev, "qp %d: Link Down\n", qp->qp_num); for (i = 0; i < NTB_LINK_DOWN_TIMEOUT; i++) { @@ -1422,18 +1508,21 @@ static void ntb_send_link_down(struct ntb_transport_qp *qp) * RETURNS: pointer to newly created ntb_queue, NULL on error. */ struct ntb_transport_qp * -ntb_transport_create_queue(void *data, struct pci_dev *pdev, +ntb_transport_create_queue(void *data, struct device *client_dev, const struct ntb_queue_handlers *handlers) { + struct ntb_dev *ndev; + struct pci_dev *pdev; + struct ntb_transport_ctx *nt; struct ntb_queue_entry *entry; struct ntb_transport_qp *qp; - struct ntb_transport *nt; + u64 qp_bit; unsigned int free_queue; - int rc, i; + int i; - nt = ntb_find_transport(pdev); - if (!nt) - goto err; + ndev = dev_ntb(client_dev->parent); + pdev = ndev->pdev; + nt = ndev->ctx; free_queue = ffs(nt->qp_bitmap); if (!free_queue) @@ -1442,9 +1531,11 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, /* decrement free_queue to make it zero based */ free_queue--; - clear_bit(free_queue, &nt->qp_bitmap); + qp = &nt->qp_vec[free_queue]; + qp_bit = BIT_ULL(qp->qp_num); + + nt->qp_bitmap_free &= ~qp_bit; - qp = &nt->qps[free_queue]; qp->cb_data = data; qp->rx_handler = handlers->rx_handler; qp->tx_handler = handlers->tx_handler; @@ -1458,7 +1549,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) goto err1; @@ -1468,7 +1559,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, } for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { - entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) goto err2; @@ -1477,10 +1568,8 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev, &qp->tx_free_q); } - rc = ntb_register_db_callback(qp->ndev, free_queue, qp, - ntb_transport_rxc_db); - if (rc) - goto err2; + ntb_db_clear(qp->ndev, qp_bit); + ntb_db_clear_mask(qp->ndev, qp_bit); dev_info(&pdev->dev, "NTB Transport QP %d created\n", qp->qp_num); @@ -1494,7 +1583,7 @@ err1: kfree(entry); if (qp->dma_chan) dmaengine_put(); - set_bit(free_queue, &nt->qp_bitmap); + nt->qp_bitmap_free |= qp_bit; err: return NULL; } @@ -1508,13 +1597,15 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue); */ void ntb_transport_free_queue(struct ntb_transport_qp *qp) { + struct ntb_transport_ctx *nt = qp->transport; struct pci_dev *pdev; struct ntb_queue_entry *entry; + u64 qp_bit; if (!qp) return; - pdev = ntb_query_pdev(qp->ndev); + pdev = qp->ndev->pdev; if (qp->dma_chan) { struct dma_chan *chan = qp->dma_chan; @@ -1531,10 +1622,18 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) dmaengine_put(); } - ntb_unregister_db_callback(qp->ndev, qp->qp_num); + qp_bit = BIT_ULL(qp->qp_num); + + ntb_db_set_mask(qp->ndev, qp_bit); + tasklet_disable(&qp->rxc_db_work); cancel_delayed_work_sync(&qp->link_work); + qp->cb_data = NULL; + qp->rx_handler = NULL; + qp->tx_handler = NULL; + qp->event_handler = NULL; + while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q))) kfree(entry); @@ -1546,7 +1645,7 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) while ((entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q))) kfree(entry); - set_bit(qp->qp_num, &qp->transport->qp_bitmap); + nt->qp_bitmap_free |= qp_bit; dev_info(&pdev->dev, "NTB Transport QP %d freed\n", qp->qp_num); } @@ -1567,7 +1666,7 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len) struct ntb_queue_entry *entry; void *buf; - if (!qp || qp->client_ready == NTB_LINK_UP) + if (!qp || qp->client_ready) return NULL; entry = ntb_list_rm(&qp->ntb_rx_pend_q_lock, &qp->rx_pend_q); @@ -1636,7 +1735,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, struct ntb_queue_entry *entry; int rc; - if (!qp || qp->qp_link != NTB_LINK_UP || !len) + if (!qp || !qp->link_is_up || !len) return -EINVAL; entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); @@ -1670,9 +1769,9 @@ void ntb_transport_link_up(struct ntb_transport_qp *qp) if (!qp) return; - qp->client_ready = NTB_LINK_UP; + qp->client_ready = true; - if (qp->transport->transport_link == NTB_LINK_UP) + if (qp->transport->link_is_up) schedule_delayed_work(&qp->link_work, 0); } EXPORT_SYMBOL_GPL(ntb_transport_link_up); @@ -1688,27 +1787,20 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_up); void ntb_transport_link_down(struct ntb_transport_qp *qp) { struct pci_dev *pdev; - int rc, val; + int val; if (!qp) return; - pdev = ntb_query_pdev(qp->ndev); - qp->client_ready = NTB_LINK_DOWN; + pdev = qp->ndev->pdev; + qp->client_ready = false; - rc = ntb_read_local_spad(qp->ndev, QP_LINKS, &val); - if (rc) { - dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS); - return; - } + val = ntb_spad_read(qp->ndev, QP_LINKS); - rc = ntb_write_remote_spad(qp->ndev, QP_LINKS, - val & ~(1 << qp->qp_num)); - if (rc) - dev_err(&pdev->dev, "Error writing %x to remote spad %d\n", - val & ~(1 << qp->qp_num), QP_LINKS); + ntb_peer_spad_write(qp->ndev, QP_LINKS, + val & ~BIT(qp->qp_num)); - if (qp->qp_link == NTB_LINK_UP) + if (qp->link_is_up) ntb_send_link_down(qp); else cancel_delayed_work_sync(&qp->link_work); @@ -1728,7 +1820,7 @@ bool ntb_transport_link_query(struct ntb_transport_qp *qp) if (!qp) return false; - return qp->qp_link == NTB_LINK_UP; + return qp->link_is_up; } EXPORT_SYMBOL_GPL(ntb_transport_link_query); @@ -1774,3 +1866,69 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp) return max; } EXPORT_SYMBOL_GPL(ntb_transport_max_size); + +static void ntb_transport_doorbell_callback(void *data, int vector) +{ + struct ntb_transport_ctx *nt = data; + struct ntb_transport_qp *qp; + u64 db_bits; + unsigned int qp_num; + + db_bits = (nt->qp_bitmap & ~nt->qp_bitmap_free & + ntb_db_vector_mask(nt->ndev, vector)); + + while (db_bits) { + qp_num = __ffs(db_bits); + qp = &nt->qp_vec[qp_num]; + + tasklet_schedule(&qp->rxc_db_work); + + db_bits &= ~BIT_ULL(qp_num); + } +} + +static const struct ntb_ctx_ops ntb_transport_ops = { + .link_event = ntb_transport_event_callback, + .db_event = ntb_transport_doorbell_callback, +}; + +static struct ntb_client ntb_transport_client = { + .ops = { + .probe = ntb_transport_probe, + .remove = ntb_transport_free, + }, +}; + +static int __init ntb_transport_init(void) +{ + int rc; + + if (debugfs_initialized()) + nt_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); + + rc = bus_register(&ntb_transport_bus); + if (rc) + goto err_bus; + + rc = ntb_register_client(&ntb_transport_client); + if (rc) + goto err_client; + + return 0; + +err_client: + bus_unregister(&ntb_transport_bus); +err_bus: + debugfs_remove_recursive(nt_debugfs_dir); + return rc; +} +module_init(ntb_transport_init); + +static void __exit ntb_transport_exit(void) +{ + debugfs_remove_recursive(nt_debugfs_dir); + + ntb_unregister_client(&ntb_transport_client); + bus_unregister(&ntb_transport_bus); +} +module_exit(ntb_transport_exit); diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h index f78b64cc09d5..2862861366a5 100644 --- a/include/linux/ntb_transport.h +++ b/include/linux/ntb_transport.h @@ -5,6 +5,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -13,6 +14,7 @@ * BSD LICENSE * * Copyright(c) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2015 EMC Corporation. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,7 +42,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Intel PCIe NTB Linux driver + * PCIe NTB Transport Linux driver * * Contact Information: * Jon Mason @@ -48,21 +50,16 @@ struct ntb_transport_qp; -struct ntb_client { +struct ntb_transport_client { struct device_driver driver; - int (*probe)(struct pci_dev *pdev); - void (*remove)(struct pci_dev *pdev); + int (*probe)(struct device *client_dev); + void (*remove)(struct device *client_dev); }; -enum { - NTB_LINK_DOWN = 0, - NTB_LINK_UP, -}; - -int ntb_transport_register_client(struct ntb_client *drvr); -void ntb_transport_unregister_client(struct ntb_client *drvr); -int ntb_register_client_dev(char *device_name); -void ntb_unregister_client_dev(char *device_name); +int ntb_transport_register_client(struct ntb_transport_client *drvr); +void ntb_transport_unregister_client(struct ntb_transport_client *drvr); +int ntb_transport_register_client_dev(char *device_name); +void ntb_transport_unregister_client_dev(char *device_name); struct ntb_queue_handlers { void (*rx_handler)(struct ntb_transport_qp *qp, void *qp_data, @@ -75,7 +72,7 @@ struct ntb_queue_handlers { unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp); unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp); struct ntb_transport_qp * -ntb_transport_create_queue(void *data, struct pci_dev *pdev, +ntb_transport_create_queue(void *data, struct device *client_dev, const struct ntb_queue_handlers *handlers); void ntb_transport_free_queue(struct ntb_transport_qp *qp); int ntb_transport_rx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, -- cgit v1.2.3 From 0294112ee3135fbd15eaa70015af8283642dd970 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 4 Jul 2015 03:09:03 +0200 Subject: ACPI / PNP: Reserve ACPI resources at the fs_initcall_sync stage This effectively reverts the following three commits: 7bc10388ccdd ACPI / resources: free memory on error in add_region_before() 0f1b414d1907 ACPI / PNP: Avoid conflicting resource reservations b9a5e5e18fbf ACPI / init: Fix the ordering of acpi_reserve_resources() (commit b9a5e5e18fbf introduced regressions some of which, but not all, were addressed by commit 0f1b414d1907 and commit 7bc10388ccdd was a fixup on top of the latter) and causes ACPI fixed hardware resources to be reserved at the fs_initcall_sync stage of system initialization. The story is as follows. First, a boot regression was reported due to an apparent resource reservation ordering change after a commit that shouldn't lead to such changes. Investigation led to the conclusion that the problem happened because acpi_reserve_resources() was executed at the device_initcall() stage of system initialization which wasn't strictly ordered with respect to driver initialization (and with respect to the initialization of the pcieport driver in particular), so a random change causing the device initcalls to be run in a different order might break things. The response to that was to attempt to run acpi_reserve_resources() as soon as we knew that ACPI would be in use (commit b9a5e5e18fbf). However, that turned out to be too early, because it caused resource reservations made by the PNP system driver to fail on at least one system and that failure was addressed by commit 0f1b414d1907. That fix still turned out to be insufficient, though, because calling acpi_reserve_resources() before the fs_initcall stage of system initialization caused a boot regression to happen on the eCAFE EC-800-H20G/S netbook. That meant that we only could call acpi_reserve_resources() at the fs_initcall initialization stage or later, but then we might just as well call it after the PNP initalization in which case commit 0f1b414d1907 wouldn't be necessary any more. For this reason, the changes made by commit 0f1b414d1907 are reverted (along with a memory leak fixup on top of that commit), the changes made by commit b9a5e5e18fbf that went too far are reverted too and acpi_reserve_resources() is changed into fs_initcall_sync, which will cause it to be executed after the PNP subsystem initialization (which is an fs_initcall) and before device initcalls (including the pcieport driver initialization) which should avoid the initial issue. Link: https://bugzilla.kernel.org/show_bug.cgi?id=100581 Link: http://marc.info/?t=143092384600002&r=1&w=2 Link: https://bugzilla.kernel.org/show_bug.cgi?id=99831 Link: http://marc.info/?t=143389402600001&r=1&w=2 Fixes: b9a5e5e18fbf "ACPI / init: Fix the ordering of acpi_reserve_resources()" Reported-by: Roland Dreier Cc: All applicable Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 12 +++- drivers/acpi/resource.c | 162 ------------------------------------------------ drivers/pnp/system.c | 35 +++-------- include/linux/acpi.h | 10 --- 4 files changed, 18 insertions(+), 201 deletions(-) (limited to 'include') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c262e4acd68d..3b8963f21b36 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -175,10 +175,14 @@ static void __init acpi_request_region (struct acpi_generic_address *gas, if (!addr || !length) return; - acpi_reserve_region(addr, length, gas->space_id, 0, desc); + /* Resources are never freed */ + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + request_region(addr, length, desc); + else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + request_mem_region(addr, length, desc); } -static void __init acpi_reserve_resources(void) +static int __init acpi_reserve_resources(void) { acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, "ACPI PM1a_EVT_BLK"); @@ -207,7 +211,10 @@ static void __init acpi_reserve_resources(void) if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) acpi_request_region(&acpi_gbl_FADT.xgpe1_block, acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); + + return 0; } +fs_initcall_sync(acpi_reserve_resources); void acpi_os_printf(const char *fmt, ...) { @@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(void) acpi_status __init acpi_os_initialize1(void) { - acpi_reserve_resources(); kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 10561ce16ed1..8244f013f210 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #ifdef CONFIG_X86 @@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares, return (type & types) ? 0 : 1; } EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); - -struct reserved_region { - struct list_head node; - u64 start; - u64 end; -}; - -static LIST_HEAD(reserved_io_regions); -static LIST_HEAD(reserved_mem_regions); - -static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags, - char *desc) -{ - unsigned int length = end - start + 1; - struct resource *res; - - res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ? - request_region(start, length, desc) : - request_mem_region(start, length, desc); - if (!res) - return -EIO; - - res->flags &= ~flags; - return 0; -} - -static int add_region_before(u64 start, u64 end, u8 space_id, - unsigned long flags, char *desc, - struct list_head *head) -{ - struct reserved_region *reg; - int error; - - reg = kmalloc(sizeof(*reg), GFP_KERNEL); - if (!reg) - return -ENOMEM; - - error = request_range(start, end, space_id, flags, desc); - if (error) { - kfree(reg); - return error; - } - - reg->start = start; - reg->end = end; - list_add_tail(®->node, head); - return 0; -} - -/** - * acpi_reserve_region - Reserve an I/O or memory region as a system resource. - * @start: Starting address of the region. - * @length: Length of the region. - * @space_id: Identifier of address space to reserve the region from. - * @flags: Resource flags to clear for the region after requesting it. - * @desc: Region description (for messages). - * - * Reserve an I/O or memory region as a system resource to prevent others from - * using it. If the new region overlaps with one of the regions (in the given - * address space) already reserved by this routine, only the non-overlapping - * parts of it will be reserved. - * - * Returned is either 0 (success) or a negative error code indicating a resource - * reservation problem. It is the code of the first encountered error, but the - * routine doesn't abort until it has attempted to request all of the parts of - * the new region that don't overlap with other regions reserved previously. - * - * The resources requested by this routine are never released. - */ -int acpi_reserve_region(u64 start, unsigned int length, u8 space_id, - unsigned long flags, char *desc) -{ - struct list_head *regions; - struct reserved_region *reg; - u64 end = start + length - 1; - int ret = 0, error = 0; - - if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) - regions = &reserved_io_regions; - else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - regions = &reserved_mem_regions; - else - return -EINVAL; - - if (list_empty(regions)) - return add_region_before(start, end, space_id, flags, desc, regions); - - list_for_each_entry(reg, regions, node) - if (reg->start == end + 1) { - /* The new region can be prepended to this one. */ - ret = request_range(start, end, space_id, flags, desc); - if (!ret) - reg->start = start; - - return ret; - } else if (reg->start > end) { - /* No overlap. Add the new region here and get out. */ - return add_region_before(start, end, space_id, flags, - desc, ®->node); - } else if (reg->end == start - 1) { - goto combine; - } else if (reg->end >= start) { - goto overlap; - } - - /* The new region goes after the last existing one. */ - return add_region_before(start, end, space_id, flags, desc, regions); - - overlap: - /* - * The new region overlaps an existing one. - * - * The head part of the new region immediately preceding the existing - * overlapping one can be combined with it right away. - */ - if (reg->start > start) { - error = request_range(start, reg->start - 1, space_id, flags, desc); - if (error) - ret = error; - else - reg->start = start; - } - - combine: - /* - * The new region is adjacent to an existing one. If it extends beyond - * that region all the way to the next one, it is possible to combine - * all three of them. - */ - while (reg->end < end) { - struct reserved_region *next = NULL; - u64 a = reg->end + 1, b = end; - - if (!list_is_last(®->node, regions)) { - next = list_next_entry(reg, node); - if (next->start <= end) - b = next->start - 1; - } - error = request_range(a, b, space_id, flags, desc); - if (!error) { - if (next && next->start == b + 1) { - reg->end = next->end; - list_del(&next->node); - kfree(next); - } else { - reg->end = end; - break; - } - } else if (next) { - if (!ret) - ret = error; - - reg = next; - } else { - break; - } - } - - return ret ? ret : error; -} -EXPORT_SYMBOL_GPL(acpi_reserve_region); diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index 515f33882ab8..49c1720df59a 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -7,7 +7,6 @@ * Bjorn Helgaas */ -#include #include #include #include @@ -23,41 +22,25 @@ static const struct pnp_device_id pnp_dev_table[] = { {"", 0} }; -#ifdef CONFIG_ACPI -static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc) -{ - u8 space_id = io ? ACPI_ADR_SPACE_SYSTEM_IO : ACPI_ADR_SPACE_SYSTEM_MEMORY; - return !acpi_reserve_region(start, length, space_id, IORESOURCE_BUSY, desc); -} -#else -static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc) -{ - struct resource *res; - - res = io ? request_region(start, length, desc) : - request_mem_region(start, length, desc); - if (res) { - res->flags &= ~IORESOURCE_BUSY; - return true; - } - return false; -} -#endif - static void reserve_range(struct pnp_dev *dev, struct resource *r, int port) { char *regionid; const char *pnpid = dev_name(&dev->dev); resource_size_t start = r->start, end = r->end; - bool reserved; + struct resource *res; regionid = kmalloc(16, GFP_KERNEL); if (!regionid) return; snprintf(regionid, 16, "pnp %s", pnpid); - reserved = __reserve_range(start, end - start + 1, !!port, regionid); - if (!reserved) + if (port) + res = request_region(start, end - start + 1, regionid); + else + res = request_mem_region(start, end - start + 1, regionid); + if (res) + res->flags &= ~IORESOURCE_BUSY; + else kfree(regionid); /* @@ -66,7 +49,7 @@ static void reserve_range(struct pnp_dev *dev, struct resource *r, int port) * have double reservations. */ dev_info(&dev->dev, "%pR %s reserved\n", r, - reserved ? "has been" : "could not be"); + res ? "has been" : "could not be"); } static void reserve_resources_of_dev(struct pnp_dev *dev) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c471dfc93b71..fedfd1bea3bf 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -309,9 +309,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n, int acpi_resources_are_enforced(void); -int acpi_reserve_region(u64 start, unsigned int length, u8 space_id, - unsigned long flags, char *desc); - #ifdef CONFIG_HIBERNATION void __init acpi_no_s4_hw_signature(void); #endif @@ -507,13 +504,6 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n, return 0; } -static inline int acpi_reserve_region(u64 start, unsigned int length, - u8 space_id, unsigned long flags, - char *desc) -{ - return -ENXIO; -} - struct acpi_table_header; static inline int acpi_table_parse(char *id, int (*handler)(struct acpi_table_header *)) -- cgit v1.2.3 From 26095a01d359827eeccec5459c28ddd976183179 Mon Sep 17 00:00:00 2001 From: "Suthikulpanit, Suravee" Date: Tue, 7 Jul 2015 01:55:20 +0200 Subject: ACPI / scan: Add support for ACPI _CLS device matching Device drivers typically use ACPI _HIDs/_CIDs listed in struct device_driver acpi_match_table to match devices. However, for generic drivers, we do not want to list _HID for all supported devices. Also, certain classes of devices do not have _CID (e.g. SATA, USB). Instead, we can leverage ACPI _CLS, which specifies PCI-defined class code (i.e. base-class, subclass and programming interface). This patch adds support for matching ACPI devices using the _CLS method. To support loadable module, current design uses _HID or _CID to match device's modalias. With the new way of matching with _CLS this would requires modification to the current ACPI modalias key to include _CLS. This patch appends PCI-defined class-code to the existing ACPI modalias as following. acpi::::..::: E.g: # cat /sys/devices/platform/AMDI0600:00/modalias acpi:AMDI0600:010601: where bb is th base-class code, ss is te sub-class code, and pp is the programming interface code Since there would not be _HID/_CID in the ACPI matching table of the driver, this patch adds a field to acpi_device_id to specify the matching _CLS. static const struct acpi_device_id ahci_acpi_match[] = { { ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) }, {}, }; In this case, the corresponded entry in modules.alias file would be: alias acpi*:010601:* ahci_platform Acked-by: Mika Westerberg Reviewed-by: Hanjun Guo Signed-off-by: Suravee Suthikulpanit Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 32 ++++++++++++++++++++++++++++++-- include/linux/acpi.h | 14 ++++++++++++++ include/linux/mod_devicetable.h | 2 ++ scripts/mod/devicetable-offsets.c | 2 ++ scripts/mod/file2alias.c | 32 ++++++++++++++++++++++++++++++-- 5 files changed, 78 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2649a068671d..ec256352f423 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1019,6 +1019,29 @@ static bool acpi_of_match_device(struct acpi_device *adev, return false; } +static bool __acpi_match_device_cls(const struct acpi_device_id *id, + struct acpi_hardware_id *hwid) +{ + int i, msk, byte_shift; + char buf[3]; + + if (!id->cls) + return false; + + /* Apply class-code bitmask, before checking each class-code byte */ + for (i = 1; i <= 3; i++) { + byte_shift = 8 * (3 - i); + msk = (id->cls_msk >> byte_shift) & 0xFF; + if (!msk) + continue; + + sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); + if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) + return false; + } + return true; +} + static const struct acpi_device_id *__acpi_match_device( struct acpi_device *device, const struct acpi_device_id *ids, @@ -1036,9 +1059,12 @@ static const struct acpi_device_id *__acpi_match_device( list_for_each_entry(hwid, &device->pnp.ids, list) { /* First, check the ACPI/PNP IDs provided by the caller. */ - for (id = ids; id->id[0]; id++) - if (!strcmp((char *) id->id, hwid->id)) + for (id = ids; id->id[0] || id->cls; id++) { + if (id->id[0] && !strcmp((char *) id->id, hwid->id)) return id; + else if (id->cls && __acpi_match_device_cls(id, hwid)) + return id; + } /* * Next, check ACPI_DT_NAMESPACE_HID and try to match the @@ -2101,6 +2127,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, if (info->valid & ACPI_VALID_UID) pnp->unique_id = kstrdup(info->unique_id.string, GFP_KERNEL); + if (info->valid & ACPI_VALID_CLS) + acpi_add_id(pnp, info->class_code.string); kfree(info); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c471dfc93b71..bdfdb9f65c23 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -58,6 +58,19 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) acpi_fwnode_handle(adev) : NULL) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) +/** + * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with + * the PCI-defined class-code information + * + * @_cls : the class, subclass, prog-if triple for this device + * @_msk : the class mask for this device + * + * This macro is used to create a struct acpi_device_id that matches a + * specific PCI class. The .id and .driver_data fields will be left + * initialized with the default value. + */ +#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (_cls), .cls_msk = (_msk), + static inline bool has_acpi_companion(struct device *dev) { return is_acpi_node(dev->fwnode); @@ -446,6 +459,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *); #define ACPI_COMPANION(dev) (NULL) #define ACPI_COMPANION_SET(dev, adev) do { } while (0) #define ACPI_HANDLE(dev) (NULL) +#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (0), .cls_msk = (0), struct fwnode_handle; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 8183d6640ca7..34f25b7bf642 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -189,6 +189,8 @@ struct css_device_id { struct acpi_device_id { __u8 id[ACPI_ID_LEN]; kernel_ulong_t driver_data; + __u32 cls; + __u32 cls_msk; }; #define PNP_ID_LEN 8 diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index eff7de1fc82e..e70fcd12eeeb 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -63,6 +63,8 @@ int main(void) DEVID(acpi_device_id); DEVID_FIELD(acpi_device_id, id); + DEVID_FIELD(acpi_device_id, cls); + DEVID_FIELD(acpi_device_id, cls_msk); DEVID(pnp_device_id); DEVID_FIELD(pnp_device_id, id); diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 84c86f3cd6cd..5f2088209132 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -523,12 +523,40 @@ static int do_serio_entry(const char *filename, } ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); -/* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */ +/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or + * "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if) + * + * NOTE: Each driver should use one of the following : _HID, _CIDs + * or _CLS. Also, bb, ss, and pp can be substituted with ?? + * as don't care byte. + */ static int do_acpi_entry(const char *filename, void *symval, char *alias) { DEF_FIELD_ADDR(symval, acpi_device_id, id); - sprintf(alias, "acpi*:%s:*", *id); + DEF_FIELD_ADDR(symval, acpi_device_id, cls); + DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk); + + if (id && strlen((const char *)*id)) + sprintf(alias, "acpi*:%s:*", *id); + else if (cls) { + int i, byte_shift, cnt = 0; + unsigned int msk; + + sprintf(&alias[cnt], "acpi*:"); + cnt = 6; + for (i = 1; i <= 3; i++) { + byte_shift = 8 * (3-i); + msk = (*cls_msk >> byte_shift) & 0xFF; + if (msk) + sprintf(&alias[cnt], "%02x", + (*cls >> byte_shift) & 0xFF); + else + sprintf(&alias[cnt], "??"); + cnt += 2; + } + sprintf(&alias[cnt], ":*"); + } return 1; } ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); -- cgit v1.2.3 From f32dd117051185da6e923b35491a44d7debeeea5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jul 2015 16:29:38 +0200 Subject: tick/broadcast: Make idle check independent from mode and config Currently the broadcast busy check, which prevents the idle code from going into deep idle, works only in one shot mode. If NOHZ and HIGHRES are off (config or command line) there is no sanity check at all, so under certain conditions cpus are allowed to go into deep idle, where the local timer stops, and are not woken up again because there is no broadcast timer installed or a hrtimer based broadcast device is not evaluated. Move tick_broadcast_oneshot_control() into the common code and provide proper subfunctions for the various config combinations. The common check in tick_broadcast_oneshot_control() is for the C3STOP misfeature flag of the local clock event device. If its not set, idle can proceed. If set, further checks are necessary. Provide checks for the trivial cases: - If broadcast is disabled in the config, then return busy - If oneshot mode (NOHZ/HIGHES) is disabled in the config, return busy if the broadcast device is hrtimer based. - If oneshot mode is enabled in the config call the original tick_broadcast_oneshot_control() function. That function needs extra checks which will be implemented in seperate patches. [ Split out from a larger combo patch ] Reported-and-tested-by: Sudeep Holla Signed-off-by: Thomas Gleixner Cc: Suzuki Poulose Cc: Lorenzo Pieralisi Cc: Catalin Marinas Cc: Rafael J. Wysocki Cc: Peter Zijlstra Cc: Preeti U Murthy Cc: Ingo Molnar Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1507070929360.3916@nanos --- include/linux/tick.h | 4 ---- kernel/time/tick-broadcast.c | 26 +++++++++++--------------- kernel/time/tick-common.c | 21 +++++++++++++++++++++ kernel/time/tick-sched.h | 10 ++++++++++ 4 files changed, 42 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/linux/tick.h b/include/linux/tick.h index 3741ba1a652c..6916dcb61857 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -67,11 +67,7 @@ extern void tick_broadcast_control(enum tick_broadcast_mode mode); static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { } #endif /* BROADCAST */ -#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state); -#else -static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state) { return 0; } -#endif static inline void tick_broadcast_enable(void) { diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 9877d0b0aefc..ef77b16ad5df 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -685,18 +685,7 @@ static void broadcast_shutdown_local(struct clock_event_device *bc, clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN); } -/** - * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode - * @state: The target state (enter/exit) - * - * The system enters/leaves a state, where affected devices might stop - * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups. - * - * Called with interrupts disabled, so clockevents_lock is not - * required here because the local clock event device cannot go away - * under us. - */ -int tick_broadcast_oneshot_control(enum tick_broadcast_state state) +int __tick_broadcast_oneshot_control(enum tick_broadcast_state state) { struct clock_event_device *bc, *dev; struct tick_device *td; @@ -717,9 +706,6 @@ int tick_broadcast_oneshot_control(enum tick_broadcast_state state) td = this_cpu_ptr(&tick_cpu_device); dev = td->evtdev; - if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) - return 0; - raw_spin_lock(&tick_broadcast_lock); bc = tick_broadcast_device.evtdev; cpu = smp_processor_id(); @@ -961,6 +947,16 @@ bool tick_broadcast_oneshot_available(void) return bc ? bc->features & CLOCK_EVT_FEAT_ONESHOT : false; } +#else +int __tick_broadcast_oneshot_control(enum tick_broadcast_state state) +{ + struct clock_event_device *bc = tick_broadcast_device.evtdev; + + if (!bc || (bc->features & CLOCK_EVT_FEAT_HRTIMER)) + return -EBUSY; + + return 0; +} #endif void __init tick_broadcast_init(void) diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index 76446cb5dfe1..55e13efff1ab 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -343,6 +343,27 @@ out_bc: tick_install_broadcast_device(newdev); } +/** + * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode + * @state: The target state (enter/exit) + * + * The system enters/leaves a state, where affected devices might stop + * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups. + * + * Called with interrupts disabled, so clockevents_lock is not + * required here because the local clock event device cannot go away + * under us. + */ +int tick_broadcast_oneshot_control(enum tick_broadcast_state state) +{ + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); + + if (!(td->evtdev->features & CLOCK_EVT_FEAT_C3STOP)) + return 0; + + return __tick_broadcast_oneshot_control(state); +} + #ifdef CONFIG_HOTPLUG_CPU /* * Transfer the do_timer job away from a dying cpu. diff --git a/kernel/time/tick-sched.h b/kernel/time/tick-sched.h index 42fdf4958bcc..a4a8d4e9baa1 100644 --- a/kernel/time/tick-sched.h +++ b/kernel/time/tick-sched.h @@ -71,4 +71,14 @@ extern void tick_cancel_sched_timer(int cpu); static inline void tick_cancel_sched_timer(int cpu) { } #endif +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST +extern int __tick_broadcast_oneshot_control(enum tick_broadcast_state state); +#else +static inline int +__tick_broadcast_oneshot_control(enum tick_broadcast_state state) +{ + return -EBUSY; +} +#endif + #endif -- cgit v1.2.3 From 37b64a42067a04a22468c4e52c12af00d72e462b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jul 2015 21:56:34 +0200 Subject: tick/broadcast: Unbreak CONFIG_GENERIC_CLOCKEVENTS=n build Making tick_broadcast_oneshot_control() independent from CONFIG_GENERIC_CLOCKEVENTS_BROADCAST broke the build for CONFIG_GENERIC_CLOCKEVENTS=n because the function is not defined there. Provide a proper stub inline. Fixes: f32dd1170511 'tick/broadcast: Make idle check independent from mode and config' Reported-by: kbuild test robot Signed-off-by: Thomas Gleixner --- include/linux/tick.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/linux/tick.h b/include/linux/tick.h index 6916dcb61857..edbfc9a5293e 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -67,7 +67,14 @@ extern void tick_broadcast_control(enum tick_broadcast_mode mode); static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { } #endif /* BROADCAST */ +#ifdef CONFIG_GENERIC_CLOCKEVENTS extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state); +#else +static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state) +{ + return 0; +} +#endif static inline void tick_broadcast_enable(void) { -- cgit v1.2.3 From a899418167264c7bac574b1a0f1b2c26c5b0995a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 5 Jul 2015 17:12:30 +0000 Subject: hotplug: Prevent alloc/free of irq descriptors during cpu up/down When a cpu goes up some architectures (e.g. x86) have to walk the irq space to set up the vector space for the cpu. While this needs extra protection at the architecture level we can avoid a few race conditions by preventing the concurrent allocation/free of irq descriptors and the associated data. When a cpu goes down it moves the interrupts which are targeted to this cpu away by reassigning the affinities. While this happens interrupts can be allocated and freed, which opens a can of race conditions in the code which reassignes the affinities because interrupt descriptors might be freed underneath. Example: CPU1 CPU2 cpu_up/down irq_desc = irq_to_desc(irq); remove_from_radix_tree(desc); raw_spin_lock(&desc->lock); free(desc); We could protect the irq descriptors with RCU, but that would require a full tree change of all accesses to interrupt descriptors. But fortunately these kind of race conditions are rather limited to a few things like cpu hotplug. The normal setup/teardown is very well serialized. So the simpler and obvious solution is: Prevent allocation and freeing of interrupt descriptors accross cpu hotplug. Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Cc: xiao jin Cc: Joerg Roedel Cc: Borislav Petkov Cc: Yanmin Zhang Link: http://lkml.kernel.org/r/20150705171102.063519515@linutronix.de --- include/linux/irqdesc.h | 7 ++++++- kernel/cpu.c | 22 +++++++++++++++++++++- kernel/irq/internals.h | 4 ---- 3 files changed, 27 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 624a668e61f1..fcea4e48e21f 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -87,7 +87,12 @@ struct irq_desc { const char *name; } ____cacheline_internodealigned_in_smp; -#ifndef CONFIG_SPARSE_IRQ +#ifdef CONFIG_SPARSE_IRQ +extern void irq_lock_sparse(void); +extern void irq_unlock_sparse(void); +#else +static inline void irq_lock_sparse(void) { } +static inline void irq_unlock_sparse(void) { } extern struct irq_desc irq_desc[NR_IRQS]; #endif diff --git a/kernel/cpu.c b/kernel/cpu.c index 9c9c9fab16cc..6a374544d495 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "smpboot.h" @@ -392,13 +393,19 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) smpboot_park_threads(cpu); /* - * So now all preempt/rcu users must observe !cpu_active(). + * Prevent irq alloc/free while the dying cpu reorganizes the + * interrupt affinities. */ + irq_lock_sparse(); + /* + * So now all preempt/rcu users must observe !cpu_active(). + */ err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu)); if (err) { /* CPU didn't die: tell everyone. Can't complain. */ cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu); + irq_unlock_sparse(); goto out_release; } BUG_ON(cpu_online(cpu)); @@ -415,6 +422,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) smp_mb(); /* Read from cpu_dead_idle before __cpu_die(). */ per_cpu(cpu_dead_idle, cpu) = false; + /* Interrupts are moved away from the dying cpu, reenable alloc/free */ + irq_unlock_sparse(); + hotplug_cpu__broadcast_tick_pull(cpu); /* This actually kills the CPU. */ __cpu_die(cpu); @@ -517,8 +527,18 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen) goto out_notify; } + /* + * Some architectures have to walk the irq descriptors to + * setup the vector space for the cpu which comes online. + * Prevent irq alloc/free across the bringup. + */ + irq_lock_sparse(); + /* Arch-specific enabling code. */ ret = __cpu_up(cpu, idle); + + irq_unlock_sparse(); + if (ret != 0) goto out_notify; BUG_ON(!cpu_online(cpu)); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 4834ee828c41..61008b8433ab 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -76,12 +76,8 @@ extern void unmask_threaded_irq(struct irq_desc *desc); #ifdef CONFIG_SPARSE_IRQ static inline void irq_mark_irq(unsigned int irq) { } -extern void irq_lock_sparse(void); -extern void irq_unlock_sparse(void); #else extern void irq_mark_irq(unsigned int irq); -static inline void irq_lock_sparse(void) { } -static inline void irq_unlock_sparse(void) { } #endif extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); -- cgit v1.2.3 From 974d7af5fcc295dcf8315255142b2fe44fd74b0c Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Tue, 7 Jul 2015 13:56:57 -0400 Subject: ipv4: add support for linkdown sysctl to netconf This kernel patch exports the value of the new ignore_routes_with_linkdown via netconf. v2: changes to notify userspace via netlink when sysctl values change and proposed for 'net' since this could be considered a bugfix Signed-off-by: Andy Gospodarek Suggested-by: Nicolas Dichtel Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/uapi/linux/netconf.h | 1 + net/ipv4/devinet.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/netconf.h b/include/uapi/linux/netconf.h index 669a1f0b1d97..23cbd34e4ac7 100644 --- a/include/uapi/linux/netconf.h +++ b/include/uapi/linux/netconf.h @@ -15,6 +15,7 @@ enum { NETCONFA_RP_FILTER, NETCONFA_MC_FORWARDING, NETCONFA_PROXY_NEIGH, + NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, __NETCONFA_MAX }; #define NETCONFA_MAX (__NETCONFA_MAX - 1) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7498716e8f54..e813196c91c7 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1740,6 +1740,8 @@ static int inet_netconf_msgsize_devconf(int type) size += nla_total_size(4); if (type == -1 || type == NETCONFA_PROXY_NEIGH) size += nla_total_size(4); + if (type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) + size += nla_total_size(4); return size; } @@ -1780,6 +1782,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, nla_put_s32(skb, NETCONFA_PROXY_NEIGH, IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0) goto nla_put_failure; + if ((type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && + nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, + IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0) + goto nla_put_failure; nlmsg_end(skb, nlh); return 0; @@ -1819,6 +1825,7 @@ static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = { [NETCONFA_FORWARDING] = { .len = sizeof(int) }, [NETCONFA_RP_FILTER] = { .len = sizeof(int) }, [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, + [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, }; static int inet_netconf_get_devconf(struct sk_buff *in_skb, @@ -2048,6 +2055,12 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write, inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, ifindex, cnf); } + if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 && + new_value != old_value) { + ifindex = devinet_conf_ifindex(net, cnf); + inet_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, + ifindex, cnf); + } } return ret; -- cgit v1.2.3 From 1f6823faa8c563431a94e614d2b63ce16bb6f658 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 9 Jul 2015 10:51:46 +0200 Subject: time: Get rid of do_posix_clock_monotonic_gettime All users gone. Remove it before we get another one. Signed-off-by: Thomas Gleixner --- include/linux/timekeeping.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 3aa72e648650..6e191e4e6ab6 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -145,7 +145,6 @@ static inline void getboottime(struct timespec *ts) } #endif -#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts) #define ktime_get_real_ts64(ts) getnstimeofday64(ts) /* -- cgit v1.2.3 From 757856d2b9568a701df9ea6a4be68effbb9d6f44 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Thu, 25 Jun 2015 17:47:45 +0300 Subject: libceph: enable ceph in a non-default network namespace Grab a reference on a network namespace of the 'rbd map' (in case of rbd) or 'mount' (in case of ceph) process and use that to open sockets instead of always using init_net and bailing if network namespace is anything but init_net. Be careful to not share struct ceph_client instances between different namespaces and don't add any code in the !CONFIG_NET_NS case. This is based on a patch from Hong Zhiguo . Signed-off-by: Ilya Dryomov Reviewed-by: Sage Weil --- include/linux/ceph/messenger.h | 3 +++ net/ceph/ceph_common.c | 16 ++++++++++------ net/ceph/messenger.c | 10 +++++++++- 3 files changed, 22 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index e15499422fdc..37753278987a 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ struct ceph_messenger { struct ceph_entity_addr my_enc_addr; atomic_t stopping; + possible_net_t net; bool nocrc; bool tcp_nodelay; @@ -267,6 +269,7 @@ extern void ceph_messenger_init(struct ceph_messenger *msgr, u64 required_features, bool nocrc, bool tcp_nodelay); +extern void ceph_messenger_fini(struct ceph_messenger *msgr); extern void ceph_con_init(struct ceph_connection *con, void *private, const struct ceph_connection_operations *ops, diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index cb7db320dd27..f30329f72641 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,8 +17,6 @@ #include #include #include -#include -#include #include @@ -131,6 +130,13 @@ int ceph_compare_options(struct ceph_options *new_opt, int i; int ret; + /* + * Don't bother comparing options if network namespaces don't + * match. + */ + if (!net_eq(current->nsproxy->net_ns, read_pnet(&client->msgr.net))) + return -1; + ret = memcmp(opt1, opt2, ofs); if (ret) return ret; @@ -335,9 +341,6 @@ ceph_parse_options(char *options, const char *dev_name, int err = -ENOMEM; substring_t argstr[MAX_OPT_ARGS]; - if (current->nsproxy->net_ns != &init_net) - return ERR_PTR(-EINVAL); - opt = kzalloc(sizeof(*opt), GFP_KERNEL); if (!opt) return ERR_PTR(-ENOMEM); @@ -608,6 +611,7 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private, fail_monc: ceph_monc_stop(&client->monc); fail: + ceph_messenger_fini(&client->msgr); kfree(client); return ERR_PTR(err); } @@ -621,8 +625,8 @@ void ceph_destroy_client(struct ceph_client *client) /* unmount */ ceph_osdc_stop(&client->osdc); - ceph_monc_stop(&client->monc); + ceph_messenger_fini(&client->msgr); ceph_debugfs_client_cleanup(client); diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 1679f47280e2..5c1f98ea6741 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -479,7 +480,7 @@ static int ceph_tcp_connect(struct ceph_connection *con) int ret; BUG_ON(con->sock); - ret = sock_create_kern(&init_net, con->peer_addr.in_addr.ss_family, + ret = sock_create_kern(read_pnet(&con->msgr->net), paddr->ss_family, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) return ret; @@ -2944,11 +2945,18 @@ void ceph_messenger_init(struct ceph_messenger *msgr, msgr->tcp_nodelay = tcp_nodelay; atomic_set(&msgr->stopping, 0); + write_pnet(&msgr->net, get_net(current->nsproxy->net_ns)); dout("%s %p\n", __func__, msgr); } EXPORT_SYMBOL(ceph_messenger_init); +void ceph_messenger_fini(struct ceph_messenger *msgr) +{ + put_net(read_pnet(&msgr->net)); +} +EXPORT_SYMBOL(ceph_messenger_fini); + static void clear_standby(struct ceph_connection *con) { /* come back from STANDBY? */ -- cgit v1.2.3 From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001 From: Enrico Mioso Date: Wed, 8 Jul 2015 13:05:57 +0200 Subject: cdc_ncm: Add support for moving NDP to end of NCM frame NCM specs are not actually mandating a specific position in the frame for the NDP (Network Datagram Pointer). However, some Huawei devices will ignore our aggregates if it is not placed after the datagrams it points to. Add support for doing just this, in a per-device configurable way. While at it, update NCM subdrivers, disabling this functionality in all of them, except in huawei_cdc_ncm where it is enabled instead. We aren't making any distinction between different Huawei NCM devices, based on what the vendor driver does. Standard NCM devices are left unaffected: if they are compliant, they should be always usable, still stay on the safe side. This change has been tested and working with a Huawei E3131 device (which works regardless of NDP position), a Huawei E3531 (also working both ways) and an E3372 (which mandates NDP to be after indexed datagrams). V1->V2: - corrected wrong NDP acronym definition - fixed possible NULL pointer dereference - patch cleanup V2->V3: - Properly account for the NDP size when writing new packets to SKB Signed-off-by: Enrico Mioso Signed-off-by: David S. Miller --- drivers/net/usb/cdc_mbim.c | 2 +- drivers/net/usb/cdc_ncm.c | 61 ++++++++++++++++++++++++++++++++++++---- drivers/net/usb/huawei_cdc_ncm.c | 7 +++-- include/linux/usb/cdc_ncm.h | 7 ++++- 4 files changed, 67 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index e4b7a47a825c..efc18e05af0a 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) goto err; - ret = cdc_ncm_bind_common(dev, intf, data_altsetting); + ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0); if (ret) goto err; diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 8067b8fbb0ee..1991e4a24657 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) ctx->tx_curr_skb = NULL; } + kfree(ctx->delayed_ndp16); + kfree(ctx); } -int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting) +int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) { const struct usb_cdc_union_desc *union_desc = NULL; struct cdc_ncm_ctx *ctx; @@ -855,6 +857,17 @@ advance: /* finish setting up the device specific data */ cdc_ncm_setup(dev); + /* Device-specific flags */ + ctx->drvflags = drvflags; + + /* Allocate the delayed NDP if needed. */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { + ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL); + if (!ctx->delayed_ndp16) + goto error2; + dev_info(&intf->dev, "NDP will be placed at end of frame for this device."); + } + /* override ethtool_ops */ dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; @@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM) return -ENODEV; - /* The NCM data altsetting is fixed */ - ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM); + /* The NCM data altsetting is fixed, so we hard-coded it. + * Additionally, generic NCM devices are assumed to accept arbitrarily + * placed NDP. + */ + ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0); /* * We should get an event when network connection is "connected" or @@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data; size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex); + /* If NDP should be moved to the end of the NCM package, we can't follow the + * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and + * the wNdpIndex field in the header is actually not consistent with reality. It will be later. + */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) + if (ctx->delayed_ndp16->dwSignature == sign) + return ctx->delayed_ndp16; + /* follow the chain of NDPs, looking for a match */ while (ndpoffset) { ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset); @@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ } /* align new NDP */ - cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); + if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) + cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max); /* verify that there is room for the NDP and the datagram (reserve) */ if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size) @@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_ nth16->wNdpIndex = cpu_to_le16(skb->len); /* push a new empty NDP */ - ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); + if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)) + ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size); + else + ndp16 = ctx->delayed_ndp16; + ndp16->dwSignature = sign; ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16)); return ndp16; @@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) struct sk_buff *skb_out; u16 n = 0, index, ndplen; u8 ready2send = 0; + u32 delayed_ndp_size; + + /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated + * accordingly. Otherwise, we should check here. + */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) + delayed_ndp_size = ctx->max_ndp_size; + else + delayed_ndp_size = 0; /* if there is a remaining skb, it gets priority */ if (skb != NULL) { @@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max); /* check if we had enough room left for both NDP and frame */ - if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) { + if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) { if (n == 0) { /* won't fit, MTU problem? */ dev_kfree_skb_any(skb); @@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* variables will be reset at next call */ } + /* If requested, put NDP at end of frame. */ + if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { + nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; + cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); + nth16->wNdpIndex = cpu_to_le16(skb_out->len); + memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); + + /* Zero out delayed NDP - signature checking will naturally fail. */ + ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size); + } + /* If collected data size is less or equal ctx->min_tx_pkt * bytes, we send buffers as it is. If we get more data, it * would be more efficient for USB HS mobile device with DMA diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c index 735f7dadb9a0..2680a65cd5e4 100644 --- a/drivers/net/usb/huawei_cdc_ncm.c +++ b/drivers/net/usb/huawei_cdc_ncm.c @@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_driver *subdriver = ERR_PTR(-ENODEV); int ret = -ENODEV; struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data; + int drvflags = 0; /* altsetting should always be 1 for NCM devices - so we hard-coded - * it here + * it here. Some huawei devices will need the NDP part of the NCM package to + * be at the end of the frame. */ - ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); + drvflags |= CDC_NCM_FLAG_NDP_TO_END; + ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags); if (ret) goto err; diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h index 7c9b484735c5..1f6526c76ee8 100644 --- a/include/linux/usb/cdc_ncm.h +++ b/include/linux/usb/cdc_ncm.h @@ -80,6 +80,9 @@ #define CDC_NCM_TIMER_INTERVAL_MIN 5UL #define CDC_NCM_TIMER_INTERVAL_MAX (U32_MAX / NSEC_PER_USEC) +/* Driver flags */ +#define CDC_NCM_FLAG_NDP_TO_END 0x02 /* NDP is placed at end of frame */ + #define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \ (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE) #define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB) @@ -103,9 +106,11 @@ struct cdc_ncm_ctx { spinlock_t mtx; atomic_t stop; + int drvflags; u32 timer_interval; u32 max_ndp_size; + struct usb_cdc_ncm_ndp16 *delayed_ndp16; u32 tx_timer_pending; u32 tx_curr_frame_num; @@ -133,7 +138,7 @@ struct cdc_ncm_ctx { }; u8 cdc_ncm_select_altsetting(struct usb_interface *intf); -int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); +int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags); void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in); -- cgit v1.2.3 From d3b58c47d330de8c29898fe9746f7530408f8a59 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 26 Jun 2015 11:58:19 +0200 Subject: can: replace timestamp as unique skb attribute Commit 514ac99c64b "can: fix multiple delivery of a single CAN frame for overlapping CAN filters" requires the skb->tstamp to be set to check for identical CAN skbs. Without timestamping to be required by user space applications this timestamp was not generated which lead to commit 36c01245eb8 "can: fix loss of CAN frames in raw_rcv" - which forces the timestamp to be set in all CAN related skbuffs by introducing several __net_timestamp() calls. This forces e.g. out of tree drivers which are not using alloc_can{,fd}_skb() to add __net_timestamp() after skbuff creation to prevent the frame loss fixed in mainline Linux. This patch removes the timestamp dependency and uses an atomic counter to create an unique identifier together with the skbuff pointer. Btw: the new skbcnt element introduced in struct can_skb_priv has to be initialized with zero in out-of-tree drivers which are not using alloc_can{,fd}_skb() too. Signed-off-by: Oliver Hartkopp Cc: linux-stable Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 7 ++----- drivers/net/can/slcan.c | 2 +- drivers/net/can/vcan.c | 3 --- include/linux/can/skb.h | 2 ++ net/can/af_can.c | 12 +++++++----- net/can/bcm.c | 2 ++ net/can/raw.c | 7 ++++--- 7 files changed, 18 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index e9b1810d319f..aede704605c6 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -440,9 +440,6 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx) struct can_frame *cf = (struct can_frame *)skb->data; u8 dlc = cf->can_dlc; - if (!(skb->tstamp.tv64)) - __net_timestamp(skb); - netif_rx(priv->echo_skb[idx]); priv->echo_skb[idx] = NULL; @@ -578,7 +575,6 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) if (unlikely(!skb)) return NULL; - __net_timestamp(skb); skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -589,6 +585,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; *cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame)); memset(*cf, 0, sizeof(struct can_frame)); @@ -607,7 +604,6 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, if (unlikely(!skb)) return NULL; - __net_timestamp(skb); skb->protocol = htons(ETH_P_CANFD); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -618,6 +614,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev, can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); memset(*cfd, 0, sizeof(struct canfd_frame)); diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index f64f5290d6f8..a23a7af8eb9a 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -207,7 +207,6 @@ static void slc_bump(struct slcan *sl) if (!skb) return; - __net_timestamp(skb); skb->dev = sl->dev; skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; @@ -215,6 +214,7 @@ static void slc_bump(struct slcan *sl) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = sl->dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; memcpy(skb_put(skb, sizeof(struct can_frame)), &cf, sizeof(struct can_frame)); diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 0ce868de855d..674f367087c5 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -78,9 +78,6 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev) skb->dev = dev; skb->ip_summed = CHECKSUM_UNNECESSARY; - if (!(skb->tstamp.tv64)) - __net_timestamp(skb); - netif_rx_ni(skb); } diff --git a/include/linux/can/skb.h b/include/linux/can/skb.h index b6a52a4b457a..51bb6532785c 100644 --- a/include/linux/can/skb.h +++ b/include/linux/can/skb.h @@ -27,10 +27,12 @@ /** * struct can_skb_priv - private additional data inside CAN sk_buffs * @ifindex: ifindex of the first interface the CAN frame appeared on + * @skbcnt: atomic counter to have an unique id together with skb pointer * @cf: align to the following CAN frame at skb->data */ struct can_skb_priv { int ifindex; + int skbcnt; struct can_frame cf[0]; }; diff --git a/net/can/af_can.c b/net/can/af_can.c index 7933e62a7318..166d436196c1 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -89,6 +89,8 @@ struct timer_list can_stattimer; /* timer for statistics update */ struct s_stats can_stats; /* packet statistics */ struct s_pstats can_pstats; /* receive list statistics */ +static atomic_t skbcounter = ATOMIC_INIT(0); + /* * af_can socket functions */ @@ -310,12 +312,8 @@ int can_send(struct sk_buff *skb, int loop) return err; } - if (newskb) { - if (!(newskb->tstamp.tv64)) - __net_timestamp(newskb); - + if (newskb) netif_rx_ni(newskb); - } /* update statistics */ can_stats.tx_frames++; @@ -683,6 +681,10 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev) can_stats.rx_frames++; can_stats.rx_frames_delta++; + /* create non-zero unique skb identifier together with *skb */ + while (!(can_skb_prv(skb)->skbcnt)) + can_skb_prv(skb)->skbcnt = atomic_inc_return(&skbcounter); + rcu_read_lock(); /* deliver the packet to sockets listening on all devices */ diff --git a/net/can/bcm.c b/net/can/bcm.c index b523453585be..a1ba6875c2a2 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -261,6 +261,7 @@ static void bcm_can_tx(struct bcm_op *op) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; memcpy(skb_put(skb, CFSIZ), cf, CFSIZ); @@ -1217,6 +1218,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk) } can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; skb->dev = dev; can_skb_set_owner(skb, sk); err = can_send(skb, 1); /* send with loopback */ diff --git a/net/can/raw.c b/net/can/raw.c index 31b9748cbb4e..2e67b1423cd3 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -75,7 +75,7 @@ MODULE_ALIAS("can-proto-1"); */ struct uniqframe { - ktime_t tstamp; + int skbcnt; const struct sk_buff *skb; unsigned int join_rx_count; }; @@ -133,7 +133,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data) /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb == oskb && - ktime_equal(this_cpu_ptr(ro->uniq)->tstamp, oskb->tstamp)) { + this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) { if (ro->join_filters) { this_cpu_inc(ro->uniq->join_rx_count); /* drop frame until all enabled filters matched */ @@ -144,7 +144,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data) } } else { this_cpu_ptr(ro->uniq)->skb = oskb; - this_cpu_ptr(ro->uniq)->tstamp = oskb->tstamp; + this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt; this_cpu_ptr(ro->uniq)->join_rx_count = 1; /* drop first frame to check all enabled filters? */ if (ro->join_filters && ro->count > 1) @@ -749,6 +749,7 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; err = memcpy_from_msg(skb_put(skb, size), msg, size); if (err < 0) -- cgit v1.2.3