/* * vdds_match_niu_node -- callback function to verify a node is the * NIU Hybrid node. */ static int vdds_match_niu_node(dev_info_t *dip, void *arg) { vdds_cb_arg_t *warg = (vdds_cb_arg_t *)arg; char *name; vdds_reg_t *reg_p; uint_t reglen; int rv; uint32_t addr_hi; name = ddi_node_name(dip); if (strcmp(name, "network") != 0) { return (DDI_WALK_CONTINUE); } rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len); if (rv != DDI_PROP_SUCCESS) { DWARN(NULL, "Failed to get reg property dip=0x%p", dip); return (DDI_WALK_CONTINUE); } addr_hi = reg_p->addr_hi; DBG1(NULL, "addr_hi = 0x%x dip=0x%p", addr_hi, dip); ddi_prop_free(reg_p); if (addr_hi == HVCOOKIE(warg->cookie)) { warg->dip = dip; if (!e_ddi_branch_held(dip)) e_ddi_branch_hold(dip); DBG1(NULL, "Found dip = 0x%p", dip); return (DDI_WALK_TERMINATE); } return (DDI_WALK_CONTINUE); }
static int dr_check_io_refs(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) { register int i, reftotal = 0; static fn_t f = "dr_check_io_refs"; for (i = 0; i < devnum; i++) { dr_io_unit_t *ip = (dr_io_unit_t *)devlist[i]; dev_info_t *dip; int ref; sbd_error_t *err; err = drmach_get_dip(ip->sbi_cm.sbdev_id, &dip); if (err) DRERR_SET_C(&ip->sbi_cm.sbdev_error, &err); else if (dip != NULL) { ref = 0; ASSERT(e_ddi_branch_held(dip)); dr_check_devices(dip, &ref, hp, NULL, NULL, 0); hp->h_err = NULL; if (ref) { dr_dev_err(CE_WARN, &ip->sbi_cm, ESBD_BUSY); } PR_IO("%s: dip(%s) ref = %d\n", f, ddi_get_name(dip), ref); reftotal += ref; } else { PR_IO("%s: NO dip for id (0x%x)\n", f, (uint_t)(uintptr_t)ip->sbi_cm.sbdev_id); } } return (reftotal); }
void sbdp_check_devices(dev_info_t *dip, int *refcount, sbd_error_t *sep) { sbdp_ref_t sbr; sbr.refcount = refcount; sbr.sep = sep; ASSERT(e_ddi_branch_held(dip)); (void) e_ddi_branch_referenced(dip, sbdp_check_dip, &sbr); }
/*ARGSUSED*/ void sbd_attach_io(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) { sbd_board_t *sbp = SBDH2BD(hp->h_sbd); ASSERT(e_ddi_branch_held(dip)); (void) e_ddi_branch_configure(dip, NULL, 0); ASSERT(sbp->sb_iopath[unit] != NULL); (void) ddi_pathname(dip, sbp->sb_iopath[unit]); }
/*ARGSUSED*/ void dr_check_devices(dev_info_t *dip, int *refcount, dr_handle_t *handle, uint64_t *arr, int *idx, int len) { struct dr_ref bref = {0}; if (dip == NULL) return; bref.refcount = refcount; bref.arr = arr; bref.idx = idx; bref.len = len; ASSERT(e_ddi_branch_held(dip)); (void) e_ddi_branch_referenced(dip, dr_check_dip, &bref); }
/* * vdds_destroy_niu_node -- Destroy the NIU node. */ int vdds_destroy_niu_node(dev_info_t *niu_dip, uint64_t cookie) { int rv; dev_info_t *fdip = NULL; dev_info_t *nexus_dip = ddi_get_parent(niu_dip); DBG1(NULL, "Called"); ASSERT(nexus_dip != NULL); mutex_enter(&vdds_dev_lock); if (!e_ddi_branch_held(niu_dip)) e_ddi_branch_hold(niu_dip); /* * As we are destroying now, release the * hold that was done in during the creation. */ ddi_release_devi(niu_dip); rv = e_ddi_branch_destroy(niu_dip, &fdip, 0); if (rv != 0) { DERR(NULL, "Failed to destroy niumx/network node dip=0x%p", niu_dip); if (fdip != NULL) { ddi_release_devi(fdip); } rv = EBUSY; goto dest_exit; } /* * Cleanup the parent's ranges property set * for this Hybrid device. */ vdds_release_range_prop(nexus_dip, cookie); dest_exit: mutex_exit(&vdds_dev_lock); DBG1(NULL, "returning rv=%d", rv); return (rv); }
/* * vdds_match_niu_nexus -- callback function to verify a node is the * NIU nexus node. */ static int vdds_match_niu_nexus(dev_info_t *dip, void *arg) { vdds_cb_arg_t *warg = (vdds_cb_arg_t *)arg; vdds_reg_t *reg_p; char *name; uint64_t hdl; uint_t reglen; int rv; if (dip == ddi_root_node()) { return (DDI_WALK_CONTINUE); } name = ddi_node_name(dip); if (strcmp(name, "niu") != 0) { return (DDI_WALK_CONTINUE); } rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len); if (rv != DDI_PROP_SUCCESS) { DWARN(NULL, "Failed to get reg property dip=0x%p", dip); return (DDI_WALK_CONTINUE); } hdl = reg_p->addr_hi & 0x0FFFFFFF; ddi_prop_free(reg_p); DBG2(NULL, "Handle = 0x%lx dip=0x%p", hdl, dip); if (hdl == NIUCFGHDL(warg->cookie)) { /* Hold before returning */ if (!e_ddi_branch_held(dip)) e_ddi_branch_hold(dip); warg->dip = dip; DBG2(NULL, "Found dip = 0x%p", dip); return (DDI_WALK_TERMINATE); } return (DDI_WALK_CONTINUE); }
/*ARGSUSED*/ void sbd_detach_io(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) { int rv; dev_info_t *fdip = NULL; sbd_board_t *sbp = SBDH2BD(hp->h_sbd); ASSERT(e_ddi_branch_held(dip)); mutex_enter(&sbp->sb_slock); rv = e_ddi_branch_unconfigure(dip, &fdip, DEVI_BRANCH_EVENT); mutex_exit(&sbp->sb_slock); if (rv) { /* * If non-NULL, fdip is returned held and must be released. */ if (fdip != NULL) { sbd_errno_decode(rv, ep, fdip); ddi_release_devi(fdip); } else { sbd_errno_decode(rv, ep, dip); } } }
/* * vdds_create_niu_node -- Create NIU Hybrid node. The NIU nexus * node also created if it doesn't exist already. */ dev_info_t * vdds_create_niu_node(uint64_t cookie, uint64_t macaddr, uint32_t max_frame_size) { dev_info_t *nexus_dip; dev_info_t *niu_dip; vdds_cb_arg_t cba; DBG1(NULL, "Called"); if (vdds_hv_hio_capable == B_FALSE) { return (NULL); } mutex_enter(&vdds_dev_lock); /* Check if the nexus node exists already */ nexus_dip = vdds_find_node(cookie, ddi_root_node(), vdds_match_niu_nexus); if (nexus_dip == NULL) { /* * NIU nexus node not found, so create it now. */ cba.dip = NULL; cba.cookie = cookie; cba.macaddr = macaddr; cba.max_frame_size = max_frame_size; nexus_dip = vdds_create_new_node(&cba, NULL, vdds_new_nexus_node); if (nexus_dip == NULL) { mutex_exit(&vdds_dev_lock); return (NULL); } } DBG2(NULL, "nexus_dip = 0x%p", nexus_dip); /* Check if NIU node exists already before creating one */ niu_dip = vdds_find_node(cookie, nexus_dip, vdds_match_niu_node); if (niu_dip == NULL) { cba.dip = NULL; cba.cookie = cookie; cba.macaddr = macaddr; cba.max_frame_size = max_frame_size; niu_dip = vdds_create_new_node(&cba, nexus_dip, vdds_new_niu_node); /* * Hold the niu_dip to prevent it from * detaching. */ if (niu_dip != NULL) { e_ddi_hold_devi(niu_dip); } else { DWARN(NULL, "niumx/network node creation failed"); } } else { DWARN(NULL, "niumx/network node already exists(dip=0x%p)", niu_dip); } /* release the hold that was done in find/create */ if ((niu_dip != NULL) && (e_ddi_branch_held(niu_dip))) e_ddi_branch_rele(niu_dip); if (e_ddi_branch_held(nexus_dip)) e_ddi_branch_rele(nexus_dip); mutex_exit(&vdds_dev_lock); DBG1(NULL, "returning niu_dip=0x%p", niu_dip); return (niu_dip); }
int dr_io_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) { int i, ix; dr_board_t *bp; sbd_io_stat_t *isp; dr_io_unit_t *ip; bp = hp->h_bd; /* * Only look for requested devices that are actually present. */ devset &= DR_DEVS_PRESENT(bp); for (i = ix = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { drmachid_t id; dev_info_t *dip; sbd_error_t *err; drmach_status_t pstat; if (DEVSET_IN_SET(devset, SBD_COMP_IO, i) == 0) continue; ip = dr_get_io_unit(bp, i); if (ip->sbi_cm.sbdev_state == DR_STATE_EMPTY) { /* present, but not fully initialized */ continue; } id = ip->sbi_cm.sbdev_id; if (id == (drmachid_t)0) continue; err = drmach_status(ip->sbi_cm.sbdev_id, &pstat); if (err) { DRERR_SET_C(&ip->sbi_cm.sbdev_error, &err); return (-1); } dip = NULL; err = drmach_get_dip(id, &dip); if (err) { /* catch this in debug kernels */ ASSERT(0); sbd_err_clear(&err); continue; } isp = &dsp->d_io; bzero((caddr_t)isp, sizeof (*isp)); isp->is_cm.c_id.c_type = ip->sbi_cm.sbdev_type; isp->is_cm.c_id.c_unit = ip->sbi_cm.sbdev_unum; strncpy(isp->is_cm.c_id.c_name, pstat.type, sizeof (isp->is_cm.c_id.c_name)); dr_get_comp_cond(ip, dip); isp->is_cm.c_cond = ip->sbi_cm.sbdev_cond; isp->is_cm.c_busy = ip->sbi_cm.sbdev_busy | pstat.busy; isp->is_cm.c_time = ip->sbi_cm.sbdev_time; isp->is_cm.c_ostate = ip->sbi_cm.sbdev_ostate; isp->is_cm.c_sflags = 0; if (dip == NULL) { isp->is_pathname[0] = '\0'; isp->is_referenced = 0; isp->is_unsafe_count = 0; } else { int refcount = 0, idx = 0; uint64_t unsafe_devs[SBD_MAX_UNSAFE]; ASSERT(e_ddi_branch_held(dip)); (void) ddi_pathname(dip, isp->is_pathname); /* check reference and unsafe counts on devices */ isp->is_unsafe_count = 0; dr_check_devices(dip, &refcount, hp, unsafe_devs, &idx, SBD_MAX_UNSAFE); while (idx > 0) { isp->is_unsafe_list[idx-1] = unsafe_devs[idx-1]; --idx; } isp->is_referenced = (refcount == 0) ? 0 : 1; hp->h_err = NULL; } ix++; dsp++; } return (ix); }