Print this page
Reduce lint
OS-3878 The pseudo nexus should be FMA capable
OS-3881 pseudonex_detach does not properly check the detach command
Reviewed by: Joshua M. Clulow <josh@sysmgr.org>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>


  66 #include <sys/instance.h>
  67 #include <sys/modctl.h>
  68 #include <sys/open.h>
  69 #include <sys/stat.h>
  70 #include <sys/sunddi.h>
  71 #include <sys/sunndi.h>
  72 #include <sys/systm.h>
  73 #include <sys/mkdev.h>
  74 
  75 /*
  76  * Config information
  77  */
  78 static int pseudonex_intr_op(dev_info_t *dip, dev_info_t *rdip,
  79             ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result);
  80 
  81 static int pseudonex_attach(dev_info_t *, ddi_attach_cmd_t);
  82 static int pseudonex_detach(dev_info_t *, ddi_detach_cmd_t);
  83 static int pseudonex_open(dev_t *, int, int, cred_t *);
  84 static int pseudonex_close(dev_t, int, int, cred_t *);
  85 static int pseudonex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);


  86 static int pseudonex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
  87     void *);
  88 
  89 static void *pseudonex_state;
  90 
  91 typedef struct pseudonex_state {
  92         dev_info_t *pnx_devi;


  93 } pseudonex_state_t;
  94 
  95 static struct bus_ops pseudonex_bus_ops = {
  96         BUSO_REV,
  97         nullbusmap,             /* bus_map */
  98         NULL,                   /* bus_get_intrspec */
  99         NULL,                   /* bus_add_intrspec */
 100         NULL,                   /* bus_remove_intrspec */
 101         i_ddi_map_fault,        /* bus_map_fault */
 102         ddi_no_dma_map,         /* bus_dma_map */
 103         ddi_no_dma_allochdl,    /* bus_dma_allochdl */
 104         NULL,                   /* bus_dma_freehdl */
 105         NULL,                   /* bus_dma_bindhdl */
 106         NULL,                   /* bus_dma_unbindhdl */
 107         NULL,                   /* bus_dma_flush */
 108         NULL,                   /* bus_dma_win */
 109         NULL,                   /* bus_dma_ctl */
 110         pseudonex_ctl,          /* bus_ctl */
 111         ddi_bus_prop_op,        /* bus_prop_op */
 112         0,                      /* bus_get_eventcookie */
 113         0,                      /* bus_add_eventcall */
 114         0,                      /* bus_remove_eventcall */
 115         0,                      /* bus_post_event */
 116         NULL,                   /* bus_intr_ctl */
 117         NULL,                   /* bus_config */
 118         NULL,                   /* bus_unconfig */
 119         NULL,                   /* bus_fm_init */
 120         NULL,                   /* bus_fm_fini */
 121         NULL,                   /* bus_fm_access_enter */
 122         NULL,                   /* bus_fm_access_exit */
 123         NULL,                   /* bus_power */
 124         pseudonex_intr_op       /* bus_intr_op */
 125 };
 126 
 127 static struct cb_ops pseudonex_cb_ops = {
 128         pseudonex_open,                 /* open */
 129         pseudonex_close,                /* close */
 130         nodev,                          /* strategy */
 131         nodev,                          /* print */
 132         nodev,                          /* dump */
 133         nodev,                          /* read */
 134         nodev,                          /* write */
 135         pseudonex_ioctl,                /* ioctl */
 136         nodev,                          /* devmap */
 137         nodev,                          /* mmap */
 138         nodev,                          /* segmap */
 139         nochpoll,                       /* poll */


 211         pseudonex_state_t *pnx_state;
 212 
 213         switch (cmd) {
 214         case DDI_ATTACH:
 215                 break;
 216         case DDI_RESUME:
 217                 return (DDI_SUCCESS);
 218         default:
 219                 return (DDI_FAILURE);
 220         }
 221 
 222         /*
 223          * Save the devi for this instance in the soft_state data.
 224          */
 225         instance = ddi_get_instance(devi);
 226         if (ddi_soft_state_zalloc(pseudonex_state, instance) != DDI_SUCCESS)
 227                 return (DDI_FAILURE);
 228         pnx_state = ddi_get_soft_state(pseudonex_state, instance);
 229         pnx_state->pnx_devi = devi;
 230 



 231         if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
 232             DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
 233                 ddi_remove_minor_node(devi, NULL);
 234                 ddi_soft_state_free(pseudonex_state, instance);
 235                 return (DDI_FAILURE);
 236         }
 237         ddi_report_dev(devi);
 238         return (DDI_SUCCESS);
 239 }
 240 
 241 /*ARGSUSED*/
 242 static int
 243 pseudonex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 244 {
 245         int instance = ddi_get_instance(devi);
 246 
 247         if (cmd == DDI_SUSPEND)
 248                 return (DDI_SUCCESS);
 249 




 250         ddi_remove_minor_node(devi, NULL);
 251         ddi_soft_state_free(pseudonex_state, instance);
 252         return (DDI_SUCCESS);
 253 }
 254 
 255 /*ARGSUSED*/
 256 static int
 257 pseudonex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 258 {
 259         int instance;
 260 
 261         if (otyp != OTYP_CHR)
 262                 return (EINVAL);
 263 
 264         instance = getminor(*devp);
 265         if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
 266                 return (ENXIO);
 267 
 268         return (0);
 269 }


 357         LOCK_DEV_OPS(dmp);
 358         for (inst = 0; inst <= MAXMIN32; inst++) {
 359                 for (tdip = devnamesp[childmaj].dn_head; tdip != NULL;
 360                     tdip = ddi_get_next(tdip)) {
 361                         /* is this the current node? */
 362                         if (tdip == child)
 363                                 continue;
 364                         if (inst == ddi_get_instance(tdip)) {
 365                                 break;
 366                         }
 367                 }
 368                 if (tdip == NULL) {
 369                         UNLOCK_DEV_OPS(dmp);
 370                         return (inst);
 371                 }
 372         }
 373         UNLOCK_DEV_OPS(dmp);
 374         return (-1);
 375 }
 376 














 377 static int
 378 pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
 379     void *arg, void *result)
 380 {
 381         switch (ctlop) {
 382         case DDI_CTLOPS_REPORTDEV:
 383                 if (rdip == NULL)
 384                         return (DDI_FAILURE);
 385                 cmn_err(CE_CONT, "?pseudo-device: %s%d\n",
 386                     ddi_driver_name(rdip), ddi_get_instance(rdip));
 387                 return (DDI_SUCCESS);
 388 
 389         case DDI_CTLOPS_INITCHILD:
 390         {
 391                 char name[12];  /* enough for a decimal integer */
 392                 int instance = -1;
 393                 dev_info_t *child = (dev_info_t *)arg;
 394                 const char *childname = ddi_driver_name(child);
 395                 char **childlist;
 396                 uint_t nelems;




  66 #include <sys/instance.h>
  67 #include <sys/modctl.h>
  68 #include <sys/open.h>
  69 #include <sys/stat.h>
  70 #include <sys/sunddi.h>
  71 #include <sys/sunndi.h>
  72 #include <sys/systm.h>
  73 #include <sys/mkdev.h>
  74 
  75 /*
  76  * Config information
  77  */
  78 static int pseudonex_intr_op(dev_info_t *dip, dev_info_t *rdip,
  79             ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result);
  80 
  81 static int pseudonex_attach(dev_info_t *, ddi_attach_cmd_t);
  82 static int pseudonex_detach(dev_info_t *, ddi_detach_cmd_t);
  83 static int pseudonex_open(dev_t *, int, int, cred_t *);
  84 static int pseudonex_close(dev_t, int, int, cred_t *);
  85 static int pseudonex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  86 static int pseudonex_fm_init(dev_info_t *, dev_info_t *, int,
  87     ddi_iblock_cookie_t *);
  88 static int pseudonex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
  89     void *);
  90 
  91 static void *pseudonex_state;
  92 
  93 typedef struct pseudonex_state {
  94         dev_info_t *pnx_devi;
  95         int pnx_fmcap;
  96         ddi_iblock_cookie_t pnx_fm_ibc;
  97 } pseudonex_state_t;
  98 
  99 static struct bus_ops pseudonex_bus_ops = {
 100         BUSO_REV,
 101         nullbusmap,             /* bus_map */
 102         NULL,                   /* bus_get_intrspec */
 103         NULL,                   /* bus_add_intrspec */
 104         NULL,                   /* bus_remove_intrspec */
 105         i_ddi_map_fault,        /* bus_map_fault */
 106         ddi_no_dma_map,         /* bus_dma_map */
 107         ddi_no_dma_allochdl,    /* bus_dma_allochdl */
 108         NULL,                   /* bus_dma_freehdl */
 109         NULL,                   /* bus_dma_bindhdl */
 110         NULL,                   /* bus_dma_unbindhdl */
 111         NULL,                   /* bus_dma_flush */
 112         NULL,                   /* bus_dma_win */
 113         NULL,                   /* bus_dma_ctl */
 114         pseudonex_ctl,          /* bus_ctl */
 115         ddi_bus_prop_op,        /* bus_prop_op */
 116         0,                      /* bus_get_eventcookie */
 117         0,                      /* bus_add_eventcall */
 118         0,                      /* bus_remove_eventcall */
 119         0,                      /* bus_post_event */
 120         NULL,                   /* bus_intr_ctl */
 121         NULL,                   /* bus_config */
 122         NULL,                   /* bus_unconfig */
 123         pseudonex_fm_init,      /* bus_fm_init */
 124         NULL,                   /* bus_fm_fini */
 125         NULL,                   /* bus_fm_access_enter */
 126         NULL,                   /* bus_fm_access_exit */
 127         NULL,                   /* bus_power */
 128         pseudonex_intr_op       /* bus_intr_op */
 129 };
 130 
 131 static struct cb_ops pseudonex_cb_ops = {
 132         pseudonex_open,                 /* open */
 133         pseudonex_close,                /* close */
 134         nodev,                          /* strategy */
 135         nodev,                          /* print */
 136         nodev,                          /* dump */
 137         nodev,                          /* read */
 138         nodev,                          /* write */
 139         pseudonex_ioctl,                /* ioctl */
 140         nodev,                          /* devmap */
 141         nodev,                          /* mmap */
 142         nodev,                          /* segmap */
 143         nochpoll,                       /* poll */


 215         pseudonex_state_t *pnx_state;
 216 
 217         switch (cmd) {
 218         case DDI_ATTACH:
 219                 break;
 220         case DDI_RESUME:
 221                 return (DDI_SUCCESS);
 222         default:
 223                 return (DDI_FAILURE);
 224         }
 225 
 226         /*
 227          * Save the devi for this instance in the soft_state data.
 228          */
 229         instance = ddi_get_instance(devi);
 230         if (ddi_soft_state_zalloc(pseudonex_state, instance) != DDI_SUCCESS)
 231                 return (DDI_FAILURE);
 232         pnx_state = ddi_get_soft_state(pseudonex_state, instance);
 233         pnx_state->pnx_devi = devi;
 234 
 235         pnx_state->pnx_fmcap = DDI_FM_EREPORT_CAPABLE;
 236         ddi_fm_init(devi, &pnx_state->pnx_fmcap, &pnx_state->pnx_fm_ibc);
 237 
 238         if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
 239             DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
 240                 ddi_remove_minor_node(devi, NULL);
 241                 ddi_soft_state_free(pseudonex_state, instance);
 242                 return (DDI_FAILURE);
 243         }
 244         ddi_report_dev(devi);
 245         return (DDI_SUCCESS);
 246 }
 247 
 248 /*ARGSUSED*/
 249 static int
 250 pseudonex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 251 {
 252         int instance = ddi_get_instance(devi);
 253 
 254         if (cmd == DDI_SUSPEND)
 255                 return (DDI_SUCCESS);
 256 
 257         if (cmd != DDI_DETACH)
 258                 return (DDI_FAILURE);
 259 
 260         ddi_fm_fini(devi);
 261         ddi_remove_minor_node(devi, NULL);
 262         ddi_soft_state_free(pseudonex_state, instance);
 263         return (DDI_SUCCESS);
 264 }
 265 
 266 /*ARGSUSED*/
 267 static int
 268 pseudonex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
 269 {
 270         int instance;
 271 
 272         if (otyp != OTYP_CHR)
 273                 return (EINVAL);
 274 
 275         instance = getminor(*devp);
 276         if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
 277                 return (ENXIO);
 278 
 279         return (0);
 280 }


 368         LOCK_DEV_OPS(dmp);
 369         for (inst = 0; inst <= MAXMIN32; inst++) {
 370                 for (tdip = devnamesp[childmaj].dn_head; tdip != NULL;
 371                     tdip = ddi_get_next(tdip)) {
 372                         /* is this the current node? */
 373                         if (tdip == child)
 374                                 continue;
 375                         if (inst == ddi_get_instance(tdip)) {
 376                                 break;
 377                         }
 378                 }
 379                 if (tdip == NULL) {
 380                         UNLOCK_DEV_OPS(dmp);
 381                         return (inst);
 382                 }
 383         }
 384         UNLOCK_DEV_OPS(dmp);
 385         return (-1);
 386 }
 387 
 388 /* ARGSUSED */
 389 static int
 390 pseudonex_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap,
 391     ddi_iblock_cookie_t *ibc)
 392 {
 393         pseudonex_state_t *pnx_state;
 394 
 395         pnx_state = ddi_get_soft_state(pseudonex_state, ddi_get_instance(dip));
 396         ASSERT(pnx_state != NULL);
 397         ASSERT(ibc != NULL);
 398         *ibc = pnx_state->pnx_fm_ibc;
 399         return (pnx_state->pnx_fmcap & cap);
 400 }
 401 
 402 static int
 403 pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
 404     void *arg, void *result)
 405 {
 406         switch (ctlop) {
 407         case DDI_CTLOPS_REPORTDEV:
 408                 if (rdip == NULL)
 409                         return (DDI_FAILURE);
 410                 cmn_err(CE_CONT, "?pseudo-device: %s%d\n",
 411                     ddi_driver_name(rdip), ddi_get_instance(rdip));
 412                 return (DDI_SUCCESS);
 413 
 414         case DDI_CTLOPS_INITCHILD:
 415         {
 416                 char name[12];  /* enough for a decimal integer */
 417                 int instance = -1;
 418                 dev_info_t *child = (dev_info_t *)arg;
 419                 const char *childname = ddi_driver_name(child);
 420                 char **childlist;
 421                 uint_t nelems;