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 }