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 5*25e8c5aaSvikram * Common Development and Distribution License (the "License"). 6*25e8c5aaSvikram * 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 * 21*25e8c5aaSvikram * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 227c478bd9Sstevel@tonic-gate * Use is subject to license terms. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <librcm_impl.h> 287c478bd9Sstevel@tonic-gate #include "rcm_impl.h" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate static int query(char **, int, const char *, int, pid_t, uint_t, timespec_t *, 317c478bd9Sstevel@tonic-gate int, rcm_info_t **, int *); 327c478bd9Sstevel@tonic-gate static void cancel_query(int, const char *, pid_t, uint_t, int); 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * The following ops are invoked when modules initiate librcm calls which 367c478bd9Sstevel@tonic-gate * require daemon processing. Cascaded RCM operations must come through 377c478bd9Sstevel@tonic-gate * this path. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate librcm_ops_t rcm_ops = { 407c478bd9Sstevel@tonic-gate add_resource_client, 417c478bd9Sstevel@tonic-gate remove_resource_client, 427c478bd9Sstevel@tonic-gate get_resource_info, 437c478bd9Sstevel@tonic-gate process_resource_suspend, 447c478bd9Sstevel@tonic-gate notify_resource_resume, 457c478bd9Sstevel@tonic-gate process_resource_offline, 467c478bd9Sstevel@tonic-gate notify_resource_online, 477c478bd9Sstevel@tonic-gate notify_resource_remove, 487c478bd9Sstevel@tonic-gate request_capacity_change, 497c478bd9Sstevel@tonic-gate notify_capacity_change, 507c478bd9Sstevel@tonic-gate notify_resource_event, 517c478bd9Sstevel@tonic-gate get_resource_state 527c478bd9Sstevel@tonic-gate }; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * Process a request or a notification on a subtree 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 587c478bd9Sstevel@tonic-gate static int 597c478bd9Sstevel@tonic-gate common_resource_op(int cmd, char *rsrcname, pid_t pid, uint_t flag, int seq_num, 607c478bd9Sstevel@tonic-gate timespec_t *interval, nvlist_t *nvl, rcm_info_t **info) 617c478bd9Sstevel@tonic-gate { 627c478bd9Sstevel@tonic-gate int error; 637c478bd9Sstevel@tonic-gate rsrc_node_t *node; 647c478bd9Sstevel@tonic-gate tree_walk_arg_t arg; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * Find the node (root of subtree) in the resource tree, invoke 687c478bd9Sstevel@tonic-gate * appropriate callbacks for all clients hanging off the subtree, 697c478bd9Sstevel@tonic-gate * and mark the subtree with the appropriate state. 707c478bd9Sstevel@tonic-gate * 717c478bd9Sstevel@tonic-gate * NOTE: It's possible the node doesn't exist, which means no RCM 727c478bd9Sstevel@tonic-gate * consumer registered for the resource. In this case we silently 737c478bd9Sstevel@tonic-gate * succeed. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate error = rsrc_node_find(rsrcname, 0, &node); 767c478bd9Sstevel@tonic-gate if ((error == RCM_SUCCESS) && (node != NULL)) { 777c478bd9Sstevel@tonic-gate arg.flag = flag; 787c478bd9Sstevel@tonic-gate arg.info = info; 797c478bd9Sstevel@tonic-gate arg.seq_num = seq_num; 807c478bd9Sstevel@tonic-gate arg.interval = interval; 817c478bd9Sstevel@tonic-gate arg.nvl = nvl; 827c478bd9Sstevel@tonic-gate arg.cmd = cmd; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate if ((cmd == CMD_NOTIFY_CHANGE) || 857c478bd9Sstevel@tonic-gate (cmd == CMD_REQUEST_CHANGE) || 867c478bd9Sstevel@tonic-gate (cmd == CMD_EVENT)) { 877c478bd9Sstevel@tonic-gate error = rsrc_client_action_list(node->users, cmd, &arg); 887c478bd9Sstevel@tonic-gate } else { 897c478bd9Sstevel@tonic-gate error = rsrc_tree_action(node, cmd, &arg); 907c478bd9Sstevel@tonic-gate } 91*25e8c5aaSvikram } else if ((error == RCM_SUCCESS) && (flag & RCM_RETIRE_REQUEST)) { 92*25e8c5aaSvikram /* 93*25e8c5aaSvikram * No matching node, so no client. This means there 94*25e8c5aaSvikram * is no constraint (RCM wise) on this retire. Return 95*25e8c5aaSvikram * RCM_NO_CONSTRAINT to indicate this 96*25e8c5aaSvikram */ 97*25e8c5aaSvikram rcm_log_message(RCM_TRACE1, "No client. Returning " 98*25e8c5aaSvikram "RCM_NO_CONSTRAINT: %s\n", rsrcname); 99*25e8c5aaSvikram error = RCM_NO_CONSTRAINT; 1007c478bd9Sstevel@tonic-gate } 101*25e8c5aaSvikram 1027c478bd9Sstevel@tonic-gate return (error); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * When a resource is removed, notify all clients who registered for this 1077c478bd9Sstevel@tonic-gate * particular resource. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate int 1107c478bd9Sstevel@tonic-gate notify_resource_remove(char **rsrcnames, pid_t pid, uint_t flag, int seq_num, 1117c478bd9Sstevel@tonic-gate rcm_info_t **info) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate int i; 1147c478bd9Sstevel@tonic-gate int error; 1157c478bd9Sstevel@tonic-gate int retval = RCM_SUCCESS; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 1207c478bd9Sstevel@tonic-gate "notify_resource_remove(%s, %ld, 0x%x, %d)\n", rsrcnames[i], 1217c478bd9Sstevel@tonic-gate pid, flag, seq_num); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * Mark state as issuing removal notification. Return failure 1257c478bd9Sstevel@tonic-gate * if no DR request for this node exists. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate error = dr_req_update(rsrcnames[i], pid, flag, 1287c478bd9Sstevel@tonic-gate RCM_STATE_REMOVING, seq_num, info); 1297c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 1307c478bd9Sstevel@tonic-gate retval = error; 1317c478bd9Sstevel@tonic-gate continue; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_REMOVE, rsrcnames[i], pid, flag, 1357c478bd9Sstevel@tonic-gate seq_num, NULL, NULL, info); 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * delete the request entry from DR list 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate dr_req_remove(rsrcnames[i], flag); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) 1437c478bd9Sstevel@tonic-gate retval = error; 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate return (retval); 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * Notify users that a resource has been resumed 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate int 1537c478bd9Sstevel@tonic-gate notify_resource_resume(char **rsrcnames, pid_t pid, uint_t flag, int seq_num, 1547c478bd9Sstevel@tonic-gate rcm_info_t **info) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate int i; 1577c478bd9Sstevel@tonic-gate int error; 1587c478bd9Sstevel@tonic-gate rcm_info_t *state_info; 1597c478bd9Sstevel@tonic-gate rcm_info_tuple_t *state_tuple; 1607c478bd9Sstevel@tonic-gate int retval = RCM_SUCCESS; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate state_info = NULL; 1657c478bd9Sstevel@tonic-gate state_tuple = NULL; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* Check resource state (was resource actually suspended?) */ 1687c478bd9Sstevel@tonic-gate if (get_resource_state(rsrcnames[i], pid, &state_info) || 1697c478bd9Sstevel@tonic-gate ((state_tuple = rcm_info_next(state_info, NULL)) == NULL) || 1707c478bd9Sstevel@tonic-gate (rcm_info_state(state_tuple) == RCM_STATE_SUSPEND)) 1717c478bd9Sstevel@tonic-gate flag |= RCM_SUSPENDED; 1727c478bd9Sstevel@tonic-gate if (state_info) 1737c478bd9Sstevel@tonic-gate rcm_free_info(state_info); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 1767c478bd9Sstevel@tonic-gate "notify_resource_resume(%s, %ld, 0x%x, %d)\n", 1777c478bd9Sstevel@tonic-gate rsrcnames[i], pid, flag, seq_num); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Mark state as sending resumption notifications 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate error = dr_req_update(rsrcnames[i], pid, flag, 1837c478bd9Sstevel@tonic-gate RCM_STATE_RESUMING, seq_num, info); 1847c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 1857c478bd9Sstevel@tonic-gate retval = error; 1867c478bd9Sstevel@tonic-gate continue; 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_RESUME, rsrcnames[i], pid, flag, 1907c478bd9Sstevel@tonic-gate seq_num, NULL, NULL, info); 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate dr_req_remove(rsrcnames[i], flag); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) 1957c478bd9Sstevel@tonic-gate retval = error; 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate return (retval); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Notify users that an offlined device is again available 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate int 2057c478bd9Sstevel@tonic-gate notify_resource_online(char **rsrcnames, pid_t pid, uint_t flag, int seq_num, 2067c478bd9Sstevel@tonic-gate rcm_info_t **info) 2077c478bd9Sstevel@tonic-gate { 2087c478bd9Sstevel@tonic-gate int i; 2097c478bd9Sstevel@tonic-gate int error; 2107c478bd9Sstevel@tonic-gate int retval = RCM_SUCCESS; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 2157c478bd9Sstevel@tonic-gate "notify_resource_online(%s, %ld, 0x%x, %d)\n", 2167c478bd9Sstevel@tonic-gate rsrcnames[i], pid, flag, seq_num); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate /* 2197c478bd9Sstevel@tonic-gate * Mark state as sending onlining notifications 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate error = dr_req_update(rsrcnames[i], pid, flag, 2227c478bd9Sstevel@tonic-gate RCM_STATE_ONLINING, seq_num, info); 2237c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 2247c478bd9Sstevel@tonic-gate retval = error; 2257c478bd9Sstevel@tonic-gate continue; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_ONLINE, rsrcnames[i], pid, flag, 2297c478bd9Sstevel@tonic-gate seq_num, NULL, NULL, info); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate dr_req_remove(rsrcnames[i], flag); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) 2347c478bd9Sstevel@tonic-gate retval = error; 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate return (retval); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * For offline and suspend, need to get the logic correct here. There are 2427c478bd9Sstevel@tonic-gate * several cases: 2437c478bd9Sstevel@tonic-gate * 2447c478bd9Sstevel@tonic-gate * 1. It is a door call and RCM_QUERY is not set: 2457c478bd9Sstevel@tonic-gate * run a QUERY; if that succeeds, run the operation. 2467c478bd9Sstevel@tonic-gate * 2477c478bd9Sstevel@tonic-gate * 2. It is a door call and RCM_QUERY is set: 2487c478bd9Sstevel@tonic-gate * run the QUERY only. 2497c478bd9Sstevel@tonic-gate * 2507c478bd9Sstevel@tonic-gate * 3. It is not a door call: 2517c478bd9Sstevel@tonic-gate * run the call, but look at the flag to see if the 2527c478bd9Sstevel@tonic-gate * lock should be kept. 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * Request permission to suspend a resource 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate int 2597c478bd9Sstevel@tonic-gate process_resource_suspend(char **rsrcnames, pid_t pid, uint_t flag, int seq_num, 2607c478bd9Sstevel@tonic-gate timespec_t *interval, rcm_info_t **info) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate int i; 2637c478bd9Sstevel@tonic-gate int error = RCM_SUCCESS; 2647c478bd9Sstevel@tonic-gate int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * Query the operation first. The return value of the query indicates 2687c478bd9Sstevel@tonic-gate * if the operation should proceed and be implemented. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate if (query(rsrcnames, CMD_SUSPEND, "suspend", RCM_STATE_SUSPEND_QUERYING, 2717c478bd9Sstevel@tonic-gate pid, flag, interval, seq_num, info, &error) == 0) { 2727c478bd9Sstevel@tonic-gate return (error); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * Implement the operation. 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* Update the lock from a query state to the suspending state */ 2817c478bd9Sstevel@tonic-gate if ((error = dr_req_update(rsrcnames[i], pid, flag, 2827c478bd9Sstevel@tonic-gate RCM_STATE_SUSPENDING, seq_num, info)) != RCM_SUCCESS) { 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 2857c478bd9Sstevel@tonic-gate "suspend %s denied with error %d\n", rsrcnames[i], 2867c478bd9Sstevel@tonic-gate error); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate /* 2897c478bd9Sstevel@tonic-gate * When called from a module, don't return EAGAIN. 2907c478bd9Sstevel@tonic-gate * This is to avoid recursion if module always retries. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate if (!is_doorcall && error == EAGAIN) { 2937c478bd9Sstevel@tonic-gate return (RCM_CONFLICT); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate return (error); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* Actually suspend the resource */ 3007c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_SUSPEND, rsrcnames[i], pid, 3017c478bd9Sstevel@tonic-gate flag, seq_num, interval, NULL, info); 3027c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 3037c478bd9Sstevel@tonic-gate (void) dr_req_update(rsrcnames[i], pid, flag, 3047c478bd9Sstevel@tonic-gate RCM_STATE_SUSPEND_FAIL, seq_num, info); 3057c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 3067c478bd9Sstevel@tonic-gate "suspend tree failed for %s\n", rsrcnames[i]); 3077c478bd9Sstevel@tonic-gate return (error); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "suspend tree succeeded for %s\n", 3117c478bd9Sstevel@tonic-gate rsrcnames[i]); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate /* Update the lock for the successful suspend */ 3147c478bd9Sstevel@tonic-gate (void) dr_req_update(rsrcnames[i], pid, flag, 3157c478bd9Sstevel@tonic-gate RCM_STATE_SUSPEND, seq_num, info); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * Process a device removal request, reply is needed 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate int 3257c478bd9Sstevel@tonic-gate process_resource_offline(char **rsrcnames, pid_t pid, uint_t flag, int seq_num, 3267c478bd9Sstevel@tonic-gate rcm_info_t **info) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate int i; 3297c478bd9Sstevel@tonic-gate int error = RCM_SUCCESS; 3307c478bd9Sstevel@tonic-gate int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Query the operation first. The return value of the query indicates 3347c478bd9Sstevel@tonic-gate * if the operation should proceed and be implemented. 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate if (query(rsrcnames, CMD_OFFLINE, "offline", RCM_STATE_OFFLINE_QUERYING, 3377c478bd9Sstevel@tonic-gate pid, flag, NULL, seq_num, info, &error) == 0) { 3387c478bd9Sstevel@tonic-gate return (error); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Implement the operation. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate error = dr_req_update(rsrcnames[i], pid, flag, 3477c478bd9Sstevel@tonic-gate RCM_STATE_OFFLINING, seq_num, info); 3487c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 3497c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 3507c478bd9Sstevel@tonic-gate "offline %s denied with error %d\n", rsrcnames[i], 3517c478bd9Sstevel@tonic-gate error); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * When called from a module, don't return EAGAIN. 3557c478bd9Sstevel@tonic-gate * This is to avoid recursion if module always retries. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate if (!is_doorcall && error == EAGAIN) { 3587c478bd9Sstevel@tonic-gate return (RCM_CONFLICT); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate return (error); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* Actually offline the resource */ 3657c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_OFFLINE, rsrcnames[i], pid, 3667c478bd9Sstevel@tonic-gate flag, seq_num, NULL, NULL, info); 3677c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 3687c478bd9Sstevel@tonic-gate (void) dr_req_update(rsrcnames[i], pid, flag, 3697c478bd9Sstevel@tonic-gate RCM_STATE_OFFLINE_FAIL, seq_num, info); 3707c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 3717c478bd9Sstevel@tonic-gate "offline tree failed for %s\n", rsrcnames[i]); 3727c478bd9Sstevel@tonic-gate return (error); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "offline tree succeeded for %s\n", 3767c478bd9Sstevel@tonic-gate rsrcnames[i]); 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* Update the lock for the successful offline */ 3797c478bd9Sstevel@tonic-gate (void) dr_req_update(rsrcnames[i], pid, flag, 3807c478bd9Sstevel@tonic-gate RCM_STATE_OFFLINE, seq_num, info); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * Add a resource client who wishes to interpose on DR, events, or capacity. 3887c478bd9Sstevel@tonic-gate * Reply needed. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate int 3917c478bd9Sstevel@tonic-gate add_resource_client(char *modname, char *rsrcname, pid_t pid, uint_t flag, 3927c478bd9Sstevel@tonic-gate rcm_info_t **infop) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate int error = RCM_SUCCESS; 3957c478bd9Sstevel@tonic-gate client_t *user = NULL; 3967c478bd9Sstevel@tonic-gate rsrc_node_t *node = NULL; 3977c478bd9Sstevel@tonic-gate rcm_info_t *info = NULL; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 4007c478bd9Sstevel@tonic-gate "add_resource_client(%s, %s, %ld, 0x%x)\n", 4017c478bd9Sstevel@tonic-gate modname, rsrcname, pid, flag); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if (strcmp(rsrcname, "/") == 0) { 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * No need to register for / because it will never go away. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate rcm_log_message(RCM_INFO, gettext( 4087c478bd9Sstevel@tonic-gate "registering for / by %s has been turned into a no-op\n"), 4097c478bd9Sstevel@tonic-gate modname); 4107c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * Hold the rcm_req_lock so no dr request may come in while the 4157c478bd9Sstevel@tonic-gate * registration is in progress. 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate (void) mutex_lock(&rcm_req_lock); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * Test if the requested registration is a noop, and return EALREADY 4217c478bd9Sstevel@tonic-gate * if it is. 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate error = rsrc_node_find(rsrcname, RSRC_NODE_CREATE, &node); 4247c478bd9Sstevel@tonic-gate if ((error != RCM_SUCCESS) || (node == NULL)) { 4257c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 4267c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate user = rsrc_client_find(modname, pid, &node->users); 4307c478bd9Sstevel@tonic-gate if ((user != NULL) && 4317c478bd9Sstevel@tonic-gate ((user->flag & (flag & RCM_REGISTER_MASK)) != 0)) { 4327c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 4337c478bd9Sstevel@tonic-gate if ((flag & RCM_REGISTER_DR) && 4347c478bd9Sstevel@tonic-gate (user->state == RCM_STATE_REMOVE)) { 4357c478bd9Sstevel@tonic-gate user->state = RCM_STATE_ONLINE; 4367c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate return (EALREADY); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* If adding a new DR registration, reject if the resource is locked */ 4427c478bd9Sstevel@tonic-gate if (flag & RCM_REGISTER_DR) { 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate if (rsrc_check_lock_conflicts(rsrcname, flag, LOCK_FOR_USE, 4457c478bd9Sstevel@tonic-gate &info) != RCM_SUCCESS) { 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * The resource is being DR'ed, so return failure 4487c478bd9Sstevel@tonic-gate */ 4497c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * If caller doesn't care about info, free it 4537c478bd9Sstevel@tonic-gate */ 4547c478bd9Sstevel@tonic-gate if (infop) 4557c478bd9Sstevel@tonic-gate *infop = info; 4567c478bd9Sstevel@tonic-gate else 4577c478bd9Sstevel@tonic-gate rcm_free_info(info); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate return (RCM_CONFLICT); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* The registration is new and allowable, so add it */ 4647c478bd9Sstevel@tonic-gate error = rsrc_node_add_user(node, rsrcname, modname, pid, flag); 4657c478bd9Sstevel@tonic-gate (void) mutex_unlock(&rcm_req_lock); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate return (error); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate /* 4717c478bd9Sstevel@tonic-gate * Remove a resource client, who no longer wishes to interpose on either 4727c478bd9Sstevel@tonic-gate * DR, events, or capacity. 4737c478bd9Sstevel@tonic-gate */ 4747c478bd9Sstevel@tonic-gate int 4757c478bd9Sstevel@tonic-gate remove_resource_client(char *modname, char *rsrcname, pid_t pid, uint_t flag) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate int error; 4787c478bd9Sstevel@tonic-gate rsrc_node_t *node; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 4817c478bd9Sstevel@tonic-gate "remove_resource_client(%s, %s, %ld, 0x%x)\n", 4827c478bd9Sstevel@tonic-gate modname, rsrcname, pid, flag); 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * Allow resource client to leave anytime, assume client knows what 4867c478bd9Sstevel@tonic-gate * it is trying to do. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate error = rsrc_node_find(rsrcname, 0, &node); 4897c478bd9Sstevel@tonic-gate if ((error != RCM_SUCCESS) || (node == NULL)) { 4907c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 4917c478bd9Sstevel@tonic-gate gettext("resource %s not found\n"), rsrcname); 4927c478bd9Sstevel@tonic-gate return (ENOENT); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate return (rsrc_node_remove_user(node, modname, pid, flag)); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * Reply is needed 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate int 5027c478bd9Sstevel@tonic-gate get_resource_info(char **rsrcnames, uint_t flag, int seq_num, rcm_info_t **info) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate int rv = RCM_SUCCESS; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (flag & RCM_DR_OPERATION) { 5077c478bd9Sstevel@tonic-gate *info = rsrc_dr_info(); 5087c478bd9Sstevel@tonic-gate } else if (flag & RCM_MOD_INFO) { 5097c478bd9Sstevel@tonic-gate *info = rsrc_mod_info(); 5107c478bd9Sstevel@tonic-gate } else { 5117c478bd9Sstevel@tonic-gate rv = rsrc_usage_info(rsrcnames, flag, seq_num, info); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate return (rv); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate int 5187c478bd9Sstevel@tonic-gate notify_resource_event(char *rsrcname, id_t pid, uint_t flag, int seq_num, 5197c478bd9Sstevel@tonic-gate nvlist_t *event_data, rcm_info_t **info) 5207c478bd9Sstevel@tonic-gate { 5217c478bd9Sstevel@tonic-gate int error; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate assert(flag == 0); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "notify_resource_event(%s, %ld, 0x%x)\n", 5267c478bd9Sstevel@tonic-gate rsrcname, pid, flag); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_EVENT, rsrcname, pid, flag, seq_num, 5297c478bd9Sstevel@tonic-gate NULL, event_data, info); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate return (error); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate int 5357c478bd9Sstevel@tonic-gate request_capacity_change(char *rsrcname, id_t pid, uint_t flag, int seq_num, 5367c478bd9Sstevel@tonic-gate nvlist_t *nvl, rcm_info_t **info) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate int error; 5397c478bd9Sstevel@tonic-gate int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0); 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 5427c478bd9Sstevel@tonic-gate "request_capacity_change(%s, %ld, 0x%x, %d)\n", rsrcname, pid, 5437c478bd9Sstevel@tonic-gate flag, seq_num); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate if (is_doorcall || (flag & RCM_QUERY)) { 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_REQUEST_CHANGE, rsrcname, pid, 5487c478bd9Sstevel@tonic-gate flag | RCM_QUERY, seq_num, NULL, nvl, info); 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 5517c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 5527c478bd9Sstevel@tonic-gate "request state change query denied\n"); 5537c478bd9Sstevel@tonic-gate return (error); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate if (flag & RCM_QUERY) 5587c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_REQUEST_CHANGE, rsrcname, pid, flag, 5617c478bd9Sstevel@tonic-gate seq_num, NULL, nvl, info); 5627c478bd9Sstevel@tonic-gate 5637c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 5647c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "request state change failed\n"); 5657c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "request state change succeeded\n"); 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate return (error); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate int 5747c478bd9Sstevel@tonic-gate notify_capacity_change(char *rsrcname, id_t pid, uint_t flag, int seq_num, 5757c478bd9Sstevel@tonic-gate nvlist_t *nvl, rcm_info_t **info) 5767c478bd9Sstevel@tonic-gate { 5777c478bd9Sstevel@tonic-gate int error; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 5807c478bd9Sstevel@tonic-gate "notify_capacity_change(%s, %ld, 0x%x, %d)\n", rsrcname, pid, 5817c478bd9Sstevel@tonic-gate flag, seq_num); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate error = common_resource_op(CMD_NOTIFY_CHANGE, rsrcname, pid, flag, 5847c478bd9Sstevel@tonic-gate seq_num, NULL, nvl, info); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 5877c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "notify state change failed\n"); 5887c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE3, "notify state change succeeded\n"); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate return (error); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate int 5977c478bd9Sstevel@tonic-gate get_resource_state(char *rsrcname, pid_t pid, rcm_info_t **info) 5987c478bd9Sstevel@tonic-gate { 5997c478bd9Sstevel@tonic-gate int error; 6007c478bd9Sstevel@tonic-gate int state; 6017c478bd9Sstevel@tonic-gate char *s; 6027c478bd9Sstevel@tonic-gate char *resolved; 6037c478bd9Sstevel@tonic-gate rcm_info_t *dr_info = NULL; 6047c478bd9Sstevel@tonic-gate rcm_info_tuple_t *dr_info_tuple = NULL; 6057c478bd9Sstevel@tonic-gate rsrc_node_t *node; 6067c478bd9Sstevel@tonic-gate client_t *client; 6077c478bd9Sstevel@tonic-gate char *state_info = gettext("State of resource"); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "get_resource_state(%s, %ld)\n", 6107c478bd9Sstevel@tonic-gate rsrcname, pid); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * Check for locks, first. 6147c478bd9Sstevel@tonic-gate */ 6157c478bd9Sstevel@tonic-gate dr_info = rsrc_dr_info(); 6167c478bd9Sstevel@tonic-gate if (dr_info) { 6177c478bd9Sstevel@tonic-gate state = RCM_STATE_UNKNOWN; 6187c478bd9Sstevel@tonic-gate if ((resolved = resolve_name(rsrcname)) == NULL) 6197c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 6207c478bd9Sstevel@tonic-gate while (dr_info_tuple = rcm_info_next(dr_info, dr_info_tuple)) { 6217c478bd9Sstevel@tonic-gate s = (char *)rcm_info_rsrc(dr_info_tuple); 6227c478bd9Sstevel@tonic-gate if (s && (strcmp(resolved, s) == 0)) { 6237c478bd9Sstevel@tonic-gate state = rcm_info_state(dr_info_tuple); 6247c478bd9Sstevel@tonic-gate break; 6257c478bd9Sstevel@tonic-gate } 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate free(resolved); 6287c478bd9Sstevel@tonic-gate rcm_free_info(dr_info); 6297c478bd9Sstevel@tonic-gate if (state != RCM_STATE_UNKNOWN) { 6307c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 6317c478bd9Sstevel@tonic-gate "get_resource_state(%s)=%d\n", rsrcname, state); 6327c478bd9Sstevel@tonic-gate add_busy_rsrc_to_list(rsrcname, pid, state, 0, NULL, 6337c478bd9Sstevel@tonic-gate (char *)state_info, NULL, NULL, info); 6347c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate /* 6397c478bd9Sstevel@tonic-gate * No locks, so look for client states in the resource tree. 6407c478bd9Sstevel@tonic-gate * 6417c478bd9Sstevel@tonic-gate * NOTE: It's possible the node doesn't exist, which means no RCM 6427c478bd9Sstevel@tonic-gate * consumer registered for the resource. In this case we silently 6437c478bd9Sstevel@tonic-gate * succeed. 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate error = rsrc_node_find(rsrcname, 0, &node); 6467c478bd9Sstevel@tonic-gate state = RCM_STATE_ONLINE; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if ((error == RCM_SUCCESS) && (node != NULL)) { 6497c478bd9Sstevel@tonic-gate for (client = node->users; client; client = client->next) { 6507c478bd9Sstevel@tonic-gate if (client->state == RCM_STATE_OFFLINE_FAIL || 6517c478bd9Sstevel@tonic-gate client->state == RCM_STATE_OFFLINE_QUERY_FAIL || 6527c478bd9Sstevel@tonic-gate client->state == RCM_STATE_SUSPEND_FAIL || 6537c478bd9Sstevel@tonic-gate client->state == RCM_STATE_SUSPEND_QUERY_FAIL) { 6547c478bd9Sstevel@tonic-gate state = client->state; 6557c478bd9Sstevel@tonic-gate break; 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate if (client->state != RCM_STATE_ONLINE && 6597c478bd9Sstevel@tonic-gate client->state != RCM_STATE_REMOVE) 6607c478bd9Sstevel@tonic-gate state = client->state; 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate if (error == RCM_SUCCESS) { 6657c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "get_resource_state(%s)=%d\n", 6667c478bd9Sstevel@tonic-gate rsrcname, state); 6677c478bd9Sstevel@tonic-gate add_busy_rsrc_to_list(rsrcname, pid, state, 0, NULL, 6687c478bd9Sstevel@tonic-gate (char *)state_info, NULL, NULL, info); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate return (error); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * Perform a query of an offline or suspend. 6767c478bd9Sstevel@tonic-gate * 6777c478bd9Sstevel@tonic-gate * The return value of this function indicates whether the operation should 6787c478bd9Sstevel@tonic-gate * be implemented (0 == No, 1 == Yes). Note that locks and client state 6797c478bd9Sstevel@tonic-gate * changes will only persist if the caller is going to implement the operation. 6807c478bd9Sstevel@tonic-gate */ 6817c478bd9Sstevel@tonic-gate static int 6827c478bd9Sstevel@tonic-gate query(char **rsrcnames, int cmd, const char *opname, int querystate, pid_t pid, 6837c478bd9Sstevel@tonic-gate uint_t flag, timespec_t *interval, int seq_num, rcm_info_t **info, 6847c478bd9Sstevel@tonic-gate int *errorp) 6857c478bd9Sstevel@tonic-gate { 6867c478bd9Sstevel@tonic-gate int i; 6877c478bd9Sstevel@tonic-gate int error; 6887c478bd9Sstevel@tonic-gate int final_error; 6897c478bd9Sstevel@tonic-gate int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* Only query for door calls, or when the RCM_QUERY flag is set */ 6927c478bd9Sstevel@tonic-gate if ((is_doorcall == 0) && ((flag & RCM_QUERY) == 0)) { 6937c478bd9Sstevel@tonic-gate return (1); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* Lock all the resources. Fail the query in the case of a conflict. */ 6977c478bd9Sstevel@tonic-gate for (i = 0; rsrcnames[i] != NULL; i++) { 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, 7007c478bd9Sstevel@tonic-gate "process_resource_%s(%s, %ld, 0x%x, %d)\n", 7017c478bd9Sstevel@tonic-gate opname, rsrcnames[i], pid, flag, seq_num); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate error = dr_req_add(rsrcnames[i], pid, flag, querystate, seq_num, 7047c478bd9Sstevel@tonic-gate NULL, info); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* The query goes no further if a resource cannot be locked */ 7077c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, 7107c478bd9Sstevel@tonic-gate "%s query %s defined with error %d\n", 7117c478bd9Sstevel@tonic-gate opname, rsrcnames[i], error); 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * Replace EAGAIN with RCM_CONFLICT in the case of 7157c478bd9Sstevel@tonic-gate * module callbacks; to avoid modules from trying 7167c478bd9Sstevel@tonic-gate * again infinitely. 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate if ((is_doorcall == 0) && (error == EAGAIN)) { 7197c478bd9Sstevel@tonic-gate error = RCM_CONFLICT; 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate goto finished; 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate /* 7277c478bd9Sstevel@tonic-gate * All the resources were locked above, so use common_resource_op() 7287c478bd9Sstevel@tonic-gate * to pass the query on to the clients. Accumulate the overall error 7297c478bd9Sstevel@tonic-gate * value in 'final_error', before transferring it to 'error' at the end. 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate for (final_error = RCM_SUCCESS, i = 0; rsrcnames[i] != NULL; i++) { 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate /* Log the query (for tracing purposes). */ 7347c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "querying resource %s\n", 7357c478bd9Sstevel@tonic-gate rsrcnames[i]); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* Query the resource's clients through common_resource_op(). */ 7387c478bd9Sstevel@tonic-gate error = common_resource_op(cmd, rsrcnames[i], pid, 7397c478bd9Sstevel@tonic-gate flag | RCM_QUERY, seq_num, interval, NULL, info); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate /* 7427c478bd9Sstevel@tonic-gate * If a query fails, don't stop iterating through the loop. 7437c478bd9Sstevel@tonic-gate * Just ensure that 'final_error' is set (if not already), 7447c478bd9Sstevel@tonic-gate * log the error, and continue looping. 7457c478bd9Sstevel@tonic-gate * 7467c478bd9Sstevel@tonic-gate * In the case of a user who manually intervenes and retries 7477c478bd9Sstevel@tonic-gate * the operation, this will maximize the extent of the query 7487c478bd9Sstevel@tonic-gate * so that they experience fewer such iterations overall. 7497c478bd9Sstevel@tonic-gate */ 7507c478bd9Sstevel@tonic-gate if (error != RCM_SUCCESS) { 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* Log each query that failed along the way */ 7537c478bd9Sstevel@tonic-gate rcm_log_message(RCM_DEBUG, "%s %s query denied\n", 7547c478bd9Sstevel@tonic-gate opname, rsrcnames[i]); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate if (final_error != RCM_FAILURE) { 7577c478bd9Sstevel@tonic-gate final_error = error; 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate error = final_error; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * Tell the calling function not to proceed any further with the 7657c478bd9Sstevel@tonic-gate * implementation phase of the operation if the query failed, or 7667c478bd9Sstevel@tonic-gate * if the user's intent was to only query the operation. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate finished: 7697c478bd9Sstevel@tonic-gate if ((error != RCM_SUCCESS) || ((flag & RCM_QUERY) != 0)) { 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * Since the operation won't be implemented, cancel the 7737c478bd9Sstevel@tonic-gate * query (unlock resources and reverse client state changes). 7747c478bd9Sstevel@tonic-gate * 7757c478bd9Sstevel@tonic-gate * The cancellation routine cleans up everything for the entire 7767c478bd9Sstevel@tonic-gate * operation, and thus it should only be called from the very 7777c478bd9Sstevel@tonic-gate * root of the operation (e.g. when 'is_doorcall' is TRUE). 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate if (is_doorcall != 0) { 7807c478bd9Sstevel@tonic-gate cancel_query(cmd, opname, pid, flag, seq_num); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate *errorp = error; 7847c478bd9Sstevel@tonic-gate return (0); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate /* Otherwise, tell the caller to proceed with the implementation. */ 7887c478bd9Sstevel@tonic-gate *errorp = RCM_SUCCESS; 7897c478bd9Sstevel@tonic-gate return (1); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* 7937c478bd9Sstevel@tonic-gate * Implementation of a query cancellation. 7947c478bd9Sstevel@tonic-gate * 7957c478bd9Sstevel@tonic-gate * The full scope of the query is already noted, so the scope of the operation 7967c478bd9Sstevel@tonic-gate * does not need to be expanded in the same recursive manner that was used for 7977c478bd9Sstevel@tonic-gate * the query itself. (Clients don't have to be called to cross namespaces.) 7987c478bd9Sstevel@tonic-gate * Instead, the locks added to the DR request list during the query are scanned. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate static void 8017c478bd9Sstevel@tonic-gate cancel_query(int cmd, const char *opname, pid_t pid, uint_t flag, int seq_num) 8027c478bd9Sstevel@tonic-gate { 8037c478bd9Sstevel@tonic-gate char rsrc[MAXPATHLEN]; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * Find every lock in the DR request list that is a part of this 8077c478bd9Sstevel@tonic-gate * sequence. Call common_resource_op() with the QUERY_CANCEL flag to 8087c478bd9Sstevel@tonic-gate * cancel each sub-operation, and then remove each lock from the list. 8097c478bd9Sstevel@tonic-gate * 8107c478bd9Sstevel@tonic-gate * The 'rsrc' buffer is required to retrieve the 'device' fields of 8117c478bd9Sstevel@tonic-gate * matching DR request list entries in a way that's multi-thread safe. 8127c478bd9Sstevel@tonic-gate */ 8137c478bd9Sstevel@tonic-gate while (dr_req_lookup(seq_num, rsrc) == RCM_SUCCESS) { 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE2, "%s query %s cancelled\n", 8167c478bd9Sstevel@tonic-gate opname, rsrc); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate (void) common_resource_op(cmd, rsrc, pid, 8197c478bd9Sstevel@tonic-gate flag | RCM_QUERY | RCM_QUERY_CANCEL, seq_num, NULL, NULL, 8207c478bd9Sstevel@tonic-gate NULL); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate (void) dr_req_remove(rsrc, flag); 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate } 825