25e8c5aa2b496d9026e958ac731a610167574f59vikram * CDDL HEADER START
25e8c5aa2b496d9026e958ac731a610167574f59vikram * The contents of this file are subject to the terms of the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Common Development and Distribution License (the "License").
25e8c5aa2b496d9026e958ac731a610167574f59vikram * You may not use this file except in compliance with the License.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
25e8c5aa2b496d9026e958ac731a610167574f59vikram * See the License for the specific language governing permissions
25e8c5aa2b496d9026e958ac731a610167574f59vikram * and limitations under the License.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * When distributing Covered Code, include this CDDL HEADER in each
25e8c5aa2b496d9026e958ac731a610167574f59vikram * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If applicable, add the following below this CDDL HEADER, with the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * fields enclosed by brackets "[]" replaced with your own identifying
25e8c5aa2b496d9026e958ac731a610167574f59vikram * information: Portions Copyright [yyyy] [name of copyright owner]
25e8c5aa2b496d9026e958ac731a610167574f59vikram * CDDL HEADER END
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic void rio_assert(di_retire_t *dp, const char *EXstr, int line,
25e8c5aa2b496d9026e958ac731a610167574f59vikram const char *file);
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic int disk_select(di_node_t node, rcm_arg_t *rp);
25e8c5aa2b496d9026e958ac731a610167574f59vikramstatic int nexus_select(di_node_t node, rcm_arg_t *rp);
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hansonstatic int enclosure_select(di_node_t node, rcm_arg_t *rp);
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hansonstatic int smp_select(di_node_t node, rcm_arg_t *rp);
25e8c5aa2b496d9026e958ac731a610167574f59vikramrio_assert(di_retire_t *dp, const char *EXstr, int line, const char *file)
25e8c5aa2b496d9026e958ac731a610167574f59vikram "Assertion failed: %s, file %s, line %d\n",
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hansonenclosure_minor(di_node_t node, di_minor_t minor, void *arg)
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson dp->rt_debug(dp->rt_hdl, "[INFO]: enclosure_minor: "
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson "IDed this node as enclosure\n");
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hansonenclosure_select(di_node_t node, rcm_arg_t *rp)
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson * Check if this is an enclosure minor. If any one minor is DDI_NT_SGEN
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson * or DDI_NT_SCSI_ENCLOSURE we assume it is an enclosure.
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson if (di_walk_minor(node, DDI_NT_SCSI_ENCLOSURE, 0, &rarg,
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson dp->rt_debug(dp->rt_hdl, "[INFO]: enclosure_select:"
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson "di_walk_minor failed. Returning NOTSUP\n");
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson if (di_walk_minor(node, "ddi_generic:scsi", 0, &rarg,
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson dp->rt_debug(dp->rt_hdl, "[INFO]: enclosure_select:"
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson "di_walk_minor failed. Returning NOTSUP\n");
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hansonsmp_minor(di_node_t node, di_minor_t minor, void *arg)
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson dp->rt_debug(dp->rt_hdl, "[INFO]: smp_minor: "
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson "IDed this node as smp\n");
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson * Check if this is an smp minor. If any one minor is DDI_NT_SMP
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson * we assume it is an smp.
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson if (di_walk_minor(node, DDI_NT_SMP, 0, &rarg, smp_minor) != 0) {
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson dp->rt_debug(dp->rt_hdl, "[INFO]: smp_select:"
f76de7499b0498d120c0c5ba970d061ccb587552Stephen Hanson "di_walk_minor failed. Returning NOTSUP\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikramdisk_minor(di_node_t node, di_minor_t minor, void *arg)
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: disk_minor: is disk minor. "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "IDed this node as disk\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: disk_minor: Not a disk minor. "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "Continuing minor walk\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Check if this is a disk minor. If any one minor is DDI_NT_BLOCK
25e8c5aa2b496d9026e958ac731a610167574f59vikram * we assume it is a disk
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (di_walk_minor(node, DDI_NT_BLOCK, 0, &rarg, disk_minor) != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: disk_select: di_walk_minor "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "failed. Returning NOTSUP\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram "di_devfs_path() is NULL. Returning NOTSUP\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Check if it is a nexus
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: nexus_select: is nexus %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: nexus_select: not nexus %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* skip pseudo nodes - we only retire real hardware */
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (strncmp(path, "/pseudo/", strlen("/pseudo/")) == 0 ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram "pseudo device in subtree - returning NOTSUP: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If a device is offline/detached/down it is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * retireable irrespective of the type of device,
25e8c5aa2b496d9026e958ac731a610167574f59vikram * presumably the system is able to function without
25e8c5aa2b496d9026e958ac731a610167574f59vikram if ((state & DI_DRIVER_DETACHED) || (state & DI_DEVICE_OFFLINE) ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: device "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "is offline/detached. Assuming retire supported\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram for (i = 0; supported_devices[i].sel_name != NULL; i++) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram "found supported device: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This node is not a supported device. Retire cannot proceed
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: found "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "unsupported device. Returning NOTSUP\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram * This node is supported. Check other nodes in this subtree.
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: node_select: This node supported. "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "Checking other nodes in subtree: %s\n", rp->rcm_root);
25e8c5aa2b496d9026e958ac731a610167574f59vikram * when in doubt assume that retire is not supported for this device.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * We should not be here if devinfo snapshot is NULL.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Note: We initally set supported to 1, then walk the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * subtree rooted at devpath, allowing each node the
25e8c5aa2b496d9026e958ac731a610167574f59vikram * opportunity to veto the support. We cannot do things
25e8c5aa2b496d9026e958ac731a610167574f59vikram * the other way around i.e. assume "not supported" and
25e8c5aa2b496d9026e958ac731a610167574f59vikram * let individual nodes indicate that they are supported.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * In the latter case, the supported flag would be set
25e8c5aa2b496d9026e958ac731a610167574f59vikram * if any one node in the subtree was supported which is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * not what we want.
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (di_walk_node(rnode, DI_WALK_CLDFIRST, rp, node_select) != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: retire_supported: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "di_walk_node: failed. Returning NOTSUP\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: retire IS supported\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_finalize: retcode=%d: dev=%s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_finalize: cons_nodes NULL\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram "rcm_%s: retval=%d: error=%s: path=%s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram "rcm_%s: SUCCESS: path=%s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikramcall_offline(di_node_t node, di_minor_t minor, void *arg)
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: di_devfs_minor_path "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "failed. Returning RCM FAILURE: %s\n", rp->rcm_root);
25e8c5aa2b496d9026e958ac731a610167574f59vikram (void) snprintf(rpt->rpt_path, sizeof (rpt->rpt_path),
25e8c5aa2b496d9026e958ac731a610167574f59vikram retval = rp->rcm_offline(rp->rcm_handle, rpt->rpt_path,
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: RCM OFFLINE failed "
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: RCM OFFLINE returned "
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: RCM OFFLINE returned "
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: RCM OFFLINE returned "
25e8c5aa2b496d9026e958ac731a610167574f59vikram * We should already have terminated the walk
25e8c5aa2b496d9026e958ac731a610167574f59vikram * in case of failure
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: offline_one: entered\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: rio_path_t calloc "
25e8c5aa2b496d9026e958ac731a610167574f59vikram (void) strlcpy(rpt->rpt_path, path, sizeof (rpt->rpt_path));
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (di_walk_minor(node, NULL, 0, rp, call_offline) != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram "returned: unknown RCM error code: %d, %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * RCM_SUCCESS or RCM_NO_CONSTRAINT.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * RCM_SUCCESS implies we overcame a constraint, so keep walking.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * RCM_NO_CONSTRAINT implies no constraints applied via RCM.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Continue walking in the hope that contracts or LDI will
25e8c5aa2b496d9026e958ac731a610167574f59vikram * apply constraints
25e8c5aa2b496d9026e958ac731a610167574f59vikram * set retcode to RCM_SUCCESS to show that at least 1 node
25e8c5aa2b496d9026e958ac731a610167574f59vikram * completely walked
25e8c5aa2b496d9026e958ac731a610167574f59vikram * RCM_SUCCESS: RCM constraints (if any) were applied. The
25e8c5aa2b496d9026e958ac731a610167574f59vikram * device paths for which constraints were applied is passed
25e8c5aa2b496d9026e958ac731a610167574f59vikram * back via the pp argument
25e8c5aa2b496d9026e958ac731a610167574f59vikram * RCM_FAILURE: Either RCM constraints prevent a retire or
25e8c5aa2b496d9026e958ac731a610167574f59vikram * an error occurred
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: rcm_notify() entered\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: devinfo snapshot "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "NULL. Returning no RCM constraint: %s\n", rp->rcm_root);
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (di_walk_node(rnode, DI_WALK_CLDFIRST, rp, offline_one) != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram "failed: error: %s: %s\n", strerror(errno), rp->rcm_root);
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* online is idempotent - safe to online non-offlined nodes */
25e8c5aa2b496d9026e958ac731a610167574f59vikram "returned retcode of RCM_FAILURE: %s\n", rp->rcm_root);
25e8c5aa2b496d9026e958ac731a610167574f59vikram " - no nodes walked: RCM_NO_CONSTRAINT: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: walk_node: RCM_SUCCESS\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Convert to a sequence of NUL separated strings terminated by '\0'\0'
25e8c5aa2b496d9026e958ac731a610167574f59vikram for (len = 0, p = rp->rcm_cons_nodes; p; p = p->rpt_next) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: len of constraint str = %lu\n", len);
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: constraint str = %p\n", plistp);
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikramdi_retire_device(char *devpath, di_retire_t *dp, int flags)
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL argument(s)\n");
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram strncmp(devpath, "/devices/", strlen("/devices/")) == 0 ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram strstr(devpath, "../devices/") || strrchr(devpath, ':')) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: invalid devpath: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (flags != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: flags should be 0: %d\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram * dlopen rather than link against librcm since libdevinfo
25e8c5aa2b496d9026e958ac731a610167574f59vikram * resides in / and librcm resides in /usr. The dlopen is
25e8c5aa2b496d9026e958ac731a610167574f59vikram * safe to do since fmd which invokes the retire code
25e8c5aa2b496d9026e958ac731a610167574f59vikram * resides on /usr and will not come here until /usr is
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: Cannot dlopen librcm: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram librcm_alloc_handle = (int (*)())dlsym(librcm_hdl, "rcm_alloc_handle");
25e8c5aa2b496d9026e958ac731a610167574f59vikram rarg.rcm_offline = (int (*)())dlsym(librcm_hdl, "rcm_request_offline");
25e8c5aa2b496d9026e958ac731a610167574f59vikram rarg.rcm_online = (int (*)())dlsym(librcm_hdl, "rcm_notify_online");
25e8c5aa2b496d9026e958ac731a610167574f59vikram rarg.rcm_remove = (int (*)())dlsym(librcm_hdl, "rcm_notify_remove");
25e8c5aa2b496d9026e958ac731a610167574f59vikram librcm_free_handle = (int (*)())dlsym(librcm_hdl, "rcm_free_handle");
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Take a libdevinfo snapshot here because we cannot do so
25e8c5aa2b496d9026e958ac731a610167574f59vikram * after device is retired. If device doesn't attach, we retire
25e8c5aa2b496d9026e958ac731a610167574f59vikram * anyway i.e. it is not fatal.
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: device doesn't attach, "
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (librcm_alloc_handle(NULL, 0, NULL, &rarg.rcm_handle)
25e8c5aa2b496d9026e958ac731a610167574f59vikram * If device is already detached/nonexistent and cannot be
25e8c5aa2b496d9026e958ac731a610167574f59vikram * attached, allow retire without checking device type.
25e8c5aa2b496d9026e958ac731a610167574f59vikram * Else, check if retire is supported for this device type.
25e8c5aa2b496d9026e958ac731a610167574f59vikram (void) snprintf(path, sizeof (path), "/devices%s", devpath);
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: detached or nonexistent "
25e8c5aa2b496d9026e958ac731a610167574f59vikram "device. Bypassing retire_supported: %s\n", devpath);
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: retire not supported for "
25e8c5aa2b496d9026e958ac731a610167574f59vikram /* retire not permitted */
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: RCM constraints block "
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: RCM constraints applied"
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: No RCM constraints applied"
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: notify returned unknown "
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (modctl(MODRETIRE, devpath, constraint, clen) != 0) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: retire modctl() failed: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: retire modctl() succeeded: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram/*ARGSUSED*/
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
25e8c5aa2b496d9026e958ac731a610167574f59vikram if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram strncmp(devpath, "/devices/", strlen("/devices/")) == 0 ||
25e8c5aa2b496d9026e958ac731a610167574f59vikram strstr(devpath, "../devices/") || strrchr(devpath, ':')) {
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: invalid devpath: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[ERROR]: unretire modctl() failed: "
25e8c5aa2b496d9026e958ac731a610167574f59vikram dp->rt_debug(dp->rt_hdl, "[INFO]: unretire modctl() done: %s\n",
25e8c5aa2b496d9026e958ac731a610167574f59vikram return (0);