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,
120 NULL
121 };
122
123 /*
124 * Solaris module load time code
125 */
126
127 int
_init(void)128 _init(void)
129 {
130 void nskern_init();
131 int err;
132
133 mutex_init(&_nskern_lock, NULL, MUTEX_DRIVER, NULL);
134
135 err = mod_install(&nskern_modlinkage);
136 if (err) {
137 mutex_destroy(&_nskern_lock);
138 cmn_err(CE_WARN, "nskern_init: mod_install err %d", err);
139 return (err);
140 }
141
142 nskern_init();
143
144 return (DDI_SUCCESS);
145 }
146
147 /*
148 * Solaris module unload time code
149 */
150
151 int
_fini(void)152 _fini(void)
153 {
154 int err;
155
156 if ((err = mod_remove(&nskern_modlinkage)) == 0) {
157 nskernd_stop();
158 _nsc_stop_proc();
159 nskernd_deinit();
160
161 mutex_destroy(&_nskern_lock);
162 }
163
164 return (err);
165 }
166
167 int
_info(struct modinfo * modinfop)168 _info(struct modinfo *modinfop)
169 {
170 return (mod_info(&nskern_modlinkage, modinfop));
171 }
172
173 /*
174 * Attach an instance of the device. This happens before an open
175 * can succeed.
176 */
177
178 static int
_nskern_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)179 _nskern_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
180 {
181 if (cmd == DDI_ATTACH) {
182 nskern_dip = dip;
183 return (DDI_SUCCESS);
184 } else {
185 return (DDI_FAILURE);
186 }
187 }
188
189 /* ARGSUSED */
190
191 static int
_nskern_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)192 _nskern_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
193 {
194 if (cmd == DDI_DETACH) {
195 nskern_dip = NULL;
196 return (DDI_SUCCESS);
197 } else {
198 return (DDI_FAILURE);
199 }
200 }
201
202 /* ARGSUSED */
203 static int
_nskern_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)204 _nskern_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
205 {
206 int rc = DDI_FAILURE;
207
208 switch (cmd) {
209 case DDI_INFO_DEVT2DEVINFO:
210 *result = nskern_dip;
211 rc = DDI_SUCCESS;
212 break;
213
214 case DDI_INFO_DEVT2INSTANCE:
215 /* single instance */
216 *result = 0;
217 rc = DDI_SUCCESS;
218 break;
219 }
220
221 return (rc);
222 }
223
224 /* ARGSUSED */
225
226 int
_nskern_print(dev_t dev,char * s)227 _nskern_print(dev_t dev, char *s)
228 {
229 cmn_err(CE_WARN, "nskern:%s", s);
230 return (0);
231 }
232
233 /*
234 * nskern_init - initialize the nskern layer at module load time.
235 */
236
237 void
nskern_init(void)238 nskern_init(void)
239 {
240 _nsc_start_proc();
241 nskernd_init();
242
243 (void) nst_startup();
244 }
245
246
247 #if (defined(DS_DDICT))
248 static clock_t
nskern_lbolt(void)249 nskern_lbolt(void)
250 {
251 #ifdef _SunOS_5_6
252 clock_t lbolt;
253
254 if (drv_getparm(LBOLT, &lbolt) == 0)
255 return (lbolt);
256
257 return (0);
258 #else
259 return (ddi_get_lbolt());
260 #endif
261 }
262 #endif /* ddict */
263
264
265 /*
266 * nsc_usec()
267 * - return the value of the "microsecond timer emulation".
268 *
269 * Pre-SunOS 5.9:
270 * Actually this is a fake free running counter based on the lbolt value.
271 *
272 * SunOS 5.9+
273 * This is based on the gethrtime(9f) DDI facility.
274 */
275
276 #if (defined(DS_DDICT))
277 /* these two #defines need to match! */
278 #define USEC_SHIFT 16
279 #define INCR_TYPE uint16_t
280 #endif /* ! _SunOS_5_9+ */
281
282 clock_t
nsc_usec(void)283 nsc_usec(void)
284 {
285 /* avoid divide by zero */
286 return (gethrtime() / 1000);
287 }
288
289
290 /*
291 * nsc_yield - yield the cpu.
292 */
293 void
nsc_yield(void)294 nsc_yield(void)
295 {
296 /* can't call yield() unless there is an lwp context */
297 /* do this for now */
298
299 delay(2);
300 }
301
302
303 /*
304 * void
305 * ls_ins_before(ls_elt_t *, ls_elt_t *)
306 * Link new into list before old.
307 *
308 * Calling/Exit State:
309 * None.
310 */
311 #ifdef lint
312 void
nsc_ddi_ls_ins_before(ls_elt_t * old,ls_elt_t * new)313 nsc_ddi_ls_ins_before(ls_elt_t *old, ls_elt_t *new)
314 #else
315 void
316 ls_ins_before(ls_elt_t *old, ls_elt_t *new)
317 #endif
318 {
319 new->ls_prev = old->ls_prev;
320 new->ls_next = old;
321 new->ls_prev->ls_next = new;
322 new->ls_next->ls_prev = new;
323 }
324
325 /*
326 * void
327 * ls_ins_after(ls_elt_t *, ls_elt_t *)
328 * Link new into list after old.
329 *
330 * Calling/Exit State:
331 * None.
332 */
333 #ifdef lint
334 void
nsc_ddi_ls_ins_after(ls_elt_t * old,ls_elt_t * new)335 nsc_ddi_ls_ins_after(ls_elt_t *old, ls_elt_t *new)
336 #else
337 void
338 ls_ins_after(ls_elt_t *old, ls_elt_t *new)
339 #endif
340 {
341 new->ls_next = old->ls_next;
342 new->ls_prev = old;
343 new->ls_next->ls_prev = new;
344 new->ls_prev->ls_next = new;
345 }
346
347 /*
348 * ls_elt_t *
349 * ls_remque(ls_elt_t *)
350 * Unlink first element in the specified list.
351 *
352 * Calling/Exit State:
353 * Returns the element's address or 0 if list is empty.
354 * Resets elements pointers to empty list state.
355 */
356 ls_elt_t *
ls_remque(ls_elt_t * p)357 ls_remque(ls_elt_t *p)
358 {
359 ls_elt_t *result = 0;
360
361 if (!LS_ISEMPTY(p)) {
362 result = p->ls_next;
363 result->ls_prev->ls_next = result->ls_next;
364 result->ls_next->ls_prev = result->ls_prev;
365 LS_INIT(result);
366 }
367 return (result);
368 }
369
370 /*
371 * void
372 * ls_remove(ls_elt_t *)
373 * Unlink donated element for list.
374 *
375 * Calling/Exit State:
376 * Resets elements pointers to empty list state.
377 */
378 #ifdef lint
379 void
nsc_ddi_ls_remove(ls_elt_t * p)380 nsc_ddi_ls_remove(ls_elt_t *p)
381 #else
382 void
383 ls_remove(ls_elt_t *p)
384 #endif
385 {
386 p->ls_prev->ls_next = p->ls_next;
387 p->ls_next->ls_prev = p->ls_prev;
388 LS_INIT(p);
389 }
390