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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 }