static void dr_resume_devices(dev_info_t *start, dr_sr_handle_t *srh) { dr_handle_t *handle; dev_info_t *dip, *next, *last = NULL; major_t major; char *bn; int circ; major = (major_t)-1; /* attach in reverse device tree order */ while (last != start) { dip = start; next = ddi_get_next_sibling(dip); while (next != last && dip != srh->sr_failed_dip) { dip = next; next = ddi_get_next_sibling(dip); } if (dip == srh->sr_failed_dip) { /* release hold acquired in dr_suspend_devices() */ srh->sr_failed_dip = NULL; ndi_rele_devi(dip); } else if (dr_is_real_device(dip) && srh->sr_failed_dip == NULL) { if ((bn = ddi_binding_name(dip)) != NULL) { major = ddi_name_to_major(bn); } else { bn = "<null>"; } if (!dr_bypass_device(bn) && !drmach_verify_sr(dip, 0)) { char d_name[40], d_alias[40], *d_info; d_name[0] = 0; d_info = ddi_get_name_addr(dip); if (d_info == NULL) d_info = "<null>"; if (!dr_resolve_devname(dip, d_name, d_alias)) { if (d_alias[0] != 0) { prom_printf("\tresuming " "%s@%s (aka %s)\n", d_name, d_info, d_alias); } else { prom_printf("\tresuming " "%s@%s\n", d_name, d_info); } } else { prom_printf("\tresuming %s@%s\n", bn, d_info); } if (devi_attach(dip, DDI_RESUME) != DDI_SUCCESS) { /* * Print a console warning, * set an e_code of ESBD_RESUME, * and save the driver major * number in the e_rsc. */ prom_printf("\tFAILED to resume %s@%s", d_name[0] ? d_name : bn, d_info); srh->sr_err_idx = dr_add_int(srh->sr_err_ints, srh->sr_err_idx, DR_MAX_ERR_INT, (uint64_t)major); handle = srh->sr_dr_handlep; dr_op_err(CE_IGNORE, handle, ESBD_RESUME, "%s@%s", d_name[0] ? d_name : bn, d_info); } } } /* Hold parent busy while walking its children */ ndi_devi_enter(dip, &circ); dr_resume_devices(ddi_get_child(dip), srh); ndi_devi_exit(dip, circ); last = dip; } }
static void sbdp_resume_devices(dev_info_t *start, sbdp_sr_handle_t *srh) { int circ; dev_info_t *dip, *next, *last = NULL; char *bn; sbd_error_t *sep; sep = &srh->sep; /* attach in reverse device tree order */ while (last != start) { dip = start; next = ddi_get_next_sibling(dip); while (next != last && dip != SR_FAILED_DIP(srh)) { dip = next; next = ddi_get_next_sibling(dip); } if (dip == SR_FAILED_DIP(srh)) { /* Release hold acquired in sbdp_suspend_devices() */ ndi_rele_devi(dip); SR_FAILED_DIP(srh) = NULL; } else if (sbdp_is_real_device(dip) && SR_FAILED_DIP(srh) == NULL) { if (DEVI(dip)->devi_binding_name != NULL) { bn = ddi_binding_name(dip); } #ifdef DEBUG if (!sbdp_bypass_device(bn)) { #else { #endif char d_name[40], d_alias[40], *d_info; d_name[0] = 0; d_info = ddi_get_name_addr(dip); if (d_info == NULL) d_info = "<null>"; if (!sbdp_resolve_devname(dip, d_name, d_alias)) { if (d_alias[0] != 0) { SBDP_DBG_QR("\tresuming " "%s@%s (aka %s)\n", d_name, d_info, d_alias); } else { SBDP_DBG_QR("\tresuming " "%s@%s\n", d_name, d_info); } } else { SBDP_DBG_QR("\tresuming %s@%s\n", bn, d_info); } if (devi_attach(dip, DDI_RESUME) != DDI_SUCCESS) { /* * Print a console warning, * set an errno of ESGT_RESUME, * and save the driver major * number in the e_str. */ (void) sprintf(sbdp_get_err_buf(sep), "%s@%s", d_name[0] ? d_name : bn, d_info); SBDP_DBG_QR("\tFAILED to resume " "%s\n", sbdp_get_err_buf(sep)); sbdp_set_err(sep, ESGT_RESUME, NULL); } } } ndi_devi_enter(dip, &circ); sbdp_resume_devices(ddi_get_child(dip), srh); ndi_devi_exit(dip, circ); last = dip; } } /* * True if thread is virtually stopped. Similar to CPR_VSTOPPED * but from DR point of view. These user threads are waiting in * the kernel. Once they return from kernel, they will process * the stop signal and stop. */ #define SBDP_VSTOPPED(t) \ ((t)->t_state == TS_SLEEP && \ (t)->t_wchan != NULL && \ (t)->t_astflag && \ ((t)->t_proc_flag & TP_CHKPT)) static int sbdp_stop_user_threads(sbdp_sr_handle_t *srh) { int count; char cache_psargs[PSARGSZ]; kthread_id_t cache_tp; uint_t cache_t_state; int bailout; sbd_error_t *sep; kthread_id_t tp; extern void add_one_utstop(); extern void utstop_timedwait(clock_t); extern void utstop_init(void); #define SBDP_UTSTOP_RETRY 4 #define SBDP_UTSTOP_WAIT hz if (sbdp_skip_user_threads) return (DDI_SUCCESS); sep = &srh->sep; ASSERT(sep); utstop_init(); /* we need to try a few times to get past fork, etc. */ for (count = 0; count < SBDP_UTSTOP_RETRY; count++) { /* walk the entire threadlist */ mutex_enter(&pidlock); for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) { proc_t *p = ttoproc(tp); /* handle kernel threads separately */ if (p->p_as == &kas || p->p_stat == SZOMB) continue; mutex_enter(&p->p_lock); thread_lock(tp); if (tp->t_state == TS_STOPPED) { /* add another reason to stop this thread */ tp->t_schedflag &= ~TS_RESUME; } else { tp->t_proc_flag |= TP_CHKPT; thread_unlock(tp); mutex_exit(&p->p_lock); add_one_utstop(); mutex_enter(&p->p_lock); thread_lock(tp); aston(tp); if (ISWAKEABLE(tp) || ISWAITING(tp)) { setrun_locked(tp); } } /* grab thread if needed */ if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU) poke_cpu(tp->t_cpu->cpu_id); thread_unlock(tp); mutex_exit(&p->p_lock); } mutex_exit(&pidlock); /* let everything catch up */ utstop_timedwait(count * count * SBDP_UTSTOP_WAIT); /* now, walk the threadlist again to see if we are done */ mutex_enter(&pidlock); for (tp = curthread->t_next, bailout = 0; tp != curthread; tp = tp->t_next) { proc_t *p = ttoproc(tp); /* handle kernel threads separately */ if (p->p_as == &kas || p->p_stat == SZOMB) continue; /* * If this thread didn't stop, and we don't allow * unstopped blocked threads, bail. */ thread_lock(tp); if (!CPR_ISTOPPED(tp) && !(sbdp_allow_blocked_threads && SBDP_VSTOPPED(tp))) { /* nope, cache the details for later */ bcopy(p->p_user.u_psargs, cache_psargs, sizeof (cache_psargs)); cache_tp = tp; cache_t_state = tp->t_state; bailout = 1; } thread_unlock(tp); } mutex_exit(&pidlock); /* were all the threads stopped? */ if (!bailout) break; } /* were we unable to stop all threads after a few tries? */ if (bailout) { cmn_err(CE_NOTE, "process: %s id: %p state: %x\n", cache_psargs, cache_tp, cache_t_state); (void) sprintf(sbdp_get_err_buf(sep), "%s", cache_psargs); sbdp_set_err(sep, ESGT_UTHREAD, NULL); return (ESRCH); } return (DDI_SUCCESS); }
/* * Init and attach the root node. root node is the first one to be * attached, so the process is somewhat "handcrafted". */ void i_ddi_init_root() { #ifdef DDI_PROP_DEBUG (void) ddi_prop_debug(1); /* Enable property debugging */ #endif /* DDI_PROP_DEBUG */ /* * Initialize root node */ if (impl_ddi_sunbus_initchild(top_devinfo) != DDI_SUCCESS) panic("Could not initialize root nexus"); /* * Attach root node (no need to probe) * Hold both devinfo and rootnex driver so they can't go away. */ DEVI(top_devinfo)->devi_ops = ndi_hold_driver(top_devinfo); ASSERT(DEV_OPS_HELD(DEVI(top_devinfo)->devi_ops)); DEVI(top_devinfo)->devi_instance = e_ddi_assign_instance(top_devinfo); (void) i_ddi_load_drvconf(DEVI(top_devinfo)->devi_major); mutex_enter(&(DEVI(top_devinfo)->devi_lock)); DEVI_SET_ATTACHING(top_devinfo); mutex_exit(&(DEVI(top_devinfo)->devi_lock)); if (devi_attach(top_devinfo, DDI_ATTACH) != DDI_SUCCESS) panic("Could not attach root nexus"); mutex_enter(&(DEVI(top_devinfo)->devi_lock)); DEVI_CLR_ATTACHING(top_devinfo); mutex_exit(&(DEVI(top_devinfo)->devi_lock)); mutex_init(&global_vhci_lock, NULL, MUTEX_DEFAULT, NULL); ndi_hold_devi(top_devinfo); /* hold it forever */ i_ddi_set_node_state(top_devinfo, DS_READY); /* * Now, expand .conf children of root */ (void) i_ndi_make_spec_children(top_devinfo, 0); /* * Must be set up before attaching root or pseudo drivers */ pm_init_locks(); /* * Attach options dip */ options_dip = i_ddi_attach_pseudo_node("options"); /* * Attach pseudo nexus and enumerate its children */ pseudo_dip = i_ddi_attach_pseudo_node(DEVI_PSEUDO_NEXNAME); (void) i_ndi_make_spec_children(pseudo_dip, 0); /* * Attach and hold clone dip */ clone_dip = i_ddi_attach_pseudo_node("clone"); clone_major = ddi_driver_major(clone_dip); mm_major = ddi_name_to_major("mm"); nulldriver_major = ddi_name_to_major("nulldriver"); /* * Attach scsi_vhci for MPXIO, this registers scsi vhci class * with the MPXIO framework. */ scsi_vhci_dip = i_ddi_attach_pseudo_node("scsi_vhci"); }
int xen_resume_devices(dev_info_t *start, int resume_failed) { dev_info_t *dip, *next, *last = NULL; int did_suspend; int error = resume_failed; char buf[XPV_BUFSIZE]; SUSPEND_DEBUG("xen_resume_devices\n"); while (last != start) { dip = start; next = ddi_get_next_sibling(dip); while (next != last) { dip = next; next = ddi_get_next_sibling(dip); } /* * cpr is the only one that uses this field and the device * itself hasn't resumed yet, there is no need to use a * lock, even though kernel threads are active by now. */ did_suspend = DEVI(dip)->devi_cpr_flags & DCF_CPR_SUSPENDED; if (did_suspend) DEVI(dip)->devi_cpr_flags &= ~DCF_CPR_SUSPENDED; /* * There may be background attaches happening on devices * that were not originally suspended by cpr, so resume * only devices that were suspended by cpr. Also, stop * resuming after the first resume failure, but traverse * the entire tree to clear the suspend flag. */ if (did_suspend && !error) { SUSPEND_DEBUG("Resuming device %s\n", ddi_deviname(dip, buf)); /* * If a device suspended by cpr gets detached during * the resume process (for example, due to hotplugging) * before cpr gets around to issuing it a DDI_RESUME, * we'll have problems. */ if (!i_ddi_devi_attached(dip)) { cmn_err(CE_WARN, "Skipping %s, device " "not ready for resume", ddi_deviname(dip, buf)); } else { if (devi_attach(dip, DDI_RESUME) != DDI_SUCCESS) { error = ENXIO; } } } if (error == ENXIO) { cmn_err(CE_WARN, "Unable to resume device %s", ddi_deviname(dip, buf)); } error = xen_resume_devices(ddi_get_child(dip), error); last = dip; } return (error); }