17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5602ca9eaScth * Common Development and Distribution License (the "License"). 6602ca9eaScth * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22602ca9eaScth * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * RCM module supporting multiplexed I/O controllers (MPxIO). 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <stdarg.h> 337c478bd9Sstevel@tonic-gate #include <unistd.h> 347c478bd9Sstevel@tonic-gate #include <assert.h> 357c478bd9Sstevel@tonic-gate #include <syslog.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <synch.h> 387c478bd9Sstevel@tonic-gate #include <libintl.h> 397c478bd9Sstevel@tonic-gate #include <locale.h> 407c478bd9Sstevel@tonic-gate #include <ctype.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 427c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 437c478bd9Sstevel@tonic-gate #include <sys/types.h> 447c478bd9Sstevel@tonic-gate #include "rcm_module.h" 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #define MPXIO_PROP_NAME "mpxio-component" 477c478bd9Sstevel@tonic-gate #define MPXIO_PROP_CLIENT "client" 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define CMD_GETINFO 0 507c478bd9Sstevel@tonic-gate #define CMD_OFFLINE 1 517c478bd9Sstevel@tonic-gate #define CMD_ONLINE 2 527c478bd9Sstevel@tonic-gate #define CMD_REMOVE 3 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #define CACHE_NEW 0 557c478bd9Sstevel@tonic-gate #define CACHE_REFERENCED 1 567c478bd9Sstevel@tonic-gate #define CACHE_STALE 2 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #define MPXIO_MSG_CACHEFAIL gettext("Internal analysis failure.") 597c478bd9Sstevel@tonic-gate #define MPXIO_MSG_LASTPATH gettext("Last path to busy resources.") 607c478bd9Sstevel@tonic-gate #define MPXIO_MSG_USAGE gettext("SCSI Multipathing PHCI (%s)") 617c478bd9Sstevel@tonic-gate #define MPXIO_MSG_USAGEUNKNOWN gettext("SCSI Multipathing PHCI (<unknown>)") 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate typedef struct { 647c478bd9Sstevel@tonic-gate char *path; 657c478bd9Sstevel@tonic-gate di_path_state_t state; 667c478bd9Sstevel@tonic-gate } phci_t; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate typedef struct phci_list { 697c478bd9Sstevel@tonic-gate phci_t phci; 707c478bd9Sstevel@tonic-gate int referenced; 717c478bd9Sstevel@tonic-gate struct phci_list *next; 727c478bd9Sstevel@tonic-gate } phci_list_t; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate typedef struct group { 757c478bd9Sstevel@tonic-gate int offline; 767c478bd9Sstevel@tonic-gate int nphcis; 777c478bd9Sstevel@tonic-gate int nclients; 787c478bd9Sstevel@tonic-gate phci_t *phcis; 797c478bd9Sstevel@tonic-gate char **clients; 807c478bd9Sstevel@tonic-gate struct group *next; 817c478bd9Sstevel@tonic-gate } group_t; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static int mpxio_register(rcm_handle_t *); 847c478bd9Sstevel@tonic-gate static int mpxio_unregister(rcm_handle_t *); 857c478bd9Sstevel@tonic-gate static int mpxio_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **, char **, 867c478bd9Sstevel@tonic-gate nvlist_t *, rcm_info_t **); 877c478bd9Sstevel@tonic-gate static int mpxio_suspend(rcm_handle_t *, char *, id_t, timespec_t *, uint_t, 887c478bd9Sstevel@tonic-gate char **, rcm_info_t **); 897c478bd9Sstevel@tonic-gate static int mpxio_resume(rcm_handle_t *, char *, id_t, uint_t, char **, 907c478bd9Sstevel@tonic-gate rcm_info_t **); 917c478bd9Sstevel@tonic-gate static int mpxio_offline(rcm_handle_t *, char *, id_t, uint_t, char **, 927c478bd9Sstevel@tonic-gate rcm_info_t **); 937c478bd9Sstevel@tonic-gate static int mpxio_online(rcm_handle_t *, char *, id_t, uint_t, char **, 947c478bd9Sstevel@tonic-gate rcm_info_t **); 957c478bd9Sstevel@tonic-gate static int mpxio_remove(rcm_handle_t *, char *, id_t, uint_t, char **, 967c478bd9Sstevel@tonic-gate rcm_info_t **); 977c478bd9Sstevel@tonic-gate static int get_nclients(di_node_t, void *); 987c478bd9Sstevel@tonic-gate static int build_groups(di_node_t, void *); 997c478bd9Sstevel@tonic-gate static void refresh_regs(rcm_handle_t *); 1007c478bd9Sstevel@tonic-gate static int get_affected_clients(rcm_handle_t *, char *, int, int, char ***); 1017c478bd9Sstevel@tonic-gate static int detect_client_change(rcm_handle_t *, int, int, group_t *, char *); 1027c478bd9Sstevel@tonic-gate static int merge_clients(int *, char ***, group_t *); 1037c478bd9Sstevel@tonic-gate static phci_list_t *lookup_phci(char *); 1047c478bd9Sstevel@tonic-gate static int is_client(di_node_t); 1057c478bd9Sstevel@tonic-gate static char *get_rsrcname(di_node_t); 1067c478bd9Sstevel@tonic-gate static char *s_state(di_path_state_t); 1077c478bd9Sstevel@tonic-gate static int compare_phci(const void *, const void *); 1087c478bd9Sstevel@tonic-gate static void free_grouplist(); 1097c478bd9Sstevel@tonic-gate static void free_group(group_t *); 1107c478bd9Sstevel@tonic-gate static void free_clients(int, char **); 1117c478bd9Sstevel@tonic-gate static void free_phcis(int, phci_t *); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static struct rcm_mod_ops mpxio_ops = 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate RCM_MOD_OPS_VERSION, 1167c478bd9Sstevel@tonic-gate mpxio_register, 1177c478bd9Sstevel@tonic-gate mpxio_unregister, 1187c478bd9Sstevel@tonic-gate mpxio_getinfo, 1197c478bd9Sstevel@tonic-gate mpxio_suspend, 1207c478bd9Sstevel@tonic-gate mpxio_resume, 1217c478bd9Sstevel@tonic-gate mpxio_offline, 1227c478bd9Sstevel@tonic-gate mpxio_online, 1237c478bd9Sstevel@tonic-gate mpxio_remove, 1247c478bd9Sstevel@tonic-gate NULL, 1257c478bd9Sstevel@tonic-gate NULL, 1267c478bd9Sstevel@tonic-gate NULL 1277c478bd9Sstevel@tonic-gate }; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static group_t *group_list; 1307c478bd9Sstevel@tonic-gate static phci_list_t *reg_list; 1317c478bd9Sstevel@tonic-gate static mutex_t mpxio_lock; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate extern int errno; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate /* 1367c478bd9Sstevel@tonic-gate * Return the mod-ops vector for initialization. 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate struct rcm_mod_ops * 1397c478bd9Sstevel@tonic-gate rcm_mod_init() 1407c478bd9Sstevel@tonic-gate { 1417c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: rcm_mod_init()\n"); 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate return (&mpxio_ops); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * Return name and version number for mod_info. 1487c478bd9Sstevel@tonic-gate */ 1497c478bd9Sstevel@tonic-gate const char * 1507c478bd9Sstevel@tonic-gate rcm_mod_info() 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: rcm_mod_info()\n"); 1537c478bd9Sstevel@tonic-gate 154*648495d6Svikram return (gettext("RCM MPxIO module 1.6")); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * Destroy the cache and mutex lock when being unloaded. 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate int 1617c478bd9Sstevel@tonic-gate rcm_mod_fini() 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate phci_list_t *reg; 1647c478bd9Sstevel@tonic-gate phci_list_t *next; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: rcm_mod_fini()\n"); 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* Free the cache of MPxIO group information */ 1697c478bd9Sstevel@tonic-gate free_grouplist(); 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* Free the cache of registrants */ 1727c478bd9Sstevel@tonic-gate reg = reg_list; 1737c478bd9Sstevel@tonic-gate while (reg) { 1747c478bd9Sstevel@tonic-gate next = reg->next; 1757c478bd9Sstevel@tonic-gate free(reg->phci.path); 1767c478bd9Sstevel@tonic-gate free(reg); 1777c478bd9Sstevel@tonic-gate reg = next; 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* Destroy the mutex for locking the caches */ 1817c478bd9Sstevel@tonic-gate (void) mutex_destroy(&mpxio_lock); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * During each register callback: totally rebuild the group list from a new 1887c478bd9Sstevel@tonic-gate * libdevinfo snapshot, and then update the registrants. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate static int 1917c478bd9Sstevel@tonic-gate mpxio_register(rcm_handle_t *hdl) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate int nclients = 0; 1947c478bd9Sstevel@tonic-gate di_node_t devroot; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: register()\n"); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate (void) mutex_lock(&mpxio_lock); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* Destroy the previous group list */ 2017c478bd9Sstevel@tonic-gate free_grouplist(); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* Get a current libdevinfo snapshot */ 2047c478bd9Sstevel@tonic-gate if ((devroot = di_init("/", DINFOCPYALL | DINFOPATH)) == DI_NODE_NIL) { 2057c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 2067c478bd9Sstevel@tonic-gate "MPXIO: libdevinfo initialization failed (%s).\n", 2077c478bd9Sstevel@tonic-gate strerror(errno)); 2087c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 2097c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * First count the total number of clients. This'll be a useful 2147c478bd9Sstevel@tonic-gate * upper bound when allocating client arrays within each group. 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate (void) di_walk_node(devroot, DI_WALK_CLDFIRST, &nclients, get_nclients); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, gettext("MPXIO: found %d clients.\n"), 2197c478bd9Sstevel@tonic-gate nclients); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * Then walk the libdevinfo snapshot, building up the new group list 2237c478bd9Sstevel@tonic-gate * along the way. Pass in the total number of clients (from above) to 2247c478bd9Sstevel@tonic-gate * assist in group construction. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate (void) di_walk_node(devroot, DI_WALK_CLDFIRST, &nclients, build_groups); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* Now with a new group list constructed, refresh the registrants */ 2297c478bd9Sstevel@tonic-gate refresh_regs(hdl); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* Free the libdevinfo snapshot */ 2327c478bd9Sstevel@tonic-gate di_fini(devroot); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate return (0); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Unregister all PHCIs and mark the whole registrants list as stale. 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate static int 2437c478bd9Sstevel@tonic-gate mpxio_unregister(rcm_handle_t *hdl) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate phci_list_t *reg; 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: unregister()\n"); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate (void) mutex_lock(&mpxio_lock); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate for (reg = reg_list; reg != NULL; reg = reg->next) { 2527c478bd9Sstevel@tonic-gate (void) rcm_unregister_interest(hdl, reg->phci.path, 0); 2537c478bd9Sstevel@tonic-gate reg->referenced = CACHE_STALE; 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * To return usage information, just lookup the PHCI in the cache and return 2637c478bd9Sstevel@tonic-gate * a string identifying that it's a PHCI and describing its cached MPxIO state. 2647c478bd9Sstevel@tonic-gate * Recurse with the cached list of disks if dependents are to be included. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate static int 2677c478bd9Sstevel@tonic-gate mpxio_getinfo(rcm_handle_t *hdl, char *rsrc, id_t id, uint_t flags, 2687c478bd9Sstevel@tonic-gate char **infostr, char **errstr, nvlist_t *props, rcm_info_t **infop) 2697c478bd9Sstevel@tonic-gate { 2707c478bd9Sstevel@tonic-gate size_t len; 2717c478bd9Sstevel@tonic-gate int rv = RCM_SUCCESS; 2727c478bd9Sstevel@tonic-gate char *buf = NULL; 2737c478bd9Sstevel@tonic-gate char **clients = NULL; 2747c478bd9Sstevel@tonic-gate phci_list_t *reg; 2757c478bd9Sstevel@tonic-gate char c; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: getinfo(%s)\n", rsrc); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate *infostr = NULL; 2807c478bd9Sstevel@tonic-gate *errstr = NULL; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate (void) mutex_lock(&mpxio_lock); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if ((reg = lookup_phci(rsrc)) == NULL) { 2857c478bd9Sstevel@tonic-gate *errstr = strdup(MPXIO_MSG_CACHEFAIL); 2867c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 2877c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate len = snprintf(&c, 1, MPXIO_MSG_USAGE, s_state(reg->phci.state)); 2917c478bd9Sstevel@tonic-gate buf = calloc(len + 1, sizeof (char)); 2927c478bd9Sstevel@tonic-gate if ((buf == NULL) || (snprintf(buf, len + 1, MPXIO_MSG_USAGE, 2937c478bd9Sstevel@tonic-gate s_state(reg->phci.state)) > len + 1)) { 2947c478bd9Sstevel@tonic-gate *infostr = strdup(MPXIO_MSG_USAGEUNKNOWN); 2957c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Cannot construct usage string.")); 2967c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 2977c478bd9Sstevel@tonic-gate if (buf) 2987c478bd9Sstevel@tonic-gate free(buf); 2997c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate *infostr = buf; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (flags & RCM_INCLUDE_DEPENDENT) { 3047c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "MPXIO: getting clients\n"); 3057c478bd9Sstevel@tonic-gate if (get_affected_clients(hdl, rsrc, CMD_GETINFO, flags, 3067c478bd9Sstevel@tonic-gate &clients) < 0) { 3077c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Cannot lookup clients.")); 3087c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 3097c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate if (clients) { 3127c478bd9Sstevel@tonic-gate rv = rcm_get_info_list(hdl, clients, flags, infop); 3137c478bd9Sstevel@tonic-gate free(clients); 3147c478bd9Sstevel@tonic-gate } else { 3157c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "MPXIO: none found\n"); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 3207c478bd9Sstevel@tonic-gate return (rv); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * Nothing is implemented for suspend operations. 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate static int 3277c478bd9Sstevel@tonic-gate mpxio_suspend(rcm_handle_t *hdl, char *rsrc, id_t id, timespec_t *interval, 3287c478bd9Sstevel@tonic-gate uint_t flags, char **errstr, rcm_info_t **infop) 3297c478bd9Sstevel@tonic-gate { 3307c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: suspend(%s)\n", rsrc); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * Nothing is implemented for resume operations. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate static int 3397c478bd9Sstevel@tonic-gate mpxio_resume(rcm_handle_t *hdl, char *rsrc, id_t id, uint_t flags, 3407c478bd9Sstevel@tonic-gate char **errstr, rcm_info_t **infop) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: resume(%s)\n", rsrc); 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * MPxIO has no policy against offlining. If disks will be affected, then 3497c478bd9Sstevel@tonic-gate * base the return value for this request on the results of offlining the 3507c478bd9Sstevel@tonic-gate * list of disks. Otherwise succeed. 3517c478bd9Sstevel@tonic-gate */ 3527c478bd9Sstevel@tonic-gate static int 3537c478bd9Sstevel@tonic-gate mpxio_offline(rcm_handle_t *hdl, char *rsrc, id_t id, uint_t flags, 3547c478bd9Sstevel@tonic-gate char **errstr, rcm_info_t **infop) 3557c478bd9Sstevel@tonic-gate { 3567c478bd9Sstevel@tonic-gate char **clients = NULL; 3577c478bd9Sstevel@tonic-gate int rv = RCM_SUCCESS; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: offline(%s)\n", rsrc); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate (void) mutex_lock(&mpxio_lock); 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate if (get_affected_clients(hdl, rsrc, CMD_OFFLINE, flags, &clients) < 0) { 3647c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Cannot lookup clients.")); 3657c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 3667c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate if (clients) { 3707c478bd9Sstevel@tonic-gate rv = rcm_request_offline_list(hdl, clients, flags, infop); 3717c478bd9Sstevel@tonic-gate if (rv != RCM_SUCCESS) 3727c478bd9Sstevel@tonic-gate *errstr = strdup(MPXIO_MSG_LASTPATH); 3737c478bd9Sstevel@tonic-gate free(clients); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate return (rv); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * If disks are affected, then they are probably offline and we need to 3837c478bd9Sstevel@tonic-gate * propagate this online notification to them. 3847c478bd9Sstevel@tonic-gate */ 3857c478bd9Sstevel@tonic-gate static int 3867c478bd9Sstevel@tonic-gate mpxio_online(rcm_handle_t *hdl, char *rsrc, id_t id, uint_t flags, 3877c478bd9Sstevel@tonic-gate char **errstr, rcm_info_t **infop) 3887c478bd9Sstevel@tonic-gate { 3897c478bd9Sstevel@tonic-gate char **clients; 3907c478bd9Sstevel@tonic-gate int rv = RCM_SUCCESS; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: online(%s)\n", rsrc); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate (void) mutex_lock(&mpxio_lock); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (get_affected_clients(hdl, rsrc, CMD_ONLINE, flags, &clients) < 0) { 3977c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Cannot lookup clients.")); 3987c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 3997c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate if (clients) { 4037c478bd9Sstevel@tonic-gate rv = rcm_notify_online_list(hdl, clients, flags, infop); 4047c478bd9Sstevel@tonic-gate free(clients); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate return (rv); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * If clients are affected, then they are probably offline and we need to 4147c478bd9Sstevel@tonic-gate * propagate this removal notification to them. We can also remove the 4157c478bd9Sstevel@tonic-gate * cache entry for this PHCI. If that leaves its group empty, then the 4167c478bd9Sstevel@tonic-gate * group will be removed during the next register callback. 4177c478bd9Sstevel@tonic-gate */ 4187c478bd9Sstevel@tonic-gate static int 4197c478bd9Sstevel@tonic-gate mpxio_remove(rcm_handle_t *hdl, char *rsrc, id_t id, uint_t flags, 4207c478bd9Sstevel@tonic-gate char **errstr, rcm_info_t **infop) 4217c478bd9Sstevel@tonic-gate { 4227c478bd9Sstevel@tonic-gate char **clients; 4237c478bd9Sstevel@tonic-gate int rv = RCM_SUCCESS; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, "MPXIO: remove(%s)\n", rsrc); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate (void) mutex_lock(&mpxio_lock); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate if (get_affected_clients(hdl, rsrc, CMD_REMOVE, flags, &clients) < 0) { 4307c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Cannot lookup clients.")); 4317c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 4327c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if (clients) { 4367c478bd9Sstevel@tonic-gate rv = rcm_notify_remove_list(hdl, clients, flags, infop); 4377c478bd9Sstevel@tonic-gate free(clients); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate (void) mutex_unlock(&mpxio_lock); 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate return (rv); 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Returns a string representation of a given libdevinfo path state. 4487c478bd9Sstevel@tonic-gate */ 4497c478bd9Sstevel@tonic-gate static char * 4507c478bd9Sstevel@tonic-gate s_state(di_path_state_t state) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate switch (state) { 4537c478bd9Sstevel@tonic-gate case DI_PATH_STATE_ONLINE: 4547c478bd9Sstevel@tonic-gate return ("online"); 4557c478bd9Sstevel@tonic-gate case DI_PATH_STATE_OFFLINE: 4567c478bd9Sstevel@tonic-gate return ("offline"); 4577c478bd9Sstevel@tonic-gate case DI_PATH_STATE_STANDBY: 4587c478bd9Sstevel@tonic-gate return ("standby"); 4597c478bd9Sstevel@tonic-gate case DI_PATH_STATE_FAULT: 4607c478bd9Sstevel@tonic-gate return ("faulted"); 4617c478bd9Sstevel@tonic-gate default: 4627c478bd9Sstevel@tonic-gate return ("<unknown>"); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate static int 4677c478bd9Sstevel@tonic-gate get_affected_clients(rcm_handle_t *hdl, char *rsrc, int cmd, int flags, 4687c478bd9Sstevel@tonic-gate char ***clientsp) 4697c478bd9Sstevel@tonic-gate { 4707c478bd9Sstevel@tonic-gate int nclients = 0; 4717c478bd9Sstevel@tonic-gate phci_t phci; 4727c478bd9Sstevel@tonic-gate group_t *group; 4737c478bd9Sstevel@tonic-gate char **clients = NULL; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate /* Build a dummy phci_t for use with bsearch(). */ 4767c478bd9Sstevel@tonic-gate phci.path = rsrc; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* Analyze the effects upon each group. */ 4797c478bd9Sstevel@tonic-gate for (group = group_list; group != NULL; group = group->next) { 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* If the PHCI isn't in the group, then no effects. Skip. */ 4827c478bd9Sstevel@tonic-gate if (bsearch(&phci, group->phcis, group->nphcis, sizeof (phci_t), 4837c478bd9Sstevel@tonic-gate compare_phci) == NULL) 4847c478bd9Sstevel@tonic-gate continue; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Merge in the clients. All clients are merged in for getinfo 4887c478bd9Sstevel@tonic-gate * operations. Otherwise it's contingent upon a state change 4897c478bd9Sstevel@tonic-gate * being transferred to the clients as a result of changing 4907c478bd9Sstevel@tonic-gate * the PHCI's state. 4917c478bd9Sstevel@tonic-gate */ 4927c478bd9Sstevel@tonic-gate if ((cmd == CMD_GETINFO) || 4937c478bd9Sstevel@tonic-gate detect_client_change(hdl, cmd, flags, group, rsrc)) { 4947c478bd9Sstevel@tonic-gate if (merge_clients(&nclients, &clients, group) < 0) { 4957c478bd9Sstevel@tonic-gate free_clients(nclients, clients); 4967c478bd9Sstevel@tonic-gate return (-1); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate /* Return the array of affected disks */ 5027c478bd9Sstevel@tonic-gate *clientsp = clients; 5037c478bd9Sstevel@tonic-gate return (0); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Iterates through the members of a PHCI list, returning the entry 5087c478bd9Sstevel@tonic-gate * corresponding to the named PHCI resource. Returns NULL when the lookup 5097c478bd9Sstevel@tonic-gate * fails. 5107c478bd9Sstevel@tonic-gate */ 5117c478bd9Sstevel@tonic-gate static phci_list_t * 5127c478bd9Sstevel@tonic-gate lookup_phci(char *rsrc) 5137c478bd9Sstevel@tonic-gate { 5147c478bd9Sstevel@tonic-gate phci_list_t *reg; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate for (reg = reg_list; reg != NULL; reg = reg->next) { 5177c478bd9Sstevel@tonic-gate if (strcmp(reg->phci.path, rsrc) == 0) 5187c478bd9Sstevel@tonic-gate return (reg); 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate return (NULL); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * Tests whether or not an operation on a specific PHCI resource would affect 5267c478bd9Sstevel@tonic-gate * the array of client devices attached to the PHCI's MPxIO group. 5277c478bd9Sstevel@tonic-gate * 5287c478bd9Sstevel@tonic-gate * Returns: 1 if clients would be affected, 0 if not. 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate static int 5317c478bd9Sstevel@tonic-gate detect_client_change(rcm_handle_t *hdl, int cmd, int flags, group_t *group, 5327c478bd9Sstevel@tonic-gate char *rsrc) 5337c478bd9Sstevel@tonic-gate { 5347c478bd9Sstevel@tonic-gate int i; 5357c478bd9Sstevel@tonic-gate int state; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * Perform a full set analysis on the set of redundant PHCIs. When 5397c478bd9Sstevel@tonic-gate * there are no unaffected and online PHCIs, then changing the state 5407c478bd9Sstevel@tonic-gate * of the named PHCI results in a client state change. 5417c478bd9Sstevel@tonic-gate */ 5427c478bd9Sstevel@tonic-gate for (i = 0; i < group->nphcis; i++) { 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* Filter the named resource out of the analysis */ 5457c478bd9Sstevel@tonic-gate if (strcmp(group->phcis[i].path, rsrc) == 0) 5467c478bd9Sstevel@tonic-gate continue; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate /* 5497c478bd9Sstevel@tonic-gate * If we find a path that's in the ONLINE or STANDBY state 5507c478bd9Sstevel@tonic-gate * that would be left over in the system after completing 5517c478bd9Sstevel@tonic-gate * whatever DR or hotplugging operation is in progress, then 5527c478bd9Sstevel@tonic-gate * return a 0. 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate if ((group->phcis[i].state == DI_PATH_STATE_ONLINE) || 5557c478bd9Sstevel@tonic-gate (group->phcis[i].state == DI_PATH_STATE_STANDBY)) { 5567c478bd9Sstevel@tonic-gate if (rcm_get_rsrcstate(hdl, group->phcis[i].path, &state) 5577c478bd9Sstevel@tonic-gate != RCM_SUCCESS) { 5587c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 5597c478bd9Sstevel@tonic-gate "MPXIO: Failed to query resource state\n"); 5607c478bd9Sstevel@tonic-gate continue; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "MPXIO: state of %s: %d\n", 5637c478bd9Sstevel@tonic-gate group->phcis[i].path, state); 5647c478bd9Sstevel@tonic-gate if (state == RCM_STATE_ONLINE) { 5657c478bd9Sstevel@tonic-gate return (0); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * The analysis above didn't find a redundant path to take over. So 5727c478bd9Sstevel@tonic-gate * report that the state of the client resources will change. 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate return (1); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * Merges the client disks connected to a particular MPxIO group in with a 5797c478bd9Sstevel@tonic-gate * previous array of disk clients. The result is to adjust the 'nclients' 5807c478bd9Sstevel@tonic-gate * value with the new count of disks in the array, and to adjust the 'disks' 5817c478bd9Sstevel@tonic-gate * value to be a larger array of disks including its original contents along 5827c478bd9Sstevel@tonic-gate * with the current group's contents merged in. 5837c478bd9Sstevel@tonic-gate */ 5847c478bd9Sstevel@tonic-gate static int 5857c478bd9Sstevel@tonic-gate merge_clients(int *nclients, char ***clientsp, group_t *group) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate int i; 5887c478bd9Sstevel@tonic-gate int old_nclients; 5897c478bd9Sstevel@tonic-gate char **clients_new; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate if (group->nclients) { 5927c478bd9Sstevel@tonic-gate old_nclients = *nclients; 5937c478bd9Sstevel@tonic-gate *nclients += group->nclients; 5947c478bd9Sstevel@tonic-gate clients_new = realloc(*clientsp, 5957c478bd9Sstevel@tonic-gate ((*nclients) + 1) * sizeof (char *)); 5967c478bd9Sstevel@tonic-gate if (clients_new == NULL) { 5977c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 5987c478bd9Sstevel@tonic-gate "MPXIO: cannot reallocate client array (%s).\n", 5997c478bd9Sstevel@tonic-gate strerror(errno)); 6007c478bd9Sstevel@tonic-gate return (-1); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate for (i = old_nclients; i < (*nclients); i++) { 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * Don't allocate space for individual disks in the 6057c478bd9Sstevel@tonic-gate * merged list. Just make references to the previously 6067c478bd9Sstevel@tonic-gate * allocated strings in the group_t structs themselves. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate clients_new[i] = group->clients[i - old_nclients]; 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate clients_new[(*nclients)] = NULL; 6117c478bd9Sstevel@tonic-gate *clientsp = clients_new; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate return (0); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * A libdevinfo di_walk_node() callback. It's passed an integer pointer as an 6197c478bd9Sstevel@tonic-gate * argument, and it increments the integer each time it encounters an MPxIO 6207c478bd9Sstevel@tonic-gate * client. By initializing the integer to zero and doing a libdevinfo walk with 6217c478bd9Sstevel@tonic-gate * this function, the total count of MPxIO clients in the system can be found. 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate static int 6247c478bd9Sstevel@tonic-gate get_nclients(di_node_t dinode, void *arg) 6257c478bd9Sstevel@tonic-gate { 6267c478bd9Sstevel@tonic-gate int *nclients = arg; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate if (is_client(dinode)) 6297c478bd9Sstevel@tonic-gate (*nclients)++; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate /* 6357c478bd9Sstevel@tonic-gate * Tests a libdevinfo node to determine if it's an MPxIO client. 6367c478bd9Sstevel@tonic-gate * 6377c478bd9Sstevel@tonic-gate * Returns: non-zero for true, 0 for false. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate static int 6407c478bd9Sstevel@tonic-gate is_client(di_node_t dinode) 6417c478bd9Sstevel@tonic-gate { 642602ca9eaScth return (di_path_client_next_path(dinode, DI_PATH_NIL) != DI_PATH_NIL); 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * After a new group_list has been constructed, this refreshes the RCM 6477c478bd9Sstevel@tonic-gate * registrations and the reg_list contents. It uses a clock like algorithm 6487c478bd9Sstevel@tonic-gate * with reference bits in the reg_list to know which registrants are new or 6497c478bd9Sstevel@tonic-gate * old. 6507c478bd9Sstevel@tonic-gate */ 6517c478bd9Sstevel@tonic-gate static void 6527c478bd9Sstevel@tonic-gate refresh_regs(rcm_handle_t *hdl) 6537c478bd9Sstevel@tonic-gate { 6547c478bd9Sstevel@tonic-gate int i; 6557c478bd9Sstevel@tonic-gate group_t *group; 6567c478bd9Sstevel@tonic-gate phci_list_t *reg; 6577c478bd9Sstevel@tonic-gate phci_list_t *prev_reg; 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate /* 6607c478bd9Sstevel@tonic-gate * First part of the clock-like algorithm: clear reference bits. 6617c478bd9Sstevel@tonic-gate */ 6627c478bd9Sstevel@tonic-gate for (reg = reg_list; reg != NULL; reg = reg->next) 6637c478bd9Sstevel@tonic-gate reg->referenced = CACHE_STALE; 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* 6667c478bd9Sstevel@tonic-gate * Second part of the clock-like algorithm: set the reference bits 6677c478bd9Sstevel@tonic-gate * on every registrant that's still active. (Also add new list nodes 6687c478bd9Sstevel@tonic-gate * for new registrants.) 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate for (group = group_list; group != NULL; group = group->next) { 6717c478bd9Sstevel@tonic-gate for (i = 0; i < group->nphcis; i++) { 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* 6747c478bd9Sstevel@tonic-gate * If already stale in the registrants list, just set 6757c478bd9Sstevel@tonic-gate * its reference bit to REFERENCED and update its state. 6767c478bd9Sstevel@tonic-gate */ 6777c478bd9Sstevel@tonic-gate if ((reg = lookup_phci(group->phcis[i].path)) != NULL) { 6787c478bd9Sstevel@tonic-gate if (reg->referenced == CACHE_STALE) 6797c478bd9Sstevel@tonic-gate reg->referenced = CACHE_REFERENCED; 6807c478bd9Sstevel@tonic-gate reg->phci.state = group->phcis[i].state; 6817c478bd9Sstevel@tonic-gate continue; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * Otherwise, build a new list node and mark it NEW. 6867c478bd9Sstevel@tonic-gate */ 6877c478bd9Sstevel@tonic-gate reg = (phci_list_t *)calloc(1, sizeof (*reg)); 6887c478bd9Sstevel@tonic-gate if (reg == NULL) { 6897c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 6907c478bd9Sstevel@tonic-gate "MPXIO: cannot allocate phci_list (%s).\n", 6917c478bd9Sstevel@tonic-gate strerror(errno)); 6927c478bd9Sstevel@tonic-gate continue; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate reg->phci.path = strdup(group->phcis[i].path); 6957c478bd9Sstevel@tonic-gate if (reg->phci.path == NULL) { 6967c478bd9Sstevel@tonic-gate free(reg); 6977c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 6987c478bd9Sstevel@tonic-gate "MPXIO: cannot allocate phci path (%s).\n", 6997c478bd9Sstevel@tonic-gate strerror(errno)); 7007c478bd9Sstevel@tonic-gate continue; 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate reg->phci.state = group->phcis[i].state; 7037c478bd9Sstevel@tonic-gate reg->referenced = CACHE_NEW; 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* Link it at the head of reg_list */ 7067c478bd9Sstevel@tonic-gate reg->next = reg_list; 7077c478bd9Sstevel@tonic-gate reg_list = reg; 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * Final part of the clock algorithm: unregister stale entries, and 7137c478bd9Sstevel@tonic-gate * register new entries. Stale entries get removed from the list. 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate reg = reg_list; 7167c478bd9Sstevel@tonic-gate prev_reg = NULL; 7177c478bd9Sstevel@tonic-gate while (reg) { 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* Unregister and remove stale entries. */ 7207c478bd9Sstevel@tonic-gate if (reg->referenced == CACHE_STALE) { 7217c478bd9Sstevel@tonic-gate (void) rcm_unregister_interest(hdl, reg->phci.path, 0); 7227c478bd9Sstevel@tonic-gate free(reg->phci.path); 7237c478bd9Sstevel@tonic-gate if (prev_reg == NULL) { 7247c478bd9Sstevel@tonic-gate reg_list = reg->next; 7257c478bd9Sstevel@tonic-gate free(reg); 7267c478bd9Sstevel@tonic-gate reg = reg_list; 7277c478bd9Sstevel@tonic-gate } else { 7287c478bd9Sstevel@tonic-gate prev_reg->next = reg->next; 7297c478bd9Sstevel@tonic-gate free(reg); 7307c478bd9Sstevel@tonic-gate reg = prev_reg->next; 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate continue; 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* Register new entries. */ 7367c478bd9Sstevel@tonic-gate if (reg->referenced == CACHE_NEW) { 7377c478bd9Sstevel@tonic-gate if (rcm_register_interest(hdl, reg->phci.path, 0, NULL) 7387c478bd9Sstevel@tonic-gate != RCM_SUCCESS) { 7397c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 7407c478bd9Sstevel@tonic-gate "MPXIO: failed to register %s (%s).\n", 7417c478bd9Sstevel@tonic-gate reg->phci.path, strerror(errno)); 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate prev_reg = reg; 7467c478bd9Sstevel@tonic-gate reg = reg->next; 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * A libdevinfo di_walk_node() callback that builds up the MPxIO group list. 7537c478bd9Sstevel@tonic-gate * 7547c478bd9Sstevel@tonic-gate * Every node encountered that's a client node is added into a group's client 7557c478bd9Sstevel@tonic-gate * list. Whenever a group doesn't already exist with a matching set of 7567c478bd9Sstevel@tonic-gate * related PHCIs, then a new group is constructed and put at the head of the 7577c478bd9Sstevel@tonic-gate * group list. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate static int 7607c478bd9Sstevel@tonic-gate build_groups(di_node_t dinode, void *arg) 7617c478bd9Sstevel@tonic-gate { 7627c478bd9Sstevel@tonic-gate int i = 0; 7637c478bd9Sstevel@tonic-gate int nphcis = 0; 7647c478bd9Sstevel@tonic-gate int *nclients = (int *)arg; 7657c478bd9Sstevel@tonic-gate phci_t *phcis; 7667c478bd9Sstevel@tonic-gate group_t *group; 7677c478bd9Sstevel@tonic-gate di_node_t phcinode; 7687c478bd9Sstevel@tonic-gate di_path_t dipath = DI_PATH_NIL; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* Safety check */ 7717c478bd9Sstevel@tonic-gate if (nclients == NULL) 7727c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * Build a sorted array of PHCIs pertaining to the client. 7767c478bd9Sstevel@tonic-gate */ 777602ca9eaScth while ((dipath = 778602ca9eaScth di_path_client_next_path(dinode, dipath)) != DI_PATH_NIL) 7797c478bd9Sstevel@tonic-gate nphcis++; 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* Skip non-clients. */ 7827c478bd9Sstevel@tonic-gate if (nphcis == 0) 7837c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate if ((phcis = (phci_t *)calloc(nphcis, sizeof (phci_t))) == NULL) { 7867c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 7877c478bd9Sstevel@tonic-gate "MPXIO: failed to allocate client's PHCIs (%s).\n", 7887c478bd9Sstevel@tonic-gate strerror(errno)); 7897c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 7907c478bd9Sstevel@tonic-gate } 791602ca9eaScth while ((dipath = 792602ca9eaScth di_path_client_next_path(dinode, dipath)) != DI_PATH_NIL) { 7937c478bd9Sstevel@tonic-gate phcinode = di_path_phci_node(dipath); 7947c478bd9Sstevel@tonic-gate if (phcinode == DI_NODE_NIL) { 7957c478bd9Sstevel@tonic-gate free_phcis(i, phcis); /* free preceeding PHCIs */ 7967c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 7977c478bd9Sstevel@tonic-gate "MPXIO: client appears to have no PHCIs.\n"); 7987c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate if ((phcis[i].path = get_rsrcname(phcinode)) == NULL) { 8017c478bd9Sstevel@tonic-gate free_phcis(i, phcis); 8027c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate phcis[i].state = di_path_state(dipath); 8057c478bd9Sstevel@tonic-gate i++; 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate qsort(phcis, nphcis, sizeof (phci_t), compare_phci); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * Compare that PHCI set to each existing group's set. We just add 8117c478bd9Sstevel@tonic-gate * the client to the group and exit successfully once a match is made. 8127c478bd9Sstevel@tonic-gate * Falling out of this loop means no match was found. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate for (group = group_list; group != NULL; group = group->next) { 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /* There is no match if the number of PHCIs is inequal */ 8177c478bd9Sstevel@tonic-gate if (nphcis != group->nphcis) 8187c478bd9Sstevel@tonic-gate continue; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* Compare the PHCIs linearly (which is okay; they're sorted) */ 8217c478bd9Sstevel@tonic-gate for (i = 0; i < nphcis; i++) 8227c478bd9Sstevel@tonic-gate if (strcmp(phcis[i].path, group->phcis[i].path) != 0) 8237c478bd9Sstevel@tonic-gate break; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * If the loop above completed, we have a match. Add the client 8277c478bd9Sstevel@tonic-gate * to the group's disk array in that case, and return 8287c478bd9Sstevel@tonic-gate * successfully. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate if (i == nphcis) { 8317c478bd9Sstevel@tonic-gate free_phcis(nphcis, phcis); 8327c478bd9Sstevel@tonic-gate if ((group->clients[group->nclients] = 8337c478bd9Sstevel@tonic-gate get_rsrcname(dinode)) == NULL) 8347c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8357c478bd9Sstevel@tonic-gate group->nclients++; 8367c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 8377c478bd9Sstevel@tonic-gate } 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate /* The loop above didn't find a match. So build a new group. */ 8417c478bd9Sstevel@tonic-gate if ((group = (group_t *)calloc(1, sizeof (*group))) == NULL) { 8427c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 8437c478bd9Sstevel@tonic-gate "MPXIO: failed to allocate PHCI group (%s).\n", 8447c478bd9Sstevel@tonic-gate strerror(errno)); 8457c478bd9Sstevel@tonic-gate free_phcis(nphcis, phcis); 8467c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate if ((group->clients = (char **)calloc(*nclients, sizeof (char *))) == 8497c478bd9Sstevel@tonic-gate NULL) { 8507c478bd9Sstevel@tonic-gate free(group); 8517c478bd9Sstevel@tonic-gate free_phcis(nphcis, phcis); 8527c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate group->nphcis = nphcis; 8557c478bd9Sstevel@tonic-gate group->phcis = phcis; 8567c478bd9Sstevel@tonic-gate if ((group->clients[0] = get_rsrcname(dinode)) == NULL) { 8577c478bd9Sstevel@tonic-gate free_group(group); 8587c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate group->nclients = 1; 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate /* Link the group into the group list and return successfully. */ 8637c478bd9Sstevel@tonic-gate group->next = group_list; 8647c478bd9Sstevel@tonic-gate group_list = group; 8657c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * For bsearch() and qsort(). Returns the results of a strcmp() on the names 8707c478bd9Sstevel@tonic-gate * of two phci_t's. 8717c478bd9Sstevel@tonic-gate */ 8727c478bd9Sstevel@tonic-gate static int 8737c478bd9Sstevel@tonic-gate compare_phci(const void *arg1, const void *arg2) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate phci_t *p1 = (phci_t *)arg1; 8767c478bd9Sstevel@tonic-gate phci_t *p2 = (phci_t *)arg2; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate if ((p1 == NULL) || (p2 == NULL)) { 8797c478bd9Sstevel@tonic-gate if (p1 != NULL) 8807c478bd9Sstevel@tonic-gate return (-1); 8817c478bd9Sstevel@tonic-gate else if (p2 != NULL) 8827c478bd9Sstevel@tonic-gate return (1); 8837c478bd9Sstevel@tonic-gate return (0); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate return (strcmp(p1->path, p2->path)); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate /* 8907c478bd9Sstevel@tonic-gate * Free the whole list of group's in the global group_list. 8917c478bd9Sstevel@tonic-gate */ 8927c478bd9Sstevel@tonic-gate static void 8937c478bd9Sstevel@tonic-gate free_grouplist() 8947c478bd9Sstevel@tonic-gate { 8957c478bd9Sstevel@tonic-gate group_t *group = group_list; 8967c478bd9Sstevel@tonic-gate group_t *next; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate while (group) { 8997c478bd9Sstevel@tonic-gate next = group->next; 9007c478bd9Sstevel@tonic-gate free_group(group); 9017c478bd9Sstevel@tonic-gate group = next; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate group_list = NULL; 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * Free the contents of a single group_t. 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate static void 9117c478bd9Sstevel@tonic-gate free_group(group_t *group) 9127c478bd9Sstevel@tonic-gate { 9137c478bd9Sstevel@tonic-gate if (group) { 9147c478bd9Sstevel@tonic-gate free_phcis(group->nphcis, group->phcis); 9157c478bd9Sstevel@tonic-gate free_clients(group->nclients, group->clients); 9167c478bd9Sstevel@tonic-gate free(group); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* 9217c478bd9Sstevel@tonic-gate * Free an array of clients. 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate static void 9247c478bd9Sstevel@tonic-gate free_clients(int nclients, char **clients) 9257c478bd9Sstevel@tonic-gate { 9267c478bd9Sstevel@tonic-gate int i; 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate if (clients != NULL) { 9297c478bd9Sstevel@tonic-gate if (nclients > 0) { 9307c478bd9Sstevel@tonic-gate for (i = 0; i < nclients; i++) 9317c478bd9Sstevel@tonic-gate if (clients[i]) 9327c478bd9Sstevel@tonic-gate free(clients[i]); 9337c478bd9Sstevel@tonic-gate } 9347c478bd9Sstevel@tonic-gate free(clients); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate /* 9397c478bd9Sstevel@tonic-gate * Free an array of phci_t's. 9407c478bd9Sstevel@tonic-gate */ 9417c478bd9Sstevel@tonic-gate static void 9427c478bd9Sstevel@tonic-gate free_phcis(int nphcis, phci_t *phcis) 9437c478bd9Sstevel@tonic-gate { 9447c478bd9Sstevel@tonic-gate int i; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if ((phcis != NULL) && (nphcis > 0)) { 9477c478bd9Sstevel@tonic-gate for (i = 0; i < nphcis; i++) 9487c478bd9Sstevel@tonic-gate if (phcis[i].path) 9497c478bd9Sstevel@tonic-gate free(phcis[i].path); 9507c478bd9Sstevel@tonic-gate free(phcis); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Converts a libdevinfo node into a /devices path. Caller must free results. 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate static char * 9587c478bd9Sstevel@tonic-gate get_rsrcname(di_node_t dinode) 9597c478bd9Sstevel@tonic-gate { 9607c478bd9Sstevel@tonic-gate int len; 9617c478bd9Sstevel@tonic-gate char *rsrcname; 9627c478bd9Sstevel@tonic-gate char *devfspath; 9637c478bd9Sstevel@tonic-gate char name[MAXPATHLEN]; 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate if ((devfspath = di_devfs_path(dinode)) == NULL) { 9667c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "MPXIO: resource has null path.\n"); 9677c478bd9Sstevel@tonic-gate return (NULL); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate len = snprintf(name, sizeof (name), "/devices%s", devfspath); 9717c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath); 9727c478bd9Sstevel@tonic-gate if (len >= sizeof (name)) { 9737c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, "MPXIO: resource path too long.\n"); 9747c478bd9Sstevel@tonic-gate return (NULL); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate if ((rsrcname = strdup(name)) == NULL) 9787c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 9797c478bd9Sstevel@tonic-gate "MPXIO: failed to allocate resource name (%s).\n", 9807c478bd9Sstevel@tonic-gate strerror(errno)); 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate return (rsrcname); 9837c478bd9Sstevel@tonic-gate } 984