1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * This file contains interface code to make the kernel look it has
28 * an svr4.2 ddi/ddk. It also adds a little other system dependent
29 * functionality that is useful for drivers lower than nsctl.
30 */
31
32 #include <sys/types.h>
33 #ifndef DS_DDICT
34 #include <sys/time.h> /* only DDI compliant as of 5.9 */
35 #endif
36 #include <sys/param.h>
37 #include <sys/errno.h>
38 #include <sys/kmem.h>
39 #include <sys/ksynch.h>
40 #include <sys/cmn_err.h>
41 #include <sys/uio.h>
42 #include <sys/conf.h>
43 #include <sys/modctl.h>
44 #ifndef DS_DDICT
45 #include <sys/vnode.h>
46 #endif
47 #include <sys/open.h>
48 #include <sys/ddi.h>
49
50 #include "nsc_thread.h"
51
52 #ifdef DS_DDICT
53 #include <sys/nsctl/contract.h>
54 #endif
55
56 #include <sys/nsctl/nsctl.h>
57 #include <sys/nsctl/nsvers.h>
58 #include "nskernd.h"
59 #include "nsc_list.h"
60
61 kmutex_t _nskern_lock;
62
63 void _nsc_stop_proc(void);
64 void _nsc_start_proc(void);
65
66
67 /*
68 * Solaris specific driver module interface code.
69 */
70
71 static struct cb_ops nskern_cb_ops = {
72 nulldev, /* open */
73 nulldev, /* close */
74 nodev, /* strategy */
75 nodev, /* print */
76 nodev, /* dump */
77 nodev, /* read */
78 nodev, /* write */
79 nodev, /* ioctl */
80 nodev, /* devmap routine */
81 nodev, /* mmap routine */
82 nodev, /* segmap */
83 nochpoll, /* chpoll */
84 ddi_prop_op,
85 0, /* not a STREAMS driver, no cb_str routine */
86 D_NEW | D_MP | D_64BIT, /* safe for multi-thread/multi-processor */
87 CB_REV,
88 nodev, /* aread */
89 nodev, /* awrite */
90 };
91
92 static int _nskern_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
93 static int _nskern_attach(dev_info_t *, ddi_attach_cmd_t);
94 static int _nskern_detach(dev_info_t *, ddi_detach_cmd_t);
95
96 static struct dev_ops nskern_ops = {
97 DEVO_REV, /* Driver build version */
98 0, /* device reference count */
99 _nskern_getinfo,
100 nulldev, /* identify */
101 nulldev, /* probe */
102 _nskern_attach,
103 _nskern_detach,
104 nodev, /* reset */
105 &nskern_cb_ops,
106 (struct bus_ops *)NULL
107 };
108
109 static struct modldrv nskern_ldrv = {
110 &mod_driverops,
111 "nws:Kernel Interface:" ISS_VERSION_STR,
112 &nskern_ops
113 };
114
115 static dev_info_t *nskern_dip;
116
117 static struct modlinkage nskern_modlinkage = {
118 MODREV_1,
119 { &nskern_ldrv, NULL }
120 };
121
122 /*
123 * Solaris module load time code
124 */
125
126 int
127 _init(void)
128 {
129 void nskern_init();
130 int err;
131
132 mutex_init(&_nskern_lock, NULL, MUTEX_DRIVER, NULL);
133
134 err = mod_install(&nskern_modlinkage);
135 if (err) {
136 mutex_destroy(&_nskern_lock);
137 cmn_err(CE_WARN, "nskern_init: mod_install err %d", err);
138 return (err);
139 }
140
141 nskern_init();
142
143 return (DDI_SUCCESS);
144 }
145
146 /*
147 * Solaris module unload time code
148 */
149
150 int
151 _fini(void)
152 {
153 int err;
154
155 if ((err = mod_remove(&nskern_modlinkage)) == 0) {
156 nskernd_stop();
157 _nsc_stop_proc();
158 nskernd_deinit();
159
160 mutex_destroy(&_nskern_lock);
161 }
162
163 return (err);
164 }
165
166 int
167 _info(struct modinfo *modinfop)
168 {
169 return (mod_info(&nskern_modlinkage, modinfop));
170 }
171
172 /*
173 * Attach an instance of the device. This happens before an open
174 * can succeed.
175 */
176
177 static int
178 _nskern_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
179 {
180 if (cmd == DDI_ATTACH) {
181 nskern_dip = dip;
182 return (DDI_SUCCESS);
183 } else {
184 return (DDI_FAILURE);
185 }
186 }
187
188 /* ARGSUSED */
189
190 static int
191 _nskern_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
192 {
193 if (cmd == DDI_DETACH) {
194 nskern_dip = NULL;
195 return (DDI_SUCCESS);
196 } else {
197 return (DDI_FAILURE);
198 }
199 }
200
201 /* ARGSUSED */
202 static int
203 _nskern_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
204 {
205 int rc = DDI_FAILURE;
206
207 switch (cmd) {
208 case DDI_INFO_DEVT2DEVINFO:
209 *result = nskern_dip;
210 rc = DDI_SUCCESS;
211 break;
212
213 case DDI_INFO_DEVT2INSTANCE:
214 /* single instance */
215 *result = 0;
216 rc = DDI_SUCCESS;
217 break;
218 }
219
220 return (rc);
221 }
222
223 /* ARGSUSED */
224
225 int
226 _nskern_print(dev_t dev, char *s)
227 {
228 cmn_err(CE_WARN, "nskern:%s", s);
229 return (0);
230 }
231
232 /*
233 * nskern_init - initialize the nskern layer at module load time.
234 */
235
236 void
237 nskern_init(void)
238 {
239 _nsc_start_proc();
240 nskernd_init();
241
242 (void) nst_startup();
243 }
244
245
246 #if (defined(DS_DDICT))
247 static clock_t
248 nskern_lbolt(void)
249 {
250 #ifdef _SunOS_5_6
251 clock_t lbolt;
252
253 if (drv_getparm(LBOLT, &lbolt) == 0)
254 return (lbolt);
255
256 return (0);
257 #else
258 return (ddi_get_lbolt());
259 #endif
260 }
261 #endif /* ddict */
262
263
264 /*
265 * nsc_usec()
266 * - return the value of the "microsecond timer emulation".
267 *
268 * Pre-SunOS 5.9:
269 * Actually this is a fake free running counter based on the lbolt value.
270 *
271 * SunOS 5.9+
272 * This is based on the gethrtime(9f) DDI facility.
273 */
274
275 #if (defined(DS_DDICT))
276 /* these two #defines need to match! */
277 #define USEC_SHIFT 16
278 #define INCR_TYPE uint16_t
279 #endif /* ! _SunOS_5_9+ */
280
281 clock_t
282 nsc_usec(void)
283 {
284 /* avoid divide by zero */
285 return (gethrtime() / 1000);
286 }
287
288
289 /*
290 * nsc_yield - yield the cpu.
291 */
292 void
293 nsc_yield(void)
294 {
295 /* can't call yield() unless there is an lwp context */
296 /* do this for now */
297
298 delay(2);
299 }
300
301
302 /*
303 * void
304 * ls_ins_before(ls_elt_t *, ls_elt_t *)
305 * Link new into list before old.
306 *
307 * Calling/Exit State:
308 * None.
309 */
310 #ifdef lint
311 void
312 nsc_ddi_ls_ins_before(ls_elt_t *old, ls_elt_t *new)
313 #else
314 void
315 ls_ins_before(ls_elt_t *old, ls_elt_t *new)
316 #endif
317 {
318 new->ls_prev = old->ls_prev;
319 new->ls_next = old;
320 new->ls_prev->ls_next = new;
321 new->ls_next->ls_prev = new;
322 }
323
324 /*
325 * void
326 * ls_ins_after(ls_elt_t *, ls_elt_t *)
327 * Link new into list after old.
328 *
329 * Calling/Exit State:
330 * None.
331 */
332 #ifdef lint
333 void
334 nsc_ddi_ls_ins_after(ls_elt_t *old, ls_elt_t *new)
335 #else
336 void
337 ls_ins_after(ls_elt_t *old, ls_elt_t *new)
338 #endif
339 {
340 new->ls_next = old->ls_next;
341 new->ls_prev = old;
342 new->ls_next->ls_prev = new;
343 new->ls_prev->ls_next = new;
344 }
345
346 /*
347 * ls_elt_t *
348 * ls_remque(ls_elt_t *)
349 * Unlink first element in the specified list.
350 *
351 * Calling/Exit State:
352 * Returns the element's address or 0 if list is empty.
353 * Resets elements pointers to empty list state.
354 */
355 ls_elt_t *
356 ls_remque(ls_elt_t *p)
357 {
358 ls_elt_t *result = 0;
359
360 if (!LS_ISEMPTY(p)) {
361 result = p->ls_next;
362 result->ls_prev->ls_next = result->ls_next;
363 result->ls_next->ls_prev = result->ls_prev;
364 LS_INIT(result);
365 }
366 return (result);
367 }
368
369 /*
370 * void
371 * ls_remove(ls_elt_t *)
372 * Unlink donated element for list.
373 *
374 * Calling/Exit State:
375 * Resets elements pointers to empty list state.
376 */
377 #ifdef lint
378 void
379 nsc_ddi_ls_remove(ls_elt_t *p)
380 #else
381 void
382 ls_remove(ls_elt_t *p)
383 #endif
384 {
385 p->ls_prev->ls_next = p->ls_next;
386 p->ls_next->ls_prev = p->ls_prev;
387 LS_INIT(p);
388 }