xref: /titanic_51/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_hash.c (revision da5ab83fc888325fc812733d8a54bc5eab65c65c)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2014 Joyent, Inc.  All rights reserved.
14  */
15 
16 #include <sys/scsi/adapters/mpt_sas/mptsas_hash.h>
17 #include <sys/sysmacros.h>
18 #include <sys/types.h>
19 #include <sys/kmem.h>
20 #include <sys/list.h>
21 #include <sys/ddi.h>
22 
23 #ifdef lint
24 extern refhash_link_t *obj_to_link(refhash_t *, void *);
25 extern void *link_to_obj(refhash_t *, refhash_link_t *);
26 extern void *obj_to_tag(refhash_t *, void *);
27 #else
28 #define	obj_to_link(_h, _o)	\
29 	((refhash_link_t *)(((char *)(_o)) + (_h)->rh_link_off))
30 #define	link_to_obj(_h, _l)	\
31 	((void *)(((char *)(_l)) - (_h)->rh_link_off))
32 #define	obj_to_tag(_h, _o)	\
33 	((void *)(((char *)(_o)) + (_h)->rh_tag_off))
34 #endif
35 
36 refhash_t *
37 refhash_create(uint_t bucket_count, refhash_hash_f hash,
38     refhash_cmp_f cmp, refhash_dtor_f dtor, size_t obj_size, size_t link_off,
39     size_t tag_off, int km_flags)
40 {
41 	refhash_t *hp;
42 	uint_t i;
43 
44 	hp = kmem_alloc(sizeof (refhash_t), km_flags);
45 	if (hp == NULL)
46 		return (NULL);
47 	hp->rh_buckets = kmem_zalloc(bucket_count * sizeof (list_t), km_flags);
48 	if (hp->rh_buckets == NULL) {
49 		kmem_free(hp, sizeof (refhash_t));
50 		return (NULL);
51 	}
52 	hp->rh_bucket_count = bucket_count;
53 
54 	for (i = 0; i < bucket_count; i++) {
55 		list_create(&hp->rh_buckets[i], sizeof (refhash_link_t),
56 		    offsetof(refhash_link_t, rhl_chain_link));
57 	}
58 	list_create(&hp->rh_objs, sizeof (refhash_link_t),
59 	    offsetof(refhash_link_t, rhl_global_link));
60 
61 	hp->rh_obj_size = obj_size;
62 	hp->rh_link_off = link_off;
63 	hp->rh_tag_off = tag_off;
64 	hp->rh_hash = hash;
65 	hp->rh_cmp = cmp;
66 	hp->rh_dtor = dtor;
67 
68 	return (hp);
69 }
70 
71 void
72 refhash_destroy(refhash_t *hp)
73 {
74 	ASSERT(list_is_empty(&hp->rh_objs));
75 
76 	kmem_free(hp->rh_buckets, hp->rh_bucket_count * sizeof (list_t));
77 	kmem_free(hp, sizeof (refhash_t));
78 }
79 
80 void
81 refhash_insert(refhash_t *hp, void *op)
82 {
83 	uint_t bucket;
84 	refhash_link_t *lp = obj_to_link(hp, op);
85 
86 	bucket = hp->rh_hash(obj_to_tag(hp, op)) % hp->rh_bucket_count;
87 	list_link_init(&lp->rhl_chain_link);
88 	list_link_init(&lp->rhl_global_link);
89 	lp->rhl_flags = 0;
90 	lp->rhl_refcnt = 0;
91 	list_insert_tail(&hp->rh_buckets[bucket], lp);
92 	list_insert_tail(&hp->rh_objs, lp);
93 }
94 
95 static void
96 refhash_delete(refhash_t *hp, void *op)
97 {
98 	refhash_link_t *lp = obj_to_link(hp, op);
99 	uint_t bucket;
100 
101 	bucket = hp->rh_hash(obj_to_tag(hp, op)) % hp->rh_bucket_count;
102 	list_remove(&hp->rh_buckets[bucket], lp);
103 	list_remove(&hp->rh_objs, lp);
104 	hp->rh_dtor(op);
105 }
106 
107 void
108 refhash_remove(refhash_t *hp, void *op)
109 {
110 	refhash_link_t *lp = obj_to_link(hp, op);
111 
112 	if (lp->rhl_refcnt > 0) {
113 		lp->rhl_flags |= RHL_F_DEAD;
114 	} else {
115 		refhash_delete(hp, op);
116 	}
117 }
118 
119 void *
120 refhash_lookup(refhash_t *hp, const void *tp)
121 {
122 	uint_t bucket;
123 	refhash_link_t *lp;
124 	void *op;
125 
126 	bucket = hp->rh_hash(tp) % hp->rh_bucket_count;
127 	for (lp = list_head(&hp->rh_buckets[bucket]); lp != NULL;
128 	    lp = list_next(&hp->rh_buckets[bucket], lp)) {
129 		op = link_to_obj(hp, lp);
130 		if (hp->rh_cmp(obj_to_tag(hp, op), tp) == 0 &&
131 		    !(lp->rhl_flags & RHL_F_DEAD)) {
132 			return (op);
133 		}
134 	}
135 
136 	return (NULL);
137 }
138 
139 void *
140 refhash_linear_search(refhash_t *hp, refhash_eval_f eval, void *arg)
141 {
142 	void *op;
143 	refhash_link_t *lp;
144 
145 	for (lp = list_head(&hp->rh_objs); lp != NULL;
146 	    lp = list_next(&hp->rh_objs, lp)) {
147 		op = link_to_obj(hp, lp);
148 		if (eval(op, arg) == 0)
149 			return (op);
150 	}
151 
152 	return (NULL);
153 }
154 
155 void
156 refhash_hold(refhash_t *hp, void *op)
157 {
158 	refhash_link_t *lp = obj_to_link(hp, op);
159 
160 	++lp->rhl_refcnt;
161 }
162 
163 void
164 refhash_rele(refhash_t *hp, void *op)
165 {
166 	refhash_link_t *lp = obj_to_link(hp, op);
167 
168 	ASSERT(lp->rhl_refcnt > 0);
169 
170 	if (--lp->rhl_refcnt == 0 && (lp->rhl_flags & RHL_F_DEAD))
171 		refhash_remove(hp, op);
172 }
173 
174 void *
175 refhash_first(refhash_t *hp)
176 {
177 	refhash_link_t *lp;
178 
179 	lp = list_head(&hp->rh_objs);
180 	if (lp == NULL)
181 		return (NULL);
182 
183 	++lp->rhl_refcnt;
184 
185 	return (link_to_obj(hp, lp));
186 }
187 
188 void *
189 refhash_next(refhash_t *hp, void *op)
190 {
191 	refhash_link_t *lp;
192 
193 	lp = obj_to_link(hp, op);
194 	while ((lp = list_next(&hp->rh_objs, lp)) != NULL) {
195 		if (!(lp->rhl_flags & RHL_F_DEAD))
196 			break;
197 	}
198 
199 	refhash_rele(hp, op);
200 	if (lp == NULL)
201 		return (NULL);
202 
203 	++lp->rhl_refcnt;
204 
205 	return (link_to_obj(hp, lp));
206 }
207 
208 boolean_t
209 refhash_obj_valid(refhash_t *hp, const void *op)
210 {
211 	/* LINTED - E_ARG_INCOMPATIBLE_WITH_ARG_L */
212 	const refhash_link_t *lp = obj_to_link(hp, op);
213 
214 	return ((lp->rhl_flags & RHL_F_DEAD) != 0);
215 }
216