1*3941Svenki /* 2*3941Svenki * CDDL HEADER START 3*3941Svenki * 4*3941Svenki * The contents of this file are subject to the terms of the 5*3941Svenki * Common Development and Distribution License (the "License"). 6*3941Svenki * You may not use this file except in compliance with the License. 7*3941Svenki * 8*3941Svenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3941Svenki * or http://www.opensolaris.org/os/licensing. 10*3941Svenki * See the License for the specific language governing permissions 11*3941Svenki * and limitations under the License. 12*3941Svenki * 13*3941Svenki * When distributing Covered Code, include this CDDL HEADER in each 14*3941Svenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3941Svenki * If applicable, add the following below this CDDL HEADER, with the 16*3941Svenki * fields enclosed by brackets "[]" replaced with your own identifying 17*3941Svenki * information: Portions Copyright [yyyy] [name of copyright owner] 18*3941Svenki * 19*3941Svenki * CDDL HEADER END 20*3941Svenki */ 21*3941Svenki /* 22*3941Svenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*3941Svenki * Use is subject to license terms. 24*3941Svenki */ 25*3941Svenki 26*3941Svenki #pragma ident "%Z%%M% %I% %E% SMI" 27*3941Svenki 28*3941Svenki /* 29*3941Svenki * sun4v domain services SNMP driver 30*3941Svenki */ 31*3941Svenki 32*3941Svenki #include <sys/types.h> 33*3941Svenki #include <sys/file.h> 34*3941Svenki #include <sys/errno.h> 35*3941Svenki #include <sys/open.h> 36*3941Svenki #include <sys/cred.h> 37*3941Svenki #include <sys/uio.h> 38*3941Svenki #include <sys/stat.h> 39*3941Svenki #include <sys/ksynch.h> 40*3941Svenki #include <sys/modctl.h> 41*3941Svenki #include <sys/conf.h> 42*3941Svenki #include <sys/devops.h> 43*3941Svenki #include <sys/debug.h> 44*3941Svenki #include <sys/cmn_err.h> 45*3941Svenki #include <sys/ddi.h> 46*3941Svenki #include <sys/sunddi.h> 47*3941Svenki #include <sys/ds.h> 48*3941Svenki #include <sys/ds_snmp.h> 49*3941Svenki 50*3941Svenki #define DS_SNMP_NAME "ds_snmp" 51*3941Svenki #define DS_SNMP_MAX_OPENS 256 52*3941Svenki #define DS_BITS_IN_UINT64 64 53*3941Svenki #define DS_MINOR_POOL_SZ (DS_SNMP_MAX_OPENS / DS_BITS_IN_UINT64) 54*3941Svenki #define DS_SNMP_MINOR_SHIFT 56 55*3941Svenki #define DS_SNMP_DBG if (ds_snmp_debug) printf 56*3941Svenki 57*3941Svenki typedef struct { 58*3941Svenki uint64_t seq_num; 59*3941Svenki uint64_t type; 60*3941Svenki } ds_snmp_msg_t; 61*3941Svenki 62*3941Svenki typedef enum { 63*3941Svenki DS_SNMP_REQUEST = 0, 64*3941Svenki DS_SNMP_REPLY = 1, 65*3941Svenki DS_SNMP_ERROR = 2 66*3941Svenki } ds_snmp_msg_type_t; 67*3941Svenki 68*3941Svenki typedef enum { 69*3941Svenki DS_SNMP_READY = 0x0, 70*3941Svenki DS_SNMP_REQUESTED = 0x1, 71*3941Svenki DS_SNMP_DATA_AVL = 0x2, 72*3941Svenki DS_SNMP_DATA_ERR = 0x3 73*3941Svenki } ds_snmp_flags_t; 74*3941Svenki 75*3941Svenki /* 76*3941Svenki * The single mutex 'lock' protects all the SNMP/DS variables in the state 77*3941Svenki * structure. 78*3941Svenki * 79*3941Svenki * The condition variable 'state_cv' helps serialize write() calls for a 80*3941Svenki * single descriptor. When write() is called, it sets a flag to indicate 81*3941Svenki * that an SNMP request has been made to the agent. No more write()'s on 82*3941Svenki * the same open descriptor will be allowed until this flag is cleared via 83*3941Svenki * a matching read(), where the requested packet is consumed on arrival. 84*3941Svenki * Read() then wakes up any waiters blocked in write() for sending the next 85*3941Svenki * SNMP request to the agent. 86*3941Svenki */ 87*3941Svenki typedef struct ds_snmp_state { 88*3941Svenki dev_info_t *dip; 89*3941Svenki int instance; 90*3941Svenki dev_t dev; 91*3941Svenki 92*3941Svenki /* SNMP/DS */ 93*3941Svenki kmutex_t lock; 94*3941Svenki kcondvar_t state_cv; 95*3941Svenki ds_snmp_flags_t state; 96*3941Svenki void *data; 97*3941Svenki size_t data_len; 98*3941Svenki uint64_t req_id; 99*3941Svenki uint64_t last_req_id; 100*3941Svenki uint64_t gencount; 101*3941Svenki boolean_t sc_reset; 102*3941Svenki } ds_snmp_state_t; 103*3941Svenki 104*3941Svenki 105*3941Svenki static uint_t ds_snmp_debug = 0; 106*3941Svenki static void *ds_snmp_statep = NULL; 107*3941Svenki static int ds_snmp_instance = -1; 108*3941Svenki static dev_info_t *ds_snmp_devi = NULL; 109*3941Svenki 110*3941Svenki /* 111*3941Svenki * The ds_snmp_lock mutex protects the following data global to the 112*3941Svenki * driver. 113*3941Svenki * 114*3941Svenki * The ds_snmp_service_cv condition variable is used to resolve the 115*3941Svenki * potential race between the registration of snmp service via a 116*3941Svenki * ds_cap_init() in attach(), the acknowledgement of this registration 117*3941Svenki * at a later time in ds_snmp_reg_handler(), and a possible open() at 118*3941Svenki * a time inbetween. The ds_snmp_has_service and ds_snmp_handle are 119*3941Svenki * used to indicate whether the registration acknowledgement has happened 120*3941Svenki * or not. 121*3941Svenki * 122*3941Svenki * The ds_snmp_minor_pool[] is a bitmask to allocate and keep track of 123*3941Svenki * minor numbers dynamically. 124*3941Svenki */ 125*3941Svenki static kmutex_t ds_snmp_lock; 126*3941Svenki static kcondvar_t ds_snmp_service_cv; 127*3941Svenki static int ds_snmp_has_service = B_FALSE; 128*3941Svenki static ds_svc_hdl_t ds_snmp_handle = DS_INVALID_HDL; 129*3941Svenki static uint64_t ds_snmp_minor_pool[DS_MINOR_POOL_SZ]; /* bitmask */ 130*3941Svenki static int ds_snmp_num_opens = 0; 131*3941Svenki 132*3941Svenki static int ds_snmp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 133*3941Svenki static int ds_snmp_attach(dev_info_t *, ddi_attach_cmd_t); 134*3941Svenki static int ds_snmp_detach(dev_info_t *, ddi_detach_cmd_t); 135*3941Svenki static int ds_snmp_open(dev_t *, int, int, cred_t *); 136*3941Svenki static int ds_snmp_close(dev_t, int, int, cred_t *); 137*3941Svenki static int ds_snmp_read(dev_t, struct uio *, cred_t *); 138*3941Svenki static int ds_snmp_write(dev_t, struct uio *, cred_t *); 139*3941Svenki static int ds_snmp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 140*3941Svenki 141*3941Svenki /* 142*3941Svenki * DS Callbacks 143*3941Svenki */ 144*3941Svenki static void ds_snmp_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 145*3941Svenki static void ds_snmp_unreg_handler(ds_cb_arg_t arg); 146*3941Svenki static void ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 147*3941Svenki 148*3941Svenki /* 149*3941Svenki * SNMP DS capability registration 150*3941Svenki */ 151*3941Svenki static ds_ver_t ds_snmp_ver_1_0 = { 1, 0 }; 152*3941Svenki static ds_capability_t ds_snmp_cap = { 153*3941Svenki "snmp", 154*3941Svenki &ds_snmp_ver_1_0, 155*3941Svenki 1 156*3941Svenki }; 157*3941Svenki 158*3941Svenki /* 159*3941Svenki * SNMP DS Client callback vector 160*3941Svenki */ 161*3941Svenki static ds_clnt_ops_t ds_snmp_ops = { 162*3941Svenki ds_snmp_reg_handler, /* ds_reg_cb */ 163*3941Svenki ds_snmp_unreg_handler, /* ds_unreg_cb */ 164*3941Svenki ds_snmp_data_handler, /* ds_data_cb */ 165*3941Svenki NULL /* cb_arg */ 166*3941Svenki }; 167*3941Svenki 168*3941Svenki /* 169*3941Svenki * DS SNMP driver Ops Vector 170*3941Svenki */ 171*3941Svenki static struct cb_ops ds_snmp_cb_ops = { 172*3941Svenki ds_snmp_open, /* cb_open */ 173*3941Svenki ds_snmp_close, /* cb_close */ 174*3941Svenki nodev, /* cb_strategy */ 175*3941Svenki nodev, /* cb_print */ 176*3941Svenki nodev, /* cb_dump */ 177*3941Svenki ds_snmp_read, /* cb_read */ 178*3941Svenki ds_snmp_write, /* cb_write */ 179*3941Svenki ds_snmp_ioctl, /* cb_ioctl */ 180*3941Svenki nodev, /* cb_devmap */ 181*3941Svenki nodev, /* cb_mmap */ 182*3941Svenki nodev, /* cb_segmap */ 183*3941Svenki nochpoll, /* cb_chpoll */ 184*3941Svenki ddi_prop_op, /* cb_prop_op */ 185*3941Svenki (struct streamtab *)NULL, /* cb_str */ 186*3941Svenki D_MP | D_64BIT, /* cb_flag */ 187*3941Svenki CB_REV, /* cb_rev */ 188*3941Svenki nodev, /* cb_aread */ 189*3941Svenki nodev /* cb_awrite */ 190*3941Svenki }; 191*3941Svenki 192*3941Svenki static struct dev_ops ds_snmp_dev_ops = { 193*3941Svenki DEVO_REV, /* devo_rev */ 194*3941Svenki 0, /* devo_refcnt */ 195*3941Svenki ds_snmp_getinfo, /* devo_getinfo */ 196*3941Svenki nulldev, /* devo_identify */ 197*3941Svenki nulldev, /* devo_probe */ 198*3941Svenki ds_snmp_attach, /* devo_attach */ 199*3941Svenki ds_snmp_detach, /* devo_detach */ 200*3941Svenki nodev, /* devo_reset */ 201*3941Svenki &ds_snmp_cb_ops, /* devo_cb_ops */ 202*3941Svenki (struct bus_ops *)NULL, /* devo_bus_ops */ 203*3941Svenki nulldev /* devo_power */ 204*3941Svenki }; 205*3941Svenki 206*3941Svenki static struct modldrv modldrv = { 207*3941Svenki &mod_driverops, 208*3941Svenki "Domain Services SNMP Driver 1.0", 209*3941Svenki &ds_snmp_dev_ops 210*3941Svenki }; 211*3941Svenki 212*3941Svenki static struct modlinkage modlinkage = { 213*3941Svenki MODREV_1, 214*3941Svenki (void *)&modldrv, 215*3941Svenki NULL 216*3941Svenki }; 217*3941Svenki 218*3941Svenki int 219*3941Svenki _init(void) 220*3941Svenki { 221*3941Svenki int retval; 222*3941Svenki 223*3941Svenki mutex_init(&ds_snmp_lock, NULL, MUTEX_DRIVER, NULL); 224*3941Svenki cv_init(&ds_snmp_service_cv, NULL, CV_DRIVER, NULL); 225*3941Svenki 226*3941Svenki retval = ddi_soft_state_init(&ds_snmp_statep, 227*3941Svenki sizeof (ds_snmp_state_t), DS_SNMP_MAX_OPENS); 228*3941Svenki if (retval != 0) { 229*3941Svenki cv_destroy(&ds_snmp_service_cv); 230*3941Svenki mutex_destroy(&ds_snmp_lock); 231*3941Svenki return (retval); 232*3941Svenki } 233*3941Svenki 234*3941Svenki retval = mod_install(&modlinkage); 235*3941Svenki if (retval != 0) { 236*3941Svenki ddi_soft_state_fini(&ds_snmp_statep); 237*3941Svenki cv_destroy(&ds_snmp_service_cv); 238*3941Svenki mutex_destroy(&ds_snmp_lock); 239*3941Svenki } 240*3941Svenki 241*3941Svenki return (retval); 242*3941Svenki } 243*3941Svenki 244*3941Svenki int 245*3941Svenki _info(struct modinfo *modinfop) 246*3941Svenki { 247*3941Svenki return (mod_info(&modlinkage, modinfop)); 248*3941Svenki } 249*3941Svenki 250*3941Svenki int 251*3941Svenki _fini(void) 252*3941Svenki { 253*3941Svenki int retval; 254*3941Svenki 255*3941Svenki if ((retval = mod_remove(&modlinkage)) != 0) 256*3941Svenki return (retval); 257*3941Svenki 258*3941Svenki ddi_soft_state_fini(&ds_snmp_statep); 259*3941Svenki 260*3941Svenki cv_destroy(&ds_snmp_service_cv); 261*3941Svenki mutex_destroy(&ds_snmp_lock); 262*3941Svenki 263*3941Svenki return (retval); 264*3941Svenki } 265*3941Svenki 266*3941Svenki /*ARGSUSED*/ 267*3941Svenki static int 268*3941Svenki ds_snmp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 269*3941Svenki { 270*3941Svenki ds_snmp_state_t *sp; 271*3941Svenki int retval = DDI_FAILURE; 272*3941Svenki 273*3941Svenki ASSERT(resultp != NULL); 274*3941Svenki 275*3941Svenki switch (cmd) { 276*3941Svenki case DDI_INFO_DEVT2DEVINFO: 277*3941Svenki sp = ddi_get_soft_state(ds_snmp_statep, getminor((dev_t)arg)); 278*3941Svenki if (sp != NULL) { 279*3941Svenki *resultp = sp->dip; 280*3941Svenki retval = DDI_SUCCESS; 281*3941Svenki } else 282*3941Svenki *resultp = NULL; 283*3941Svenki break; 284*3941Svenki 285*3941Svenki case DDI_INFO_DEVT2INSTANCE: 286*3941Svenki *resultp = (void *)(uintptr_t)getminor((dev_t)arg); 287*3941Svenki retval = DDI_SUCCESS; 288*3941Svenki break; 289*3941Svenki } 290*3941Svenki 291*3941Svenki return (retval); 292*3941Svenki } 293*3941Svenki 294*3941Svenki static int 295*3941Svenki ds_snmp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 296*3941Svenki { 297*3941Svenki int rv; 298*3941Svenki 299*3941Svenki switch (cmd) { 300*3941Svenki case DDI_ATTACH: 301*3941Svenki if (ds_snmp_instance != -1) 302*3941Svenki return (DDI_FAILURE); 303*3941Svenki break; 304*3941Svenki 305*3941Svenki case DDI_RESUME: 306*3941Svenki return (DDI_SUCCESS); 307*3941Svenki 308*3941Svenki default: 309*3941Svenki return (DDI_FAILURE); 310*3941Svenki } 311*3941Svenki 312*3941Svenki ds_snmp_instance = ddi_get_instance(dip); 313*3941Svenki if (ddi_create_minor_node(dip, DS_SNMP_NAME, S_IFCHR, ds_snmp_instance, 314*3941Svenki DDI_PSEUDO, 0) != DDI_SUCCESS) { 315*3941Svenki cmn_err(CE_WARN, "%s@%d: Unable to create minor node", 316*3941Svenki DS_SNMP_NAME, ds_snmp_instance); 317*3941Svenki return (DDI_FAILURE); 318*3941Svenki } 319*3941Svenki 320*3941Svenki bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t)); 321*3941Svenki 322*3941Svenki ds_snmp_ops.cb_arg = dip; 323*3941Svenki if ((rv = ds_cap_init(&ds_snmp_cap, &ds_snmp_ops)) != 0) { 324*3941Svenki cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv); 325*3941Svenki ddi_remove_minor_node(dip, NULL); 326*3941Svenki ds_snmp_instance = -1; 327*3941Svenki return (DDI_FAILURE); 328*3941Svenki } 329*3941Svenki 330*3941Svenki ds_snmp_devi = dip; 331*3941Svenki ddi_report_dev(dip); 332*3941Svenki 333*3941Svenki return (DDI_SUCCESS); 334*3941Svenki } 335*3941Svenki 336*3941Svenki /*ARGSUSED*/ 337*3941Svenki static int 338*3941Svenki ds_snmp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 339*3941Svenki { 340*3941Svenki switch (cmd) { 341*3941Svenki case DDI_DETACH: 342*3941Svenki if (ds_snmp_instance == -1) 343*3941Svenki return (DDI_FAILURE); 344*3941Svenki break; 345*3941Svenki 346*3941Svenki case DDI_SUSPEND: 347*3941Svenki return (DDI_SUCCESS); 348*3941Svenki 349*3941Svenki default: 350*3941Svenki return (DDI_FAILURE); 351*3941Svenki } 352*3941Svenki 353*3941Svenki (void) ds_cap_fini(&ds_snmp_cap); 354*3941Svenki 355*3941Svenki ddi_remove_minor_node(ds_snmp_devi, NULL); 356*3941Svenki bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t)); 357*3941Svenki 358*3941Svenki ds_snmp_instance = -1; 359*3941Svenki ds_snmp_devi = NULL; 360*3941Svenki 361*3941Svenki return (DDI_SUCCESS); 362*3941Svenki } 363*3941Svenki 364*3941Svenki static minor_t 365*3941Svenki ds_snmp_get_minor(void) 366*3941Svenki { 367*3941Svenki uint64_t val; 368*3941Svenki int i, ndx; 369*3941Svenki minor_t minor; 370*3941Svenki 371*3941Svenki mutex_enter(&ds_snmp_lock); 372*3941Svenki for (ndx = 0; ndx < DS_MINOR_POOL_SZ; ndx++) { 373*3941Svenki val = ds_snmp_minor_pool[ndx]; 374*3941Svenki for (i = 0; i < DS_BITS_IN_UINT64; i++) { 375*3941Svenki if ((val & 0x1) == 0) { 376*3941Svenki ds_snmp_minor_pool[ndx] |= ((uint64_t)1 << i); 377*3941Svenki ds_snmp_num_opens++; 378*3941Svenki mutex_exit(&ds_snmp_lock); 379*3941Svenki 380*3941Svenki minor = ndx * DS_BITS_IN_UINT64 + i + 1; 381*3941Svenki 382*3941Svenki return (minor); 383*3941Svenki } 384*3941Svenki val >>= 1; 385*3941Svenki } 386*3941Svenki } 387*3941Svenki mutex_exit(&ds_snmp_lock); 388*3941Svenki 389*3941Svenki return (0); 390*3941Svenki } 391*3941Svenki 392*3941Svenki static void 393*3941Svenki ds_snmp_rel_minor(minor_t minor) 394*3941Svenki { 395*3941Svenki int i, ndx; 396*3941Svenki 397*3941Svenki ndx = (minor - 1) / DS_BITS_IN_UINT64; 398*3941Svenki i = (minor - 1) % DS_BITS_IN_UINT64; 399*3941Svenki 400*3941Svenki ASSERT(ndx < DS_MINOR_POOL_SZ); 401*3941Svenki 402*3941Svenki mutex_enter(&ds_snmp_lock); 403*3941Svenki 404*3941Svenki ds_snmp_num_opens--; 405*3941Svenki ds_snmp_minor_pool[ndx] &= ~((uint64_t)1 << i); 406*3941Svenki 407*3941Svenki mutex_exit(&ds_snmp_lock); 408*3941Svenki } 409*3941Svenki 410*3941Svenki static boolean_t 411*3941Svenki ds_snmp_is_open(minor_t minor) 412*3941Svenki { 413*3941Svenki uint64_t val; 414*3941Svenki int i, ndx; 415*3941Svenki 416*3941Svenki ndx = (minor - 1) / DS_BITS_IN_UINT64; 417*3941Svenki i = (minor - 1) % DS_BITS_IN_UINT64; 418*3941Svenki 419*3941Svenki val = ((uint64_t)1 << i); 420*3941Svenki if (ds_snmp_minor_pool[ndx] & val) 421*3941Svenki return (B_TRUE); 422*3941Svenki else 423*3941Svenki return (B_FALSE); 424*3941Svenki } 425*3941Svenki 426*3941Svenki static int 427*3941Svenki ds_snmp_create_state(dev_t *devp) 428*3941Svenki { 429*3941Svenki major_t major; 430*3941Svenki minor_t minor; 431*3941Svenki ds_snmp_state_t *sp; 432*3941Svenki 433*3941Svenki if ((minor = ds_snmp_get_minor()) == 0) 434*3941Svenki return (EMFILE); 435*3941Svenki 436*3941Svenki if (ddi_soft_state_zalloc(ds_snmp_statep, minor) != DDI_SUCCESS) { 437*3941Svenki cmn_err(CE_WARN, "%s@%d: Unable to allocate state", 438*3941Svenki DS_SNMP_NAME, minor); 439*3941Svenki ds_snmp_rel_minor(minor); 440*3941Svenki return (ENOMEM); 441*3941Svenki } 442*3941Svenki 443*3941Svenki sp = ddi_get_soft_state(ds_snmp_statep, minor); 444*3941Svenki if (devp != NULL) 445*3941Svenki major = getemajor(*devp); 446*3941Svenki else 447*3941Svenki major = ddi_driver_major(ds_snmp_devi); 448*3941Svenki 449*3941Svenki sp->dev = makedevice(major, minor); 450*3941Svenki if (devp != NULL) 451*3941Svenki *devp = sp->dev; 452*3941Svenki 453*3941Svenki sp->instance = minor; 454*3941Svenki sp->data = NULL; 455*3941Svenki sp->data_len = 0; 456*3941Svenki sp->req_id = 0; 457*3941Svenki sp->last_req_id = 0; 458*3941Svenki sp->state = DS_SNMP_READY; 459*3941Svenki sp->sc_reset = B_FALSE; 460*3941Svenki 461*3941Svenki mutex_init(&sp->lock, NULL, MUTEX_DRIVER, NULL); 462*3941Svenki cv_init(&sp->state_cv, NULL, CV_DRIVER, NULL); 463*3941Svenki 464*3941Svenki return (0); 465*3941Svenki } 466*3941Svenki 467*3941Svenki static int 468*3941Svenki ds_snmp_destroy_state(dev_t dev) 469*3941Svenki { 470*3941Svenki ds_snmp_state_t *sp; 471*3941Svenki minor_t minor; 472*3941Svenki 473*3941Svenki minor = getminor(dev); 474*3941Svenki 475*3941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL) 476*3941Svenki return (ENXIO); 477*3941Svenki 478*3941Svenki ASSERT(sp->instance == minor); 479*3941Svenki 480*3941Svenki /* 481*3941Svenki * If the app has not exited cleanly, the data may not have been 482*3941Svenki * read/memory freed, hence take care of that here 483*3941Svenki */ 484*3941Svenki if (sp->data) { 485*3941Svenki kmem_free(sp->data, sp->data_len); 486*3941Svenki } 487*3941Svenki cv_destroy(&sp->state_cv); 488*3941Svenki mutex_destroy(&sp->lock); 489*3941Svenki 490*3941Svenki ddi_soft_state_free(ds_snmp_statep, minor); 491*3941Svenki ds_snmp_rel_minor(minor); 492*3941Svenki 493*3941Svenki return (0); 494*3941Svenki } 495*3941Svenki 496*3941Svenki /*ARGSUSED*/ 497*3941Svenki static int 498*3941Svenki ds_snmp_open(dev_t *devp, int flag, int otyp, cred_t *credp) 499*3941Svenki { 500*3941Svenki 501*3941Svenki if (otyp != OTYP_CHR) 502*3941Svenki return (EINVAL); 503*3941Svenki 504*3941Svenki if (ds_snmp_instance == -1) 505*3941Svenki return (ENXIO); 506*3941Svenki 507*3941Svenki /* 508*3941Svenki * Avoid possible race condition - ds service may not be there yet 509*3941Svenki */ 510*3941Svenki mutex_enter(&ds_snmp_lock); 511*3941Svenki while (ds_snmp_has_service == B_FALSE) { 512*3941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) { 513*3941Svenki mutex_exit(&ds_snmp_lock); 514*3941Svenki return (EINTR); 515*3941Svenki } 516*3941Svenki } 517*3941Svenki mutex_exit(&ds_snmp_lock); 518*3941Svenki 519*3941Svenki return (ds_snmp_create_state(devp)); 520*3941Svenki } 521*3941Svenki 522*3941Svenki 523*3941Svenki /*ARGSUSED*/ 524*3941Svenki static int 525*3941Svenki ds_snmp_close(dev_t dev, int flag, int otyp, cred_t *credp) 526*3941Svenki { 527*3941Svenki if (otyp != OTYP_CHR) 528*3941Svenki return (EINVAL); 529*3941Svenki 530*3941Svenki if (ds_snmp_instance == -1) 531*3941Svenki return (ENXIO); 532*3941Svenki 533*3941Svenki if (ds_snmp_handle == DS_INVALID_HDL) 534*3941Svenki return (EIO); 535*3941Svenki 536*3941Svenki return (ds_snmp_destroy_state(dev)); 537*3941Svenki } 538*3941Svenki 539*3941Svenki /*ARGSUSED*/ 540*3941Svenki static int 541*3941Svenki ds_snmp_read(dev_t dev, struct uio *uiop, cred_t *credp) 542*3941Svenki { 543*3941Svenki ds_snmp_state_t *sp; 544*3941Svenki minor_t minor; 545*3941Svenki size_t len; 546*3941Svenki int retval; 547*3941Svenki caddr_t tmpbufp = (caddr_t)NULL; 548*3941Svenki 549*3941Svenki /* 550*3941Svenki * Given that now we can have sc resets happening at any 551*3941Svenki * time, it is possible that it happened since the last time 552*3941Svenki * we issued a read, write or ioctl. If so, we need to wait 553*3941Svenki * for the unreg-reg pair to complete before we can do 554*3941Svenki * anything. 555*3941Svenki */ 556*3941Svenki mutex_enter(&ds_snmp_lock); 557*3941Svenki while (ds_snmp_has_service == B_FALSE) { 558*3941Svenki DS_SNMP_DBG("ds_snmp_read: waiting for service\n"); 559*3941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) { 560*3941Svenki mutex_exit(&ds_snmp_lock); 561*3941Svenki return (EINTR); 562*3941Svenki } 563*3941Svenki } 564*3941Svenki mutex_exit(&ds_snmp_lock); 565*3941Svenki 566*3941Svenki if ((len = uiop->uio_resid) == 0) 567*3941Svenki return (0); 568*3941Svenki 569*3941Svenki minor = getminor(dev); 570*3941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL) 571*3941Svenki return (ENXIO); 572*3941Svenki 573*3941Svenki mutex_enter(&sp->lock); 574*3941Svenki 575*3941Svenki if (sp->sc_reset == B_TRUE) { 576*3941Svenki mutex_exit(&sp->lock); 577*3941Svenki return (ECANCELED); 578*3941Svenki } 579*3941Svenki 580*3941Svenki /* 581*3941Svenki * Block or bail if there is no SNMP data 582*3941Svenki */ 583*3941Svenki if (sp->state != DS_SNMP_DATA_AVL && sp->state != DS_SNMP_DATA_ERR) { 584*3941Svenki DS_SNMP_DBG("ds_snmp_read: no SNMP data\n"); 585*3941Svenki if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) { 586*3941Svenki mutex_exit(&sp->lock); 587*3941Svenki return (EAGAIN); 588*3941Svenki } 589*3941Svenki while (sp->state != DS_SNMP_DATA_AVL && 590*3941Svenki sp->state != DS_SNMP_DATA_ERR) { 591*3941Svenki if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) { 592*3941Svenki mutex_exit(&sp->lock); 593*3941Svenki return (EINTR); 594*3941Svenki } 595*3941Svenki } 596*3941Svenki } 597*3941Svenki 598*3941Svenki /* 599*3941Svenki * If there has been an error, it could be because the agent 600*3941Svenki * returned failure and there is no data to read, or an ldc-reset 601*3941Svenki * has happened. Figure out which and return appropriate 602*3941Svenki * error to the caller. 603*3941Svenki */ 604*3941Svenki if (sp->state == DS_SNMP_DATA_ERR) { 605*3941Svenki if (sp->sc_reset == B_TRUE) { 606*3941Svenki mutex_exit(&sp->lock); 607*3941Svenki DS_SNMP_DBG("ds_snmp_read: sc got reset, " 608*3941Svenki "returning ECANCELED\n"); 609*3941Svenki return (ECANCELED); 610*3941Svenki } else { 611*3941Svenki sp->state = DS_SNMP_READY; 612*3941Svenki cv_broadcast(&sp->state_cv); 613*3941Svenki mutex_exit(&sp->lock); 614*3941Svenki DS_SNMP_DBG("ds_snmp_read: data error, " 615*3941Svenki "returning EIO\n"); 616*3941Svenki return (EIO); 617*3941Svenki } 618*3941Svenki } 619*3941Svenki 620*3941Svenki if (len > sp->data_len) 621*3941Svenki len = sp->data_len; 622*3941Svenki 623*3941Svenki tmpbufp = kmem_alloc(len, KM_SLEEP); 624*3941Svenki 625*3941Svenki bcopy(sp->data, (void *)tmpbufp, len); 626*3941Svenki kmem_free(sp->data, sp->data_len); 627*3941Svenki sp->data = (caddr_t)NULL; 628*3941Svenki sp->data_len = 0; 629*3941Svenki 630*3941Svenki /* 631*3941Svenki * SNMP data has been consumed, wake up anyone waiting to send 632*3941Svenki */ 633*3941Svenki sp->state = DS_SNMP_READY; 634*3941Svenki cv_broadcast(&sp->state_cv); 635*3941Svenki 636*3941Svenki mutex_exit(&sp->lock); 637*3941Svenki 638*3941Svenki retval = uiomove(tmpbufp, len, UIO_READ, uiop); 639*3941Svenki kmem_free(tmpbufp, len); 640*3941Svenki 641*3941Svenki return (retval); 642*3941Svenki } 643*3941Svenki 644*3941Svenki /*ARGSUSED*/ 645*3941Svenki static int 646*3941Svenki ds_snmp_write(dev_t dev, struct uio *uiop, cred_t *credp) 647*3941Svenki { 648*3941Svenki ds_snmp_state_t *sp; 649*3941Svenki ds_snmp_msg_t hdr; 650*3941Svenki minor_t minor; 651*3941Svenki size_t len; 652*3941Svenki caddr_t tmpbufp; 653*3941Svenki 654*3941Svenki /* 655*3941Svenki * Check if there was an sc reset; if yes, wait until we have the 656*3941Svenki * service back again. 657*3941Svenki */ 658*3941Svenki mutex_enter(&ds_snmp_lock); 659*3941Svenki while (ds_snmp_has_service == B_FALSE) { 660*3941Svenki DS_SNMP_DBG("ds_snmp_write: waiting for service\n"); 661*3941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) { 662*3941Svenki mutex_exit(&ds_snmp_lock); 663*3941Svenki return (EINTR); 664*3941Svenki } 665*3941Svenki } 666*3941Svenki mutex_exit(&ds_snmp_lock); 667*3941Svenki 668*3941Svenki minor = getminor(dev); 669*3941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL) 670*3941Svenki return (ENXIO); 671*3941Svenki 672*3941Svenki len = uiop->uio_resid + sizeof (ds_snmp_msg_t); 673*3941Svenki tmpbufp = kmem_alloc(len, KM_SLEEP); 674*3941Svenki 675*3941Svenki if (uiomove(tmpbufp + sizeof (ds_snmp_msg_t), 676*3941Svenki len - sizeof (ds_snmp_msg_t), UIO_WRITE, uiop) != 0) { 677*3941Svenki kmem_free(tmpbufp, len); 678*3941Svenki return (EIO); 679*3941Svenki } 680*3941Svenki 681*3941Svenki mutex_enter(&sp->lock); 682*3941Svenki 683*3941Svenki if (sp->sc_reset == B_TRUE) { 684*3941Svenki mutex_exit(&sp->lock); 685*3941Svenki kmem_free(tmpbufp, len); 686*3941Svenki DS_SNMP_DBG("ds_snmp_write: sc_reset is TRUE, " 687*3941Svenki "returning ECANCELD\n"); 688*3941Svenki return (ECANCELED); 689*3941Svenki } 690*3941Svenki 691*3941Svenki /* 692*3941Svenki * wait if earlier transaction is not yet completed 693*3941Svenki */ 694*3941Svenki while (sp->state != DS_SNMP_READY) { 695*3941Svenki if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) { 696*3941Svenki mutex_exit(&sp->lock); 697*3941Svenki kmem_free(tmpbufp, len); 698*3941Svenki return (EINTR); 699*3941Svenki } 700*3941Svenki /* 701*3941Svenki * Normally, only a reader would ever wake us up. But if we 702*3941Svenki * did get signalled with an ERROR, it could only mean there 703*3941Svenki * was an sc reset and there's no point waiting; we need to 704*3941Svenki * fail this write(). 705*3941Svenki */ 706*3941Svenki if (sp->state == DS_SNMP_DATA_ERR && sp->sc_reset == B_TRUE) { 707*3941Svenki DS_SNMP_DBG("ds_snmp_write: woke up with an sc_reset, " 708*3941Svenki "returning ECANCELED\n"); 709*3941Svenki mutex_exit(&sp->lock); 710*3941Svenki kmem_free(tmpbufp, len); 711*3941Svenki return (ECANCELED); 712*3941Svenki } 713*3941Svenki } 714*3941Svenki 715*3941Svenki if (sp->req_id == (((uint64_t)1 << DS_SNMP_MINOR_SHIFT) - 1)) 716*3941Svenki sp->req_id = 0; /* Reset */ 717*3941Svenki 718*3941Svenki hdr.seq_num = ((uint64_t)minor << DS_SNMP_MINOR_SHIFT) | sp->req_id; 719*3941Svenki sp->last_req_id = hdr.seq_num; 720*3941Svenki (sp->req_id)++; 721*3941Svenki 722*3941Svenki /* 723*3941Svenki * Set state to SNMP_REQUESTED, but don't wakeup anyone yet 724*3941Svenki */ 725*3941Svenki sp->state = DS_SNMP_REQUESTED; 726*3941Svenki 727*3941Svenki mutex_exit(&sp->lock); 728*3941Svenki 729*3941Svenki hdr.type = DS_SNMP_REQUEST; 730*3941Svenki bcopy((void *)&hdr, (void *)tmpbufp, sizeof (hdr)); 731*3941Svenki 732*3941Svenki /* 733*3941Svenki * If the service went away since the time we entered this 734*3941Svenki * routine and now, tough luck. Just ignore the current 735*3941Svenki * write() and return. 736*3941Svenki */ 737*3941Svenki mutex_enter(&ds_snmp_lock); 738*3941Svenki if (ds_snmp_has_service == B_FALSE) { 739*3941Svenki DS_SNMP_DBG("ds_snmp_write: service went away, aborting " 740*3941Svenki "write, returning ECANCELED\n"); 741*3941Svenki mutex_exit(&ds_snmp_lock); 742*3941Svenki kmem_free(tmpbufp, len); 743*3941Svenki return (ECANCELED); 744*3941Svenki } 745*3941Svenki DS_SNMP_DBG("ds_snmp_write: ds_cap_send(0x%lx, %lu) called.\n", 746*3941Svenki ds_snmp_handle, len); 747*3941Svenki (void) ds_cap_send(ds_snmp_handle, tmpbufp, len); 748*3941Svenki mutex_exit(&ds_snmp_lock); 749*3941Svenki 750*3941Svenki kmem_free(tmpbufp, len); 751*3941Svenki 752*3941Svenki return (0); 753*3941Svenki } 754*3941Svenki 755*3941Svenki /*ARGSUSED*/ 756*3941Svenki static int 757*3941Svenki ds_snmp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 758*3941Svenki int *rvalp) 759*3941Svenki { 760*3941Svenki ds_snmp_state_t *sp; 761*3941Svenki struct dssnmp_info info; 762*3941Svenki minor_t minor; 763*3941Svenki 764*3941Svenki /* 765*3941Svenki * Check if there was an sc reset; if yes, wait until we have the 766*3941Svenki * service back again. 767*3941Svenki */ 768*3941Svenki mutex_enter(&ds_snmp_lock); 769*3941Svenki while (ds_snmp_has_service == B_FALSE) { 770*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: waiting for service\n"); 771*3941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) { 772*3941Svenki mutex_exit(&ds_snmp_lock); 773*3941Svenki return (EINTR); 774*3941Svenki } 775*3941Svenki } 776*3941Svenki mutex_exit(&ds_snmp_lock); 777*3941Svenki 778*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: hdl=0x%lx\n", ds_snmp_handle); 779*3941Svenki 780*3941Svenki minor = getminor(dev); 781*3941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL) 782*3941Svenki return (ENXIO); 783*3941Svenki 784*3941Svenki if (!(mode & FREAD)) 785*3941Svenki return (EACCES); 786*3941Svenki 787*3941Svenki switch (cmd) { 788*3941Svenki case DSSNMP_GETINFO: 789*3941Svenki mutex_enter(&sp->lock); 790*3941Svenki 791*3941Svenki if (sp->sc_reset == B_TRUE) { 792*3941Svenki mutex_exit(&sp->lock); 793*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: returning ECANCELED\n"); 794*3941Svenki return (ECANCELED); 795*3941Svenki } 796*3941Svenki 797*3941Svenki while (sp->state != DS_SNMP_DATA_AVL && 798*3941Svenki sp->state != DS_SNMP_DATA_ERR) { 799*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, " 800*3941Svenki "waiting for data\n", sp->state, sp->sc_reset); 801*3941Svenki if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) { 802*3941Svenki mutex_exit(&sp->lock); 803*3941Svenki return (EINTR); 804*3941Svenki } 805*3941Svenki } 806*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, " 807*3941Svenki "out of wait!\n", sp->state, sp->sc_reset); 808*3941Svenki 809*3941Svenki /* 810*3941Svenki * If there has been an error, it could be because the 811*3941Svenki * agent returned failure and there is no data to read, 812*3941Svenki * or an ldc-reset has happened. Figure out which and 813*3941Svenki * return appropriate error to the caller. 814*3941Svenki */ 815*3941Svenki if (sp->state == DS_SNMP_DATA_ERR) { 816*3941Svenki if (sp->sc_reset == B_TRUE) { 817*3941Svenki mutex_exit(&sp->lock); 818*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=TRUE " 819*3941Svenki "returning ECANCELED\n"); 820*3941Svenki return (ECANCELED); 821*3941Svenki } else { 822*3941Svenki sp->state = DS_SNMP_READY; 823*3941Svenki cv_broadcast(&sp->state_cv); 824*3941Svenki mutex_exit(&sp->lock); 825*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=FALSE " 826*3941Svenki "returning EIO\n"); 827*3941Svenki return (EIO); 828*3941Svenki } 829*3941Svenki } 830*3941Svenki 831*3941Svenki info.size = sp->data_len; 832*3941Svenki info.token = sp->gencount; 833*3941Svenki 834*3941Svenki mutex_exit(&sp->lock); 835*3941Svenki 836*3941Svenki if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0) 837*3941Svenki return (EFAULT); 838*3941Svenki break; 839*3941Svenki 840*3941Svenki case DSSNMP_CLRLNKRESET: 841*3941Svenki mutex_enter(&sp->lock); 842*3941Svenki 843*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: DSSNMP_CLRLNKRESET\n"); 844*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=%d\n", sp->sc_reset); 845*3941Svenki 846*3941Svenki if (sp->sc_reset == B_TRUE) { 847*3941Svenki if (sp->data) { 848*3941Svenki DS_SNMP_DBG("ds_snmp_ioctl: data=%p, len=%lu\n", 849*3941Svenki sp->data, sp->data_len); 850*3941Svenki kmem_free(sp->data, sp->data_len); 851*3941Svenki } 852*3941Svenki sp->data = NULL; 853*3941Svenki sp->data_len = 0; 854*3941Svenki sp->state = DS_SNMP_READY; 855*3941Svenki sp->req_id = 0; 856*3941Svenki sp->last_req_id = 0; 857*3941Svenki sp->sc_reset = B_FALSE; 858*3941Svenki } 859*3941Svenki mutex_exit(&sp->lock); 860*3941Svenki break; 861*3941Svenki 862*3941Svenki default: 863*3941Svenki return (ENOTTY); 864*3941Svenki } 865*3941Svenki 866*3941Svenki return (0); 867*3941Svenki } 868*3941Svenki 869*3941Svenki /* 870*3941Svenki * DS Callbacks 871*3941Svenki */ 872*3941Svenki /*ARGSUSED*/ 873*3941Svenki static void 874*3941Svenki ds_snmp_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 875*3941Svenki { 876*3941Svenki DS_SNMP_DBG("ds_snmp_reg_handler: registering handle 0x%lx for version " 877*3941Svenki "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor); 878*3941Svenki 879*3941Svenki mutex_enter(&ds_snmp_lock); 880*3941Svenki 881*3941Svenki ASSERT(ds_snmp_handle == DS_INVALID_HDL); 882*3941Svenki 883*3941Svenki ds_snmp_handle = hdl; 884*3941Svenki ds_snmp_has_service = B_TRUE; 885*3941Svenki 886*3941Svenki cv_broadcast(&ds_snmp_service_cv); 887*3941Svenki 888*3941Svenki mutex_exit(&ds_snmp_lock); 889*3941Svenki 890*3941Svenki } 891*3941Svenki 892*3941Svenki /*ARGSUSED*/ 893*3941Svenki static void 894*3941Svenki ds_snmp_unreg_handler(ds_cb_arg_t arg) 895*3941Svenki { 896*3941Svenki minor_t minor; 897*3941Svenki ds_snmp_state_t *sp; 898*3941Svenki 899*3941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: un-registering ds_snmp service\n"); 900*3941Svenki 901*3941Svenki mutex_enter(&ds_snmp_lock); 902*3941Svenki 903*3941Svenki if (ds_snmp_num_opens) { 904*3941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: %d opens, sc reset!\n", 905*3941Svenki ds_snmp_num_opens); 906*3941Svenki for (minor = 1; minor <= DS_SNMP_MAX_OPENS; minor++) { 907*3941Svenki if (ds_snmp_is_open(minor)) { 908*3941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: minor %d " 909*3941Svenki "open\n", minor); 910*3941Svenki sp = ddi_get_soft_state(ds_snmp_statep, minor); 911*3941Svenki if (sp == NULL) 912*3941Svenki continue; 913*3941Svenki 914*3941Svenki /* 915*3941Svenki * Set the sc_reset flag and break any waiters 916*3941Svenki * out of their existing reads/writes/ioctls. 917*3941Svenki */ 918*3941Svenki DS_SNMP_DBG("ds_snmp_unreg_hdlr: about to " 919*3941Svenki "signal waiters\n"); 920*3941Svenki mutex_enter(&sp->lock); 921*3941Svenki sp->sc_reset = B_TRUE; 922*3941Svenki sp->state = DS_SNMP_DATA_ERR; 923*3941Svenki cv_broadcast(&sp->state_cv); 924*3941Svenki mutex_exit(&sp->lock); 925*3941Svenki } 926*3941Svenki } 927*3941Svenki } 928*3941Svenki 929*3941Svenki ds_snmp_handle = DS_INVALID_HDL; 930*3941Svenki ds_snmp_has_service = B_FALSE; 931*3941Svenki 932*3941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: handle invalidated\n"); 933*3941Svenki 934*3941Svenki mutex_exit(&ds_snmp_lock); 935*3941Svenki } 936*3941Svenki 937*3941Svenki /*ARGSUSED*/ 938*3941Svenki static void 939*3941Svenki ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 940*3941Svenki { 941*3941Svenki ds_snmp_state_t *sp; 942*3941Svenki ds_snmp_msg_t hdr; 943*3941Svenki size_t snmp_size; 944*3941Svenki minor_t minor; 945*3941Svenki 946*3941Svenki /* 947*3941Svenki * Make sure the header is at least valid 948*3941Svenki */ 949*3941Svenki if (buflen < sizeof (hdr)) { 950*3941Svenki cmn_err(CE_WARN, 951*3941Svenki "ds_snmp_data_handler: buflen <%lu> too small", buflen); 952*3941Svenki return; 953*3941Svenki } 954*3941Svenki 955*3941Svenki ASSERT(buf != NULL); 956*3941Svenki bcopy(buf, (void *)&hdr, sizeof (hdr)); 957*3941Svenki 958*3941Svenki DS_SNMP_DBG("ds_snmp_data_handler: msg buf len 0x%lx : type 0x%lx, " 959*3941Svenki "seqn 0x%lx\n", buflen, hdr.type, hdr.seq_num); 960*3941Svenki 961*3941Svenki minor = (int)(hdr.seq_num >> DS_SNMP_MINOR_SHIFT); 962*3941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL) 963*3941Svenki return; 964*3941Svenki 965*3941Svenki mutex_enter(&sp->lock); 966*3941Svenki 967*3941Svenki /* 968*3941Svenki * If there is no pending SNMP request, then we've received 969*3941Svenki * bogus data or an SNMP trap. Since we don't yet support SNMP 970*3941Svenki * traps, ignore it. 971*3941Svenki */ 972*3941Svenki if (sp->state != DS_SNMP_REQUESTED) { 973*3941Svenki cmn_err(CE_WARN, "Received SNMP data without request"); 974*3941Svenki mutex_exit(&sp->lock); 975*3941Svenki return; 976*3941Svenki } 977*3941Svenki 978*3941Svenki /* 979*3941Svenki * Response to a request therefore old SNMP must've been consumed 980*3941Svenki */ 981*3941Svenki ASSERT(sp->data_len == 0); 982*3941Svenki ASSERT(sp->data == NULL); 983*3941Svenki 984*3941Svenki /* 985*3941Svenki * Response seq_num should match our request seq_num 986*3941Svenki */ 987*3941Svenki if (hdr.seq_num != sp->last_req_id) { 988*3941Svenki cmn_err(CE_WARN, "Received DS snmp data out of sequence with " 989*3941Svenki "request"); 990*3941Svenki mutex_exit(&sp->lock); 991*3941Svenki return; 992*3941Svenki } 993*3941Svenki 994*3941Svenki if (hdr.type == DS_SNMP_ERROR) { 995*3941Svenki sp->state = DS_SNMP_DATA_ERR; 996*3941Svenki DS_SNMP_DBG("ds_snmp_data_handler: hdr.type = DS_SNMP_ERROR\n"); 997*3941Svenki } else { 998*3941Svenki snmp_size = buflen - sizeof (ds_snmp_msg_t); 999*3941Svenki sp->data = kmem_alloc(snmp_size, KM_SLEEP); 1000*3941Svenki sp->data_len = snmp_size; 1001*3941Svenki sp->state = DS_SNMP_DATA_AVL; 1002*3941Svenki 1003*3941Svenki bcopy((caddr_t)buf + sizeof (ds_snmp_msg_t), 1004*3941Svenki sp->data, sp->data_len); 1005*3941Svenki } 1006*3941Svenki 1007*3941Svenki sp->gencount++; 1008*3941Svenki 1009*3941Svenki /* 1010*3941Svenki * Wake up any readers waiting for data 1011*3941Svenki */ 1012*3941Svenki cv_broadcast(&sp->state_cv); 1013*3941Svenki mutex_exit(&sp->lock); 1014*3941Svenki } 1015