1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 0 stevel * Common Development and Distribution License, Version 1.0 only 6 0 stevel * (the "License"). You may not use this file except in compliance 7 0 stevel * with the License. 8 0 stevel * 9 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 0 stevel * or http://www.opensolaris.org/os/licensing. 11 0 stevel * See the License for the specific language governing permissions 12 0 stevel * and limitations under the License. 13 0 stevel * 14 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 15 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 0 stevel * If applicable, add the following below this CDDL HEADER, with the 17 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 18 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 19 0 stevel * 20 0 stevel * CDDL HEADER END 21 0 stevel */ 22 0 stevel /* 23 0 stevel * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <assert.h> 30 0 stevel #include <ctype.h> 31 0 stevel #include <stdio.h> 32 0 stevel #include <stdlib.h> 33 0 stevel #include <string.h> 34 0 stevel #include <unistd.h> 35 0 stevel #include <macros.h> 36 0 stevel #include <dirent.h> 37 0 stevel #include <libgen.h> 38 0 stevel #include <libdevinfo.h> 39 0 stevel #define CFGA_PLUGIN_LIB 40 0 stevel #include <config_admin.h> 41 0 stevel #include "ap.h" 42 0 stevel 43 0 stevel static cfga_err_t 44 0 stevel ap_suspend_check(apd_t *a, int cmd, int first, int last, int *suspend) 45 0 stevel { 46 0 stevel int c; 47 0 stevel int rc; 48 0 stevel int skip; 49 0 stevel int check; 50 0 stevel 51 0 stevel skip = a->opts.skip; 52 0 stevel 53 0 stevel /* 54 0 stevel * Check if any of the steps in the sequence 55 0 stevel * may require a suspension of service and ask 56 0 stevel * the user to confirm. 57 0 stevel */ 58 0 stevel for (check = 0, c = first; c <= last; c++) 59 0 stevel if (mask(c) & skip) 60 0 stevel continue; 61 0 stevel else if ((rc = ap_suspend_query(a, c, &check)) != CFGA_OK) 62 0 stevel return (rc); 63 0 stevel 64 0 stevel *suspend = check; 65 0 stevel 66 0 stevel /* 67 0 stevel * If a suspend is required, ask for user confirmation. 68 0 stevel * The force flag overrides the user confirmation. 69 0 stevel */ 70 0 stevel if (check && (!ap_getopt(a, OPT_FORCE)) && (!ap_confirm(a))) { 71 0 stevel ap_err(a, ERR_CMD_NACK, cmd); 72 0 stevel return (CFGA_NACK); 73 0 stevel } 74 0 stevel 75 0 stevel return (CFGA_OK); 76 0 stevel } 77 0 stevel 78 0 stevel #define AP_SEQ_OK 0 79 0 stevel #define AP_SEQ_NULL 1 80 0 stevel #define AP_SEQ_FAIL -1 81 0 stevel 82 0 stevel /* 83 0 stevel * Sequence a cfgadm state change command into driver commands. 84 0 stevel * The rstate and ostate of the AP are needed at this point 85 0 stevel * in order to compute the proper sequence. 86 0 stevel */ 87 0 stevel static int 88 0 stevel ap_seq_get(apd_t *a, int cmd, int *first, int *last) 89 0 stevel { 90 0 stevel int done = 0; 91 0 stevel int f = CMD_NONE; 92 0 stevel int l = CMD_NONE; 93 0 stevel cfga_stat_t rs, os; 94 0 stevel 95 0 stevel ap_state(a, &rs, &os); 96 0 stevel 97 0 stevel switch (rs) { 98 0 stevel case CFGA_STAT_EMPTY: 99 0 stevel switch (os) { 100 0 stevel case CFGA_STAT_UNCONFIGURED: 101 0 stevel switch (cmd) { 102 0 stevel case CMD_UNCONFIGURE: 103 0 stevel done++; 104 0 stevel break; 105 0 stevel default: 106 0 stevel break; 107 0 stevel } 108 0 stevel break; 109 0 stevel default: 110 0 stevel break; 111 0 stevel } 112 0 stevel break; 113 0 stevel case CFGA_STAT_DISCONNECTED: 114 0 stevel switch (os) { 115 0 stevel case CFGA_STAT_UNCONFIGURED: 116 0 stevel switch (cmd) { 117 0 stevel case CMD_DISCONNECT: 118 0 stevel /* 119 0 stevel * skip the disconnect command since 120 0 stevel * the rstate is already disconnected 121 0 stevel */ 122 0 stevel f = CMD_DISCONNECT; 123 0 stevel a->opts.skip |= mask(CMD_DISCONNECT); 124 0 stevel l = CMD_UNASSIGN; 125 0 stevel break; 126 0 stevel case CMD_UNCONFIGURE: 127 0 stevel done++; 128 0 stevel break; 129 0 stevel case CMD_CONNECT: 130 0 stevel f = CMD_ASSIGN; 131 0 stevel l = CMD_CONNECT; 132 0 stevel break; 133 0 stevel case CMD_CONFIGURE: 134 0 stevel f = CMD_ASSIGN; 135 0 stevel l = CMD_RCM_CAP_ADD; 136 0 stevel break; 137 0 stevel default: 138 0 stevel break; 139 0 stevel } 140 0 stevel break; 141 0 stevel default: 142 0 stevel break; 143 0 stevel } 144 0 stevel break; 145 0 stevel case CFGA_STAT_CONNECTED: 146 0 stevel switch (os) { 147 0 stevel case CFGA_STAT_UNCONFIGURED: 148 0 stevel switch (cmd) { 149 0 stevel case CMD_CONNECT: 150 0 stevel case CMD_UNCONFIGURE: 151 0 stevel done++; 152 0 stevel break; 153 0 stevel case CMD_DISCONNECT: 154 0 stevel f = CMD_DISCONNECT; 155 0 stevel l = CMD_UNASSIGN; 156 0 stevel break; 157 0 stevel case CMD_CONFIGURE: 158 0 stevel f = CMD_CONFIGURE; 159 0 stevel l = CMD_RCM_CAP_ADD; 160 0 stevel break; 161 0 stevel default: 162 0 stevel break; 163 0 stevel } 164 0 stevel break; 165 0 stevel case CFGA_STAT_CONFIGURED: 166 0 stevel switch (cmd) { 167 0 stevel case CMD_CONNECT: 168 0 stevel done++; 169 0 stevel break; 170 0 stevel case CMD_DISCONNECT: 171 0 stevel f = CMD_SUSPEND_CHECK; 172 0 stevel l = CMD_UNASSIGN; 173 0 stevel break; 174 0 stevel case CMD_CONFIGURE: 175 0 stevel f = CMD_CONFIGURE; 176 0 stevel l = CMD_RCM_CAP_ADD; 177 0 stevel break; 178 0 stevel case CMD_UNCONFIGURE: 179 0 stevel f = CMD_SUSPEND_CHECK; 180 0 stevel l = CMD_RCM_CAP_NOTIFY; 181 0 stevel break; 182 0 stevel default: 183 0 stevel break; 184 0 stevel } 185 0 stevel break; 186 0 stevel default: 187 0 stevel break; 188 0 stevel } 189 0 stevel break; 190 0 stevel default: 191 0 stevel break; 192 0 stevel } 193 0 stevel 194 0 stevel if (f == CMD_NONE) { 195 0 stevel if (done) 196 0 stevel return (AP_SEQ_NULL); 197 0 stevel ap_err(a, ERR_TRANS_INVAL, cmd); 198 0 stevel return (AP_SEQ_FAIL); 199 0 stevel } 200 0 stevel 201 0 stevel *first = f; 202 0 stevel *last = l; 203 0 stevel 204 0 stevel DBG("ap_seq(%d, %d, %d, %p, %p) = (%d, %d)\n", 205 0 stevel rs, os, cmd, (void *)first, (void *)last, f, l); 206 0 stevel 207 0 stevel return (AP_SEQ_OK); 208 0 stevel } 209 0 stevel 210 0 stevel #define DBG_RECOVER_MSG(f, l) \ 211 0 stevel DBG("Sequencing recovery: first = %s, last = %s\n", \ 212 0 stevel ap_cmd_name(f), ap_cmd_name(l)) 213 0 stevel 214 0 stevel cfga_err_t 215 0 stevel ap_seq_exec(apd_t *a, int cmd, int first, int last) 216 0 stevel { 217 0 stevel int c; 218 0 stevel int skip; 219 0 stevel int suspend; 220 0 stevel int resume; 221 0 stevel cfga_err_t rc; 222 0 stevel int recover_f = CMD_NONE; /* first recovery cmd */ 223 0 stevel int recover_l = CMD_NONE; /* last recovery cmd */ 224 0 stevel 225 0 stevel 226 0 stevel suspend = 0; 227 0 stevel resume = 0; 228 0 stevel 229 0 stevel skip = a->opts.skip; 230 0 stevel 231 0 stevel /* 232 0 stevel * The unassign step is skipped unless explicity requested 233 0 stevel * either by a -x request or as an option to a disconnect 234 0 stevel * request. 235 0 stevel */ 236 0 stevel if (cmd != CMD_UNASSIGN && ap_getopt(a, OPT_UNASSIGN) == 0) 237 0 stevel skip |= mask(CMD_UNASSIGN); 238 0 stevel 239 0 stevel /* 240 0 stevel * Check for platform options 241 0 stevel */ 242 0 stevel rc = ap_platopts_check(a, first, last); 243 0 stevel 244 0 stevel if (rc != CFGA_OK) { 245 0 stevel goto done; 246 0 stevel } 247 0 stevel 248 0 stevel for (c = first; c <= last; c++) { 249 0 stevel if (mask(c) & skip) { 250 0 stevel ap_msg(a, MSG_SKIP, c, a->target); 251 0 stevel continue; 252 0 stevel } 253 0 stevel 254 0 stevel DBG("exec %s\n", ap_cmd_name(c)); 255 0 stevel 256 0 stevel /* 257 0 stevel * If the suspend operation does not 258 0 stevel * succeed, resume any devices already 259 0 stevel * suspended as well as the device on 260 0 stevel * which the operation failed. 261 0 stevel */ 262 0 stevel switch (c) { 263 0 stevel case CMD_SUSPEND_CHECK: 264 0 stevel /* 265 0 stevel * Check whether the user allows a suspend 266 0 stevel * operation if the suspend is required. 267 0 stevel * Next step is to allow RCM clients to 268 0 stevel * interpose on the suspend operation. 269 0 stevel */ 270 0 stevel rc = ap_suspend_check(a, cmd, 271 0 stevel first + 1, last, &suspend); 272 0 stevel break; 273 0 stevel case CMD_RCM_SUSPEND: 274 0 stevel if (suspend && ((rc = ap_rcm_ctl(a, c)) == CFGA_OK)) { 275 0 stevel /* 276 0 stevel * Mark the fact that a suspend operation 277 0 stevel * is required, and that RCM clients have 278 0 stevel * allowed the suspend. 279 0 stevel */ 280 0 stevel ap_setopt(a, OPT_SUSPEND_OK); 281 0 stevel resume++; 282 0 stevel } 283 0 stevel break; 284 0 stevel case CMD_RCM_RESUME: 285 0 stevel if (resume) { 286 0 stevel (void) ap_rcm_ctl(a, c); 287 0 stevel resume--; 288 0 stevel } 289 0 stevel break; 290 0 stevel case CMD_RCM_OFFLINE: 291 0 stevel case CMD_RCM_CAP_DEL: 292 0 stevel rc = ap_rcm_ctl(a, c); 293 0 stevel break; 294 0 stevel case CMD_RCM_ONLINE: 295 0 stevel case CMD_RCM_CAP_ADD: 296 0 stevel case CMD_RCM_REMOVE: 297 0 stevel case CMD_RCM_CAP_NOTIFY: 298 0 stevel (void) ap_rcm_ctl(a, c); 299 0 stevel break; 300 0 stevel default: 301 0 stevel rc = ap_ioctl(a, c); 302 0 stevel break; 303 0 stevel } 304 0 stevel 305 0 stevel if (rc != CFGA_OK) 306 0 stevel break; 307 0 stevel 308 0 stevel } 309 0 stevel done: 310 0 stevel 311 0 stevel if (resume) 312 0 stevel (void) ap_rcm_ctl(a, CMD_RCM_RESUME); 313 0 stevel 314 0 stevel /* 315 0 stevel * Check if any operations failed. If so, attempt to rollback 316 0 stevel * to previously known states. 317 0 stevel * Note: The rollback is currently limited to RCM operations. 318 0 stevel */ 319 0 stevel if (rc != CFGA_OK) { 320 0 stevel if (c == CMD_UNCONFIGURE || 321 0 stevel c == CMD_RCM_OFFLINE || 322 0 stevel c == CMD_RCM_CAP_DEL) { 323 0 stevel DBG("ap_seq_exec: %s failed\n", ap_cmd_name(c)); 324 0 stevel 325 0 stevel switch (c) { 326 0 stevel case CMD_UNCONFIGURE: 327 0 stevel /* 328 0 stevel * If the unconfigure operation fails, perform 329 0 stevel * an RCM_ONLINE and RCM_CAP_NOTIFY only. This 330 0 stevel * keeps RCM clients consistent with the domain. 331 0 stevel */ 332 0 stevel recover_f = CMD_RCM_ONLINE; 333 0 stevel recover_l = CMD_RCM_ONLINE; 334 0 stevel DBG_RECOVER_MSG(recover_f, recover_l); 335 0 stevel (void) ap_seq_exec(a, cmd, recover_f, 336 0 stevel recover_l); 337 0 stevel 338 0 stevel recover_f = CMD_RCM_CAP_NOTIFY; 339 0 stevel recover_l = CMD_RCM_CAP_NOTIFY; 340 0 stevel DBG_RECOVER_MSG(recover_f, recover_l); 341 0 stevel (void) ap_seq_exec(a, cmd, recover_f, 342 0 stevel recover_l); 343 0 stevel break; 344 0 stevel case CMD_RCM_OFFLINE: 345 0 stevel recover_f = CMD_RCM_ONLINE; 346 0 stevel recover_l = CMD_RCM_CAP_ADD; 347 0 stevel DBG_RECOVER_MSG(recover_f, recover_l); 348 0 stevel (void) ap_seq_exec(a, cmd, recover_f, 349 0 stevel recover_l); 350 0 stevel break; 351 0 stevel case CMD_RCM_CAP_DEL: 352 0 stevel recover_f = CMD_RCM_CAP_ADD; 353 0 stevel recover_l = CMD_RCM_CAP_ADD; 354 0 stevel DBG_RECOVER_MSG(recover_f, recover_l); 355 0 stevel (void) ap_seq_exec(a, cmd, recover_f, 356 0 stevel recover_l); 357 0 stevel break; 358 0 stevel default: 359 0 stevel break; 360 0 stevel } 361 0 stevel 362 0 stevel DBG("recovery complete!\n"); 363 0 stevel } 364 0 stevel } 365 0 stevel return (rc); 366 0 stevel } 367 0 stevel 368 0 stevel cfga_err_t 369 0 stevel ap_cmd_exec(apd_t *a, int cmd) 370 0 stevel { 371 0 stevel return (ap_seq_exec(a, cmd, cmd, cmd)); 372 0 stevel } 373 0 stevel 374 0 stevel cfga_err_t 375 0 stevel ap_cmd_seq(apd_t *a, int cmd) 376 0 stevel { 377 0 stevel int first, last; 378 0 stevel cfga_err_t rc; 379 0 stevel 380 0 stevel switch (ap_seq_get(a, cmd, &first, &last)) { 381 0 stevel case AP_SEQ_OK: 382 0 stevel rc = ap_seq_exec(a, cmd, first, last); 383 0 stevel break; 384 0 stevel case AP_SEQ_NULL: 385 0 stevel rc = CFGA_OK; 386 0 stevel break; 387 0 stevel case AP_SEQ_FAIL: 388 0 stevel default: 389 0 stevel rc = CFGA_LIB_ERROR; 390 0 stevel break; 391 0 stevel } 392 0 stevel 393 0 stevel return (rc); 394 0 stevel } 395