1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * RCM backend for the DR Daemon 29 */ 30 31 #include <unistd.h> 32 #include <strings.h> 33 #include <errno.h> 34 #include <kstat.h> 35 #include <libnvpair.h> 36 #include <librcm.h> 37 #include <locale.h> 38 #include <assert.h> 39 40 #include "drd.h" 41 42 /* 43 * RCM Backend Support 44 */ 45 static int drd_rcm_init(void); 46 static int drd_rcm_fini(void); 47 static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc); 48 static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc); 49 static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc); 50 static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc); 51 static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc); 52 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc); 53 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc); 54 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc); 55 static int drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc); 56 static int drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc); 57 static int drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc); 58 static int drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc); 59 60 drd_backend_t drd_rcm_backend = { 61 drd_rcm_init, /* init */ 62 drd_rcm_fini, /* fini */ 63 drd_rcm_cpu_config_request, /* cpu_config_request */ 64 drd_rcm_cpu_config_notify, /* cpu_config_notify */ 65 drd_rcm_cpu_unconfig_request, /* cpu_unconfig_request */ 66 drd_rcm_cpu_unconfig_notify, /* cpu_unconfig_notify */ 67 drd_rcm_io_config_request, /* io_config_request */ 68 drd_rcm_io_config_notify, /* io_config_notify */ 69 drd_rcm_io_unconfig_request, /* io_unconfig_request */ 70 drd_rcm_io_unconfig_notify, /* io_unconfig_notify */ 71 drd_rcm_mem_config_request, /* mem_config_request */ 72 drd_rcm_mem_config_notify, /* mem_config_notify */ 73 drd_rcm_mem_unconfig_request, /* mem_unconfig_request */ 74 drd_rcm_mem_unconfig_notify /* mem_unconfig_notify */ 75 }; 76 77 typedef int (*rcm_op_t)(rcm_handle_t *, char *, uint_t, nvlist_t *, 78 rcm_info_t **); 79 80 #define RCM_MEM_ALL "SUNW_memory" 81 #define RCM_CPU_ALL "SUNW_cpu" 82 #define RCM_CPU RCM_CPU_ALL"/cpu" 83 #define RCM_CPU_MAX_LEN (32) 84 85 /* global RCM handle used in all RCM operations */ 86 static rcm_handle_t *rcm_hdl; 87 88 /* functions that call into RCM */ 89 static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 90 static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 91 static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc); 92 static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc); 93 static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 94 static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 95 static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc); 96 97 /* utility functions */ 98 static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status); 99 static void drd_rcm_cpu_rlist_fini(char **rlist); 100 static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int); 101 static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids); 102 static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len); 103 static char *rcm_info_table(rcm_info_t *rinfo); 104 105 /* debugging utility functions */ 106 static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids); 107 static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc); 108 static void dump_cpu_rlist(char **rlist); 109 110 static int 111 drd_rcm_init(void) 112 { 113 int rv; 114 115 drd_dbg("drd_rcm_init..."); 116 117 rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl); 118 if (rv == RCM_FAILURE) { 119 drd_err("unable to allocate RCM handle: %s", strerror(errno)); 120 return (-1); 121 } 122 123 return (0); 124 } 125 126 static int 127 drd_rcm_fini(void) 128 { 129 drd_dbg("drd_rcm_fini..."); 130 131 if (rcm_hdl != NULL) 132 rcm_free_handle(rcm_hdl); 133 134 return (0); 135 } 136 137 static int 138 drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc) 139 { 140 int idx; 141 142 drd_dbg("drd_rcm_cpu_config_request..."); 143 dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 144 145 /* 146 * There is no RCM operation to request the addition 147 * of resources. So, by definition, the operation for 148 * all the CPUs is allowed. 149 */ 150 for (idx = 0; idx < nrsrc; idx++) 151 rsrcs[idx].status = DRCTL_STATUS_ALLOW; 152 153 dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 154 155 return (0); 156 } 157 158 static int 159 drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) 160 { 161 int rv = 0; 162 163 drd_dbg("drd_rcm_cpu_config_notify..."); 164 dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 165 166 /* notify RCM about the newly added CPUs */ 167 if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) { 168 rv = -1; 169 goto done; 170 } 171 172 /* notify RCM about the increased CPU capacity */ 173 if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) { 174 rv = -1; 175 } 176 177 done: 178 dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 179 180 return (rv); 181 } 182 183 static int 184 drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc) 185 { 186 int rv = 0; 187 int idx; 188 189 drd_dbg("drd_rcm_cpu_unconfig_request..."); 190 dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 191 192 /* contact RCM to request a decrease in CPU capacity */ 193 if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) { 194 rv = -1; 195 goto done; 196 } 197 198 /* contact RCM to request the removal of CPUs */ 199 if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) { 200 rv = -1; 201 goto done; 202 } 203 204 done: 205 /* 206 * If any errors occurred, the status field for 207 * a CPU may still be in the INIT state. Set the 208 * status for any such CPU to DENY to ensure it 209 * gets processed properly. 210 */ 211 for (idx = 0; idx < nrsrc; idx++) { 212 if (rsrcs[idx].status == DRCTL_STATUS_INIT) 213 rsrcs[idx].status = DRCTL_STATUS_DENY; 214 } 215 216 dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 217 218 return (rv); 219 } 220 221 static int 222 drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc) 223 { 224 int rv = 0; 225 226 drd_dbg("drd_rcm_cpu_unconfig_notify..."); 227 dump_cpu_rsrc_list(NULL, rsrcs, nrsrc); 228 229 /* 230 * Notify RCM about the CPUs that were removed. 231 * Failures are ignored so that CPUs that could 232 * not be unconfigured can be processed by RCM. 233 */ 234 (void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc); 235 236 /* 237 * Notify RCM about any CPUs that did not make it 238 * in to the unconfigured state. 239 */ 240 if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) { 241 rv = -1; 242 goto done; 243 } 244 245 /* notify RCM about the decreased CPU capacity */ 246 if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) { 247 rv = -1; 248 } 249 250 done: 251 dump_cpu_rsrc_list("returning:", rsrcs, nrsrc); 252 253 return (rv); 254 } 255 256 static int 257 drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 258 { 259 char **rlist; 260 int rv = 0; 261 rcm_info_t *rinfo; 262 263 drd_dbg("drd_rcm_online_cpu_notify..."); 264 265 if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 266 DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) { 267 drd_dbg(" no CPUs were successfully added, nothing to do"); 268 return (0); 269 } 270 271 rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo); 272 if (rv != RCM_SUCCESS) { 273 drd_info("rcm_notify_online_list failed: %d", rv); 274 rcm_free_info(rinfo); 275 rv = -1; 276 } 277 278 drd_rcm_cpu_rlist_fini(rlist); 279 280 return (rv); 281 } 282 283 static int 284 drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 285 { 286 cpuid_t *cpus = NULL; 287 int ncpus; 288 int rv = -1; 289 cpuid_t *oldcpus = NULL; 290 cpuid_t *newcpus = NULL; 291 int oldncpus = 0; 292 int newncpus = 0; 293 nvlist_t *nvl = NULL; 294 int idx; 295 rcm_info_t *rinfo; 296 297 drd_dbg("drd_rcm_add_cpu_notify..."); 298 299 if ((rsrcs == NULL) || (nrsrc == 0)) { 300 drd_err("add_cpu_notify: cpu list empty"); 301 goto done; 302 } 303 304 ncpus = nrsrc; 305 cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 306 307 for (idx = 0; idx < nrsrc; idx++) { 308 drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id); 309 cpus[idx] = rsrcs[idx].res_cpu_id; 310 } 311 312 /* allocate an nvlist for the RCM call */ 313 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 314 goto done; 315 316 /* 317 * Added CPU capacity, so newcpus is the current list 318 * of CPUs in the system. 319 */ 320 if (get_sys_cpuids(&newcpus, &newncpus) == -1) 321 goto done; 322 323 /* 324 * Since the operation added CPU capacity, the old CPU 325 * list is the new CPU list with the CPUs involved in 326 * the operation removed. 327 */ 328 oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t)); 329 if (oldcpus == NULL) 330 goto done; 331 332 for (idx = 0; idx < newncpus; idx++) { 333 if (!is_cpu_in_list(newcpus[idx], cpus, ncpus)) 334 oldcpus[oldncpus++] = newcpus[idx]; 335 } 336 337 /* dump pre and post lists */ 338 dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 339 dump_cpu_list("newcpus: ", newcpus, newncpus); 340 dump_cpu_list("delta: ", cpus, ncpus); 341 342 /* setup the nvlist for the RCM call */ 343 if (nvlist_add_string(nvl, "state", "capacity") || 344 nvlist_add_int32(nvl, "old_total", oldncpus) || 345 nvlist_add_int32(nvl, "new_total", newncpus) || 346 nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 347 nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 348 goto done; 349 } 350 351 rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 352 rv = (rv == RCM_SUCCESS) ? 0 : -1; 353 354 done: 355 s_nvfree(nvl); 356 s_free(cpus); 357 s_free(oldcpus); 358 s_free(newcpus); 359 360 return (rv); 361 } 362 363 static int 364 drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc) 365 { 366 cpuid_t *cpus = NULL; 367 int ncpus; 368 int rv = -1; 369 cpuid_t *oldcpus = NULL; 370 cpuid_t *newcpus = NULL; 371 int oldncpus = 0; 372 int newncpus = 0; 373 nvlist_t *nvl = NULL; 374 int idx; 375 rcm_info_t *rinfo; 376 377 drd_dbg("drd_rcm_del_cpu_request..."); 378 379 if ((rsrcs == NULL) || (nrsrc == 0)) { 380 drd_err("del_cpu_request: cpu list empty"); 381 goto done; 382 } 383 384 ncpus = nrsrc; 385 cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 386 387 for (idx = 0; idx < nrsrc; idx++) { 388 cpus[idx] = rsrcs[idx].res_cpu_id; 389 } 390 391 /* allocate an nvlist for the RCM call */ 392 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 393 goto done; 394 } 395 396 /* 397 * Removing CPU capacity, so oldcpus is the current 398 * list of CPUs in the system. 399 */ 400 if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) { 401 goto done; 402 } 403 404 /* 405 * Since this is a request to remove CPU capacity, 406 * the new CPU list is the old CPU list with the CPUs 407 * involved in the operation removed. 408 */ 409 newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t)); 410 if (newcpus == NULL) { 411 goto done; 412 } 413 414 for (idx = 0; idx < oldncpus; idx++) { 415 if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus)) 416 newcpus[newncpus++] = oldcpus[idx]; 417 } 418 419 /* dump pre and post lists */ 420 dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 421 dump_cpu_list("newcpus: ", newcpus, newncpus); 422 dump_cpu_list("delta: ", cpus, ncpus); 423 424 /* setup the nvlist for the RCM call */ 425 if (nvlist_add_string(nvl, "state", "capacity") || 426 nvlist_add_int32(nvl, "old_total", oldncpus) || 427 nvlist_add_int32(nvl, "new_total", newncpus) || 428 nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 429 nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 430 goto done; 431 } 432 433 rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 434 if (rv != RCM_SUCCESS) { 435 drd_dbg("RCM call failed: %d", rv); 436 /* 437 * Since the capacity change was blocked, we 438 * mark all CPUs as blocked. It is up to the 439 * user to reframe the query so that it can 440 * succeed. 441 */ 442 for (idx = 0; idx < nrsrc; idx++) { 443 rsrcs[idx].status = DRCTL_STATUS_DENY; 444 } 445 446 /* tack on message to first resource */ 447 rsrcs[0].offset = (uintptr_t)strdup("unable to remove " 448 "specified number of CPUs"); 449 drd_dbg(" unable to remove specified number of CPUs"); 450 goto done; 451 } 452 453 rv = 0; 454 455 done: 456 s_nvfree(nvl); 457 s_free(cpus); 458 s_free(oldcpus); 459 s_free(newcpus); 460 461 return (rv); 462 } 463 464 static int 465 drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc) 466 { 467 char **rlist; 468 drctl_rsrc_t *rsrc; 469 int idx; 470 int state; 471 int rv = 0; 472 rcm_info_t *rinfo = NULL; 473 rcm_info_tuple_t *tuple = NULL; 474 const char *rsrcstr; 475 const char *errstr; 476 477 drd_dbg("drd_rcm_offline_cpu_request..."); 478 479 if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 480 DRCTL_STATUS_INIT)) == NULL) { 481 drd_err("unable to generate resource list"); 482 return (-1); 483 } 484 485 rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo); 486 if (rv == RCM_SUCCESS) { 487 drd_dbg("RCM success, rinfo=%p", rinfo); 488 goto done; 489 } 490 491 drd_dbg("RCM call failed (%d):", rv); 492 493 /* 494 * Loop through the result of the operation and add 495 * any error messages to the resource structure. 496 */ 497 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 498 499 /* find the resource of interest */ 500 rsrcstr = rcm_info_rsrc(tuple); 501 rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc); 502 503 if (rsrc == NULL) { 504 drd_dbg("unable to find resource for %s", rsrcstr); 505 continue; 506 } 507 508 errstr = rcm_info_error(tuple); 509 510 if (errstr) { 511 drd_dbg(" %s: '%s'", rsrcstr, errstr); 512 rsrc->offset = (uintptr_t)strdup(errstr); 513 } 514 } 515 516 rcm_free_info(rinfo); 517 rv = 0; 518 519 done: 520 /* 521 * Set the state of the resource based on the RCM 522 * state. CPUs in the offline state have the ok to 523 * proceed. All others have been blocked. 524 */ 525 for (idx = 0; rlist[idx] != NULL; idx++) { 526 527 state = 0; 528 rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state); 529 530 /* find the resource of interest */ 531 rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc); 532 533 if (rsrc == NULL) { 534 drd_dbg("unable to find resource for %s", rlist[idx]); 535 continue; 536 } 537 538 rsrc->status = ((state == RCM_STATE_OFFLINE) ? 539 DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY); 540 } 541 542 drd_rcm_cpu_rlist_fini(rlist); 543 544 return (rv); 545 } 546 547 static int 548 drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 549 { 550 char **rlist; 551 int rv = 0; 552 rcm_info_t *rinfo; 553 554 drd_dbg("drd_rcm_remove_cpu_notify..."); 555 556 if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 557 DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) { 558 drd_dbg(" no CPUs in the success state, nothing to do"); 559 return (0); 560 } 561 562 rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo); 563 if (rv != RCM_SUCCESS) { 564 drd_info("rcm_notify_remove_list failed: %d", rv); 565 rcm_free_info(rinfo); 566 rv = -1; 567 } 568 569 drd_rcm_cpu_rlist_fini(rlist); 570 571 return (rv); 572 } 573 574 static int 575 drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 576 { 577 char **rlist; 578 char **full_rlist; 579 int idx; 580 int ridx; 581 int state; 582 int rv = 0; 583 rcm_info_t *rinfo; 584 585 drd_dbg("drd_rcm_restore_cpu_notify..."); 586 587 if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc, 588 DRCTL_STATUS_CONFIG_FAILURE)) == NULL) { 589 drd_dbg(" no CPUs in the failed state, nothing to do"); 590 return (0); 591 } 592 593 /* 594 * Since the desired result of this operation is to 595 * restore resources to the online state, filter out 596 * the resources already in the online state before 597 * passing the list to RCM. 598 */ 599 600 /* allocate a zero filled array to ensure NULL terminated list */ 601 rlist = (char **)calloc((nrsrc + 1), sizeof (char *)); 602 if (rlist == NULL) { 603 drd_err("calloc failed: %s", strerror(errno)); 604 rv = -1; 605 goto done; 606 } 607 608 for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) { 609 state = 0; 610 rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state); 611 if (state != RCM_STATE_ONLINE) { 612 rlist[ridx] = full_rlist[idx]; 613 ridx++; 614 } 615 } 616 617 /* check if everything got filtered out */ 618 if (ridx == 0) { 619 drd_dbg(" all CPUs already online, nothing to do"); 620 goto done; 621 } 622 623 rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo); 624 if (rv != RCM_SUCCESS) { 625 drd_info("rcm_notify_online_list failed: %d", rv); 626 rcm_free_info(rinfo); 627 rv = -1; 628 } 629 630 done: 631 drd_rcm_cpu_rlist_fini(full_rlist); 632 s_free(rlist); 633 634 return (rv); 635 } 636 637 static int 638 drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc) 639 { 640 cpuid_t *cpus = NULL; 641 int rv = -1; 642 cpuid_t *oldcpus = NULL; 643 cpuid_t *newcpus = NULL; 644 int oldncpus = 0; 645 int newncpus = 0; 646 nvlist_t *nvl = NULL; 647 int idx; 648 int cidx; 649 rcm_info_t *rinfo; 650 651 drd_dbg("drd_rcm_del_cpu_notify..."); 652 653 if ((rsrcs == NULL) || (nrsrc == 0)) { 654 drd_err("del_cpu_notify: cpu list empty"); 655 goto done; 656 } 657 658 cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t)); 659 660 /* 661 * Filter out the CPUs that could not be unconfigured. 662 */ 663 for (idx = 0, cidx = 0; idx < nrsrc; idx++) { 664 if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS) 665 continue; 666 drd_dbg(" cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id); 667 cpus[cidx] = rsrcs[idx].res_cpu_id; 668 cidx++; 669 } 670 671 drd_dbg(" ncpus = %d", cidx); 672 673 /* nothing to do */ 674 if (cidx == 0) { 675 rv = 0; 676 goto done; 677 } 678 679 /* allocate an nvlist for the RCM call */ 680 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 681 goto done; 682 } 683 684 /* 685 * Removed CPU capacity, so newcpus is the current list 686 * of CPUs in the system. 687 */ 688 if (get_sys_cpuids(&newcpus, &newncpus) == -1) { 689 goto done; 690 } 691 692 /* 693 * Since the operation removed CPU capacity, the old CPU 694 * list is the new CPU list with the CPUs involved in 695 * the operation added. 696 */ 697 oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t)); 698 if (oldcpus == NULL) { 699 goto done; 700 } 701 702 for (idx = 0; idx < newncpus; idx++) { 703 if (!is_cpu_in_list(newcpus[idx], cpus, cidx)) 704 oldcpus[oldncpus++] = newcpus[idx]; 705 } 706 707 for (idx = 0; idx < cidx; idx++) { 708 oldcpus[oldncpus++] = cpus[idx]; 709 } 710 711 /* dump pre and post lists */ 712 dump_cpu_list("oldcpus: ", oldcpus, oldncpus); 713 dump_cpu_list("newcpus: ", newcpus, newncpus); 714 dump_cpu_list("delta: ", cpus, cidx); 715 716 /* setup the nvlist for the RCM call */ 717 if (nvlist_add_string(nvl, "state", "capacity") || 718 nvlist_add_int32(nvl, "old_total", oldncpus) || 719 nvlist_add_int32(nvl, "new_total", newncpus) || 720 nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) || 721 nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) { 722 goto done; 723 } 724 725 rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo); 726 rv = (rv == RCM_SUCCESS) ? 0 : -1; 727 728 done: 729 s_nvfree(nvl); 730 s_free(cpus); 731 s_free(oldcpus); 732 s_free(newcpus); 733 734 return (rv); 735 } 736 737 /* 738 * Given a list of resource structures, create a list of CPU 739 * resource strings formatted as expected by RCM. Only resources 740 * that are in the state specified by the status argument are 741 * included in the resulting list. 742 */ 743 static char ** 744 drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status) 745 { 746 char rbuf[RCM_CPU_MAX_LEN]; 747 char **rlist; 748 int idx; 749 int ridx; 750 751 drd_dbg("drd_rcm_cpu_rlist_init..."); 752 753 if ((rsrcs == NULL) || (nrsrc == 0)) { 754 drd_dbg("cpu list is empty"); 755 return (NULL); 756 } 757 758 /* allocate a zero filled array to ensure NULL terminated list */ 759 rlist = (char **)calloc((nrsrc + 1), sizeof (char *)); 760 if (rlist == NULL) { 761 drd_err("calloc failed: %s", strerror(errno)); 762 return (NULL); 763 } 764 765 for (idx = 0, ridx = 0; idx < nrsrc; idx++) { 766 767 drd_dbg(" checking cpu %d, status=%d, expected status=%d", 768 rsrcs[idx].res_cpu_id, rsrcs[idx].status, status); 769 770 /* 771 * Filter out the CPUs that are not in 772 * the requested state. 773 */ 774 if (rsrcs[idx].status != status) 775 continue; 776 777 /* generate the resource string */ 778 (void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id); 779 780 rlist[ridx] = strdup(rbuf); 781 if (rlist[ridx] == NULL) { 782 drd_err("strdup failed: %s", strerror(errno)); 783 drd_rcm_cpu_rlist_fini(rlist); 784 return (NULL); 785 } 786 787 ridx++; 788 } 789 790 /* cleanup if the list is empty */ 791 if (ridx == 0) { 792 s_free(rlist); 793 } 794 795 drd_dbg("final rlist:"); 796 dump_cpu_rlist(rlist); 797 798 return (rlist); 799 } 800 801 static void 802 drd_rcm_cpu_rlist_fini(char **rlist) 803 { 804 int idx; 805 806 drd_dbg("drd_rcm_cpu_rlist_fini..."); 807 808 dump_cpu_rlist(rlist); 809 810 for (idx = 0; rlist[idx] != NULL; idx++) { 811 s_free(rlist[idx]); 812 } 813 814 s_free(rlist); 815 } 816 817 /* 818 * Convert an RCM CPU resource string into a numerical cpuid. 819 * Assumes the resource string has the form: "SUNW_cpu/cpu<C>" 820 * where "<C>" is the numerical cpuid of interest. 821 */ 822 static cpuid_t 823 cpu_rsrcstr_to_cpuid(const char *rsrc) 824 { 825 char *cpuid_off; 826 cpuid_t cpuid; 827 828 /* 829 * Search for the last occurrance of 'u' in the 830 * expected RCM resource string "SUNW_cpu/cpu<C>". 831 * This will give a pointer to the cpuid portion. 832 */ 833 cpuid_off = strrchr(rsrc, 'u'); 834 cpuid_off++; 835 836 cpuid = atoi(cpuid_off); 837 838 return (cpuid); 839 } 840 841 /* 842 * Given an RCM CPU resource string, return a pointer to the 843 * corresponding resource structure from the given resource list. 844 * NULL is returned if no matching resource structure can be 845 * found. 846 */ 847 static drctl_rsrc_t * 848 cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc) 849 { 850 cpuid_t cpuid; 851 int idx; 852 853 cpuid = cpu_rsrcstr_to_cpuid(rsrcstr); 854 855 for (idx = 0; idx < nrsrc; idx++) { 856 if (rsrcs[idx].res_cpu_id == cpuid) 857 return (&rsrcs[idx]); 858 } 859 860 return (NULL); 861 } 862 863 static int 864 get_sys_cpuids(cpuid_t **cpuids, int *ncpuids) 865 { 866 int ncpu = 0; 867 int maxncpu; 868 kstat_t *ksp; 869 kstat_ctl_t *kc = NULL; 870 cpuid_t *cp; 871 872 drd_dbg("get_sys_cpuids..."); 873 874 if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1) 875 return (-1); 876 877 if ((kc = kstat_open()) == NULL) 878 return (-1); 879 880 if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) { 881 (void) kstat_close(kc); 882 return (-1); 883 } 884 885 for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 886 if (strcmp(ksp->ks_module, "cpu_info") == 0) 887 cp[ncpu++] = ksp->ks_instance; 888 } 889 890 dump_cpu_list("syscpus: ", cp, ncpu); 891 892 (void) kstat_close(kc); 893 894 *cpuids = cp; 895 *ncpuids = ncpu; 896 897 return (0); 898 } 899 900 static boolean_t 901 is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len) 902 { 903 int idx; 904 905 if (list == NULL) 906 return (B_FALSE); 907 908 for (idx = 0; idx < len; idx++) { 909 if (list[idx] == cpuid) 910 return (B_TRUE); 911 } 912 913 return (B_FALSE); 914 } 915 916 #define CPUIDS_PER_LINE 16 917 #define LINEWIDTH (2 * (CPUIDS_PER_LINE * 4)) 918 919 static void 920 dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids) 921 { 922 char line[LINEWIDTH]; 923 char *curr; 924 int i, j; 925 926 /* return if not debugging */ 927 if (drd_debug == 0) 928 return; 929 930 /* print just the prefix if CPU list is empty */ 931 if (ncpuids == 0) { 932 if (prefix) 933 drd_dbg("%s", prefix); 934 return; 935 } 936 937 for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) { 938 939 bzero(line, LINEWIDTH); 940 curr = line; 941 942 /* start with the prefix */ 943 (void) sprintf(curr, "%s", (prefix) ? prefix : ""); 944 curr = line + strlen(line); 945 946 /* format the CPUs for this line */ 947 for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) { 948 (void) sprintf(curr, "%3d ", cpuids[i + j]); 949 curr = line + strlen(line); 950 } 951 952 drd_dbg("%s", line); 953 } 954 } 955 956 static void 957 dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc) 958 { 959 int idx; 960 char *errstr; 961 962 /* just return if not debugging */ 963 if (drd_debug == 0) 964 return; 965 966 if (prefix) 967 drd_dbg("%s", prefix); 968 969 for (idx = 0; idx < nrsrc; idx++) { 970 971 /* get a pointer to the error string */ 972 errstr = (char *)(uintptr_t)rsrcs[idx].offset; 973 974 drd_dbg(" cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx, 975 rsrcs[idx].res_cpu_id, rsrcs[idx].status, 976 (errstr != NULL) ? errstr : ""); 977 } 978 } 979 980 static void 981 dump_cpu_rlist(char **rlist) 982 { 983 int idx; 984 int state; 985 986 static char *rcm_state_str[] = { 987 "UNKNOWN", "ONLINE", "ONLINING", 988 "OFFLINE_FAIL", "OFFLINING", "OFFLINE", 989 "REMOVING", "INVALID_7", "INVALID_8", 990 "INVALID_9", "RESUMING", "SUSPEND_FAIL", 991 "SUSPENDING", "SUSPEND", "REMOVE", 992 "OFFLINE_QUERYING", "OFFLINE_QUERY_FAIL", "OFFLINE_QUERY", 993 "SUSPEND_QUERYING", "SUSPEND_QUERY_FAIL", "SUSPEND_QUERY" 994 }; 995 996 /* just return if not debugging */ 997 if (drd_debug == 0) 998 return; 999 1000 if (rlist == NULL) { 1001 drd_dbg(" empty rlist"); 1002 return; 1003 } 1004 1005 for (idx = 0; rlist[idx] != NULL; idx++) { 1006 state = 0; 1007 rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state); 1008 drd_dbg(" rlist[%d]: rsrc=%s, state=%-2d (%s)", idx, 1009 rlist[idx], state, rcm_state_str[state]); 1010 } 1011 } 1012 1013 static int 1014 drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc) 1015 { 1016 drd_dbg("drd_rcm_io_config_request..."); 1017 1018 if (nrsrc != 1) { 1019 drd_dbg("drd_rcm_cpu_config_request: only 1 resource " 1020 "allowed for I/O requests, passed %d resources\n", nrsrc); 1021 rsrc->status = DRCTL_STATUS_DENY; 1022 1023 return (-1); 1024 } 1025 1026 /* 1027 * There is no RCM operation to request the addition 1028 * of resources. So, by definition, the operation for 1029 * the current resource is allowed. 1030 */ 1031 rsrc->status = DRCTL_STATUS_ALLOW; 1032 1033 return (0); 1034 } 1035 1036 /*ARGSUSED*/ 1037 static int 1038 drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) 1039 { 1040 drd_dbg("drd_rcm_io_config_notify..."); 1041 1042 if (nrsrc != 1) { 1043 drd_dbg("drd_rcm_cpu_config_notify: only 1 resource " 1044 "allowed for I/O requests, passed %d resources\n", nrsrc); 1045 1046 return (-1); 1047 } 1048 1049 return (0); 1050 } 1051 1052 1053 static int 1054 drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc) 1055 { 1056 int rv; 1057 char *dev = rsrc->res_dev_path; 1058 rcm_info_t *rinfo = NULL; 1059 1060 if (nrsrc != 1) { 1061 drd_dbg("drd_io_unconfig_request: only 1 resource " 1062 "allowed for I/O requests, passed %d resources\n", nrsrc); 1063 rsrc->status = DRCTL_STATUS_DENY; 1064 1065 return (-1); 1066 } 1067 1068 if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS) 1069 rsrc->status = DRCTL_STATUS_ALLOW; 1070 else { 1071 rcm_notify_online(rcm_hdl, dev, 0, NULL); 1072 rsrc->status = DRCTL_STATUS_DENY; 1073 rsrc->offset = (uintptr_t)rcm_info_table(rinfo); 1074 1075 } 1076 1077 rcm_free_info(rinfo); 1078 drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv); 1079 1080 return (rv); 1081 } 1082 1083 static int 1084 drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc) 1085 { 1086 drd_dbg("drd_rcm_io_unconfig_notify..."); 1087 1088 if (nrsrc != 1) { 1089 drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource " 1090 "allowed for I/O requests, passed %d resources\n", nrsrc); 1091 1092 return (-1); 1093 } 1094 1095 return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL)); 1096 } 1097 1098 #define MAX_FORMAT 80 1099 1100 /* 1101 * Convert rcm_info_t data into a printable table. 1102 */ 1103 static char * 1104 rcm_info_table(rcm_info_t *rinfo) 1105 { 1106 int i; 1107 size_t w; 1108 size_t width = 0; 1109 size_t w_rsrc = 0; 1110 size_t w_info = 0; 1111 size_t table_size = 0; 1112 uint_t tuples = 0; 1113 rcm_info_tuple_t *tuple = NULL; 1114 char *rsrc; 1115 char *info; 1116 char *table; 1117 static char format[MAX_FORMAT]; 1118 const char *infostr; 1119 1120 /* Protect against invalid arguments */ 1121 if (rinfo == NULL) 1122 return (NULL); 1123 1124 /* Set localized table header strings */ 1125 rsrc = dgettext(TEXT_DOMAIN, "Resource"); 1126 info = dgettext(TEXT_DOMAIN, "Information"); 1127 1128 /* A first pass, to size up the RCM information */ 1129 while (tuple = rcm_info_next(rinfo, tuple)) { 1130 if ((infostr = rcm_info_info(tuple)) != NULL) { 1131 tuples++; 1132 if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc) 1133 w_rsrc = w; 1134 if ((w = strlen(infostr)) > w_info) 1135 w_info = w; 1136 } 1137 } 1138 1139 /* If nothing was sized up above, stop early */ 1140 if (tuples == 0) 1141 return (NULL); 1142 1143 /* Adjust column widths for column headings */ 1144 if ((w = strlen(rsrc)) > w_rsrc) 1145 w_rsrc = w; 1146 else if ((w_rsrc - w) % 2) 1147 w_rsrc++; 1148 if ((w = strlen(info)) > w_info) 1149 w_info = w; 1150 else if ((w_info - w) % 2) 1151 w_info++; 1152 1153 /* 1154 * Compute the total line width of each line, 1155 * accounting for intercolumn spacing. 1156 */ 1157 width = w_info + w_rsrc + 4; 1158 1159 /* Allocate space for the table */ 1160 table_size = (2 + tuples) * (width + 1) + 2; 1161 1162 /* zero fill for the strcat() call below */ 1163 table = calloc(table_size, sizeof (char)); 1164 if (table == NULL) 1165 return (NULL); 1166 1167 /* Place a table header into the string */ 1168 1169 /* The resource header */ 1170 (void) strcat(table, "\n"); 1171 w = strlen(rsrc); 1172 for (i = 0; i < ((w_rsrc - w) / 2); i++) 1173 (void) strcat(table, " "); 1174 (void) strcat(table, rsrc); 1175 for (i = 0; i < ((w_rsrc - w) / 2); i++) 1176 (void) strcat(table, " "); 1177 1178 /* The information header */ 1179 (void) strcat(table, " "); 1180 w = strlen(info); 1181 for (i = 0; i < ((w_info - w) / 2); i++) 1182 (void) strcat(table, " "); 1183 (void) strcat(table, info); 1184 for (i = 0; i < ((w_info - w) / 2); i++) 1185 (void) strcat(table, " "); 1186 /* Underline the headers */ 1187 (void) strcat(table, "\n"); 1188 for (i = 0; i < w_rsrc; i++) 1189 (void) strcat(table, "-"); 1190 (void) strcat(table, " "); 1191 for (i = 0; i < w_info; i++) 1192 (void) strcat(table, "-"); 1193 1194 /* Construct the format string */ 1195 (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 1196 (int)w_rsrc, (int)w_info); 1197 1198 /* Add the tuples to the table string */ 1199 tuple = NULL; 1200 while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) { 1201 if ((infostr = rcm_info_info(tuple)) != NULL) { 1202 (void) strcat(table, "\n"); 1203 (void) sprintf(&((table)[strlen(table)]), 1204 format, rcm_info_rsrc(tuple), 1205 infostr); 1206 } 1207 } 1208 drd_dbg("rcm_info_table: %s\n", table); 1209 1210 return (table); 1211 } 1212 1213 static void 1214 dump_mem_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc) 1215 { 1216 int idx; 1217 char *errstr; 1218 1219 /* just return if not debugging */ 1220 if (drd_debug == 0) 1221 return; 1222 1223 if (prefix) 1224 drd_dbg("%s", prefix); 1225 1226 for (idx = 0; idx < nrsrc; idx++) { 1227 1228 /* get a pointer to the error string */ 1229 errstr = (char *)(uintptr_t)rsrcs[idx].offset; 1230 1231 drd_dbg(" mem[%d]: addr=0x%llx, size=0x%llx" 1232 " status=%d, errstr='%s'", idx, 1233 rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size, 1234 rsrcs[idx].status, (errstr != NULL) ? errstr : ""); 1235 } 1236 } 1237 1238 static int 1239 drd_rcm_mem_op(rcm_op_t op, uint64_t change) 1240 { 1241 int rv = -1; 1242 int pgsize; 1243 long oldpages; 1244 long newpages; 1245 nvlist_t *nvl = NULL; 1246 rcm_info_t *rinfo; 1247 1248 /* allocate an nvlist for the RCM call */ 1249 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1250 goto done; 1251 1252 if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 || 1253 (newpages = sysconf(_SC_PHYS_PAGES)) == -1) 1254 goto done; 1255 1256 /* 1257 * If this is a notify add, the capacity change 1258 * was positive and the current page count reflects 1259 * the new capacity level. 1260 * 1261 * If this is a request del, the capacity change 1262 * is negative and the current page count will 1263 * reflect the old capacity level. 1264 */ 1265 assert(change % pgsize == 0); 1266 if (change > 0) { 1267 oldpages = newpages - (long)(change / pgsize); 1268 } else { 1269 assert(newpages >= change / pgsize); 1270 oldpages = newpages; 1271 newpages = oldpages + (long)(change / pgsize); 1272 } 1273 1274 drd_dbg("oldpages=%lld newpages=%lld delta=%lld", 1275 oldpages, newpages, newpages - oldpages); 1276 1277 /* setup the nvlist for the RCM call */ 1278 if (nvlist_add_string(nvl, "state", "capacity") != 0 || 1279 nvlist_add_int32(nvl, "page_size", pgsize) != 0 || 1280 nvlist_add_int32(nvl, "old_pages", oldpages) != 0 || 1281 nvlist_add_int32(nvl, "new_pages", newpages) != 0) { 1282 goto done; 1283 } 1284 1285 rv = (*op)(rcm_hdl, RCM_MEM_ALL, 0, nvl, &rinfo); 1286 rv = (rv == RCM_SUCCESS) ? 0 : -1; 1287 1288 done: 1289 s_nvfree(nvl); 1290 1291 return (rv); 1292 } 1293 1294 /* 1295 * RCM clients can interpose only on removal of resources. 1296 */ 1297 static int 1298 drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc) 1299 { 1300 int idx; 1301 1302 drd_dbg("drd_rcm_mem_config_request..."); 1303 1304 if ((rsrcs == NULL) || (nrsrc == 0)) 1305 return (0); 1306 dump_mem_rsrc_list(NULL, rsrcs, nrsrc); 1307 1308 /* 1309 * There is no RCM operation to request the addition 1310 * of resources. So, by definition, the operation for 1311 * all the memory is allowed. 1312 */ 1313 for (idx = 0; idx < nrsrc; idx++) 1314 rsrcs[idx].status = DRCTL_STATUS_ALLOW; 1315 1316 dump_mem_rsrc_list("returning:", rsrcs, nrsrc); 1317 1318 return (0); 1319 } 1320 1321 static int 1322 drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc) 1323 { 1324 int idx; 1325 int rv = -1; 1326 uint64_t change = 0; 1327 1328 drd_dbg("drd_rcm_mem_config_notify..."); 1329 1330 if ((rsrcs == NULL) || (nrsrc == 0)) { 1331 drd_err("mem_config_notify: mem list empty"); 1332 goto done; 1333 } 1334 dump_mem_rsrc_list(NULL, rsrcs, nrsrc); 1335 1336 for (idx = 0; idx < nrsrc; idx++) { 1337 if (rsrcs[idx].status == DRCTL_STATUS_CONFIG_SUCCESS) 1338 change += rsrcs[idx].res_mem_size; 1339 drd_dbg(" idx=%d addr=0x%llx size=0x%llx", 1340 idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size); 1341 } 1342 1343 rv = drd_rcm_mem_op(rcm_notify_capacity_change, change); 1344 done: 1345 return (rv); 1346 } 1347 1348 static int 1349 drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc) 1350 { 1351 int rv = -1; 1352 int idx; 1353 uint64_t change = 0; 1354 1355 drd_dbg("drd_rcm_del_mem_request..."); 1356 1357 if ((rsrcs == NULL) || (nrsrc == 0)) { 1358 drd_err("mem_unconfig_request: mem list empty"); 1359 goto done; 1360 } 1361 dump_mem_rsrc_list(NULL, rsrcs, nrsrc); 1362 1363 for (idx = 0; idx < nrsrc; idx++) { 1364 drd_dbg(" idx=%d addr=0x%llx size=0x%llx", 1365 idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size); 1366 change += rsrcs[idx].res_mem_size; 1367 } 1368 1369 rv = drd_rcm_mem_op(rcm_request_capacity_change, -change); 1370 1371 if (rv != RCM_SUCCESS) { 1372 drd_dbg("RCM call failed: %d", rv); 1373 /* 1374 * Since the capacity change was blocked, we 1375 * mark all mblocks as blocked. It is up to the 1376 * user to reframe the query so that it can 1377 * succeed. 1378 */ 1379 for (idx = 0; idx < nrsrc; idx++) { 1380 rsrcs[idx].status = DRCTL_STATUS_DENY; 1381 } 1382 1383 /* tack on message to first resource */ 1384 rsrcs[0].offset = (uintptr_t)strdup("unable to remove " 1385 "specified amount of memory"); 1386 drd_dbg(" unable to remove specified amount of memory"); 1387 } else { 1388 for (idx = 0; idx < nrsrc; idx++) 1389 rsrcs[idx].status = DRCTL_STATUS_ALLOW; 1390 rv = 0; 1391 } 1392 1393 done: 1394 1395 dump_mem_rsrc_list("returning:", rsrcs, nrsrc); 1396 return (rv); 1397 } 1398 1399 static int 1400 drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc) 1401 { 1402 int idx; 1403 int rv = -1; 1404 uint64_t change = 0; 1405 1406 drd_dbg("drd_rcm_mem_unconfig_notify..."); 1407 1408 if ((rsrcs == NULL) || (nrsrc == 0)) { 1409 drd_err("unconfig_mem_notify: mem list empty"); 1410 goto done; 1411 } 1412 dump_mem_rsrc_list(NULL, rsrcs, nrsrc); 1413 1414 /* 1415 * Filter out the memory that was configured. 1416 * 1417 * We need to notify RCM about a memory capacity change 1418 * only if the memory unconfigure request wasn't successful 1419 * because if both the RCM capacity delete request and the 1420 * memory unconfigure succeed, this notify would give a 1421 * memory capacity identical to the delete request. 1422 */ 1423 for (idx = 0; idx < nrsrc; idx++) { 1424 if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS) 1425 change += rsrcs[idx].res_mem_size; 1426 drd_dbg(" idx=%d addr=0x%llx size=0x%llx", 1427 idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size); 1428 } 1429 1430 rv = drd_rcm_mem_op(rcm_notify_capacity_change, change); 1431 done: 1432 return (rv); 1433 } 1434