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.
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.
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]
22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
35 #include <libdevinfo.h>
36 #define CFGA_PLUGIN_LIB
37 #include <config_admin.h>
41 #include <libscf_priv.h>
43 static int fastreboot_disabled
;
47 ap_suspend_check(apd_t
*a
, int cmd
, int first
, int last
, int *suspend
)
57 * Check if any of the steps in the sequence
58 * may require a suspension of service and ask
59 * the user to confirm.
61 for (check
= 0, c
= first
; c
<= last
; c
++)
64 else if ((rc
= ap_suspend_query(a
, c
, &check
)) != CFGA_OK
)
70 * If a suspend is required, ask for user confirmation.
71 * The force flag overrides the user confirmation.
73 if (check
&& (!ap_getopt(a
, OPT_FORCE
)) && (!ap_confirm(a
))) {
74 ap_err(a
, ERR_CMD_NACK
, cmd
);
83 #define AP_SEQ_FAIL -1
86 * Sequence a cfgadm state change command into driver commands.
87 * The rstate and ostate of the AP are needed at this point
88 * in order to compute the proper sequence.
91 ap_seq_get(apd_t
*a
, int cmd
, int *first
, int *last
)
98 ap_state(a
, &rs
, &os
);
101 case CFGA_STAT_EMPTY
:
103 case CFGA_STAT_UNCONFIGURED
:
105 case CMD_UNCONFIGURE
:
116 case CFGA_STAT_DISCONNECTED
:
118 case CFGA_STAT_UNCONFIGURED
:
122 * skip the disconnect command since
123 * the rstate is already disconnected
126 a
->opts
.skip
|= mask(CMD_DISCONNECT
);
129 case CMD_UNCONFIGURE
:
148 case CFGA_STAT_CONNECTED
:
150 case CFGA_STAT_UNCONFIGURED
:
153 case CMD_UNCONFIGURE
:
168 case CFGA_STAT_CONFIGURED
:
174 f
= CMD_SUSPEND_CHECK
;
181 case CMD_UNCONFIGURE
:
182 f
= CMD_SUSPEND_CHECK
;
183 l
= CMD_RCM_CAP_NOTIFY
;
199 return (AP_SEQ_NULL
);
200 ap_err(a
, ERR_TRANS_INVAL
, cmd
);
201 return (AP_SEQ_FAIL
);
207 DBG("ap_seq(%d, %d, %d, %p, %p) = (%d, %d)\n",
208 rs
, os
, cmd
, (void *)first
, (void *)last
, f
, l
);
213 #define DBG_RECOVER_MSG(f, l) \
214 DBG("Sequencing recovery: first = %s, last = %s\n", \
215 ap_cmd_name(f), ap_cmd_name(l))
218 ap_seq_exec(apd_t
*a
, int cmd
, int first
, int last
)
225 int recover_f
= CMD_NONE
; /* first recovery cmd */
226 int recover_l
= CMD_NONE
; /* last recovery cmd */
235 * The unassign step is skipped unless explicity requested
236 * either by a -x request or as an option to a disconnect
239 if (cmd
!= CMD_UNASSIGN
&& ap_getopt(a
, OPT_UNASSIGN
) == 0)
240 skip
|= mask(CMD_UNASSIGN
);
243 * Check for platform options
245 rc
= ap_platopts_check(a
, first
, last
);
251 for (c
= first
; c
<= last
; c
++) {
252 if (mask(c
) & skip
) {
253 ap_msg(a
, MSG_SKIP
, c
, a
->target
);
257 DBG("exec %s\n", ap_cmd_name(c
));
260 * If the suspend operation does not
261 * succeed, resume any devices already
262 * suspended as well as the device on
263 * which the operation failed.
266 case CMD_SUSPEND_CHECK
:
268 * Check whether the user allows a suspend
269 * operation if the suspend is required.
270 * Next step is to allow RCM clients to
271 * interpose on the suspend operation.
273 rc
= ap_suspend_check(a
, cmd
,
274 first
+ 1, last
, &suspend
);
276 case CMD_RCM_SUSPEND
:
277 if (suspend
&& ((rc
= ap_rcm_ctl(a
, c
)) == CFGA_OK
)) {
279 * Mark the fact that a suspend operation
280 * is required, and that RCM clients have
281 * allowed the suspend.
283 ap_setopt(a
, OPT_SUSPEND_OK
);
289 (void) ap_rcm_ctl(a
, c
);
293 case CMD_RCM_OFFLINE
:
294 case CMD_RCM_CAP_DEL
:
295 rc
= ap_rcm_ctl(a
, c
);
298 case CMD_RCM_CAP_ADD
:
300 case CMD_RCM_CAP_NOTIFY
:
301 (void) ap_rcm_ctl(a
, c
);
306 * Disable fast reboot if a CPU/MEM/IOH hotplug event happens.
307 * Note: this is a temporary solution and will be revised when
308 * fast reboot can support CPU/MEM/IOH DR operations in the
311 * ACPI BIOS generates some static ACPI tables, such as MADT,
312 * SRAT and SLIT, to describe the system hardware configuration
313 * on power-on. When a CPU/MEM/IOH hotplug event happens, those
314 * static tables won't be updated and will become stale.
316 * If we reset the system by fast reboot, BIOS will have no
317 * chance to regenerate those staled static tables. Fast reboot
318 * can't tolerate such inconsistency between staled ACPI tables
319 * and real hardware configuration yet.
321 * A temporary solution is introduced to disable fast reboot if
322 * CPU/MEM/IOH hotplug event happens. This solution should be
323 * revised when fast reboot is enhanced to support CPU/MEM/IOH
330 if (!fastreboot_disabled
&&
331 scf_fastreboot_default_set_transient(B_FALSE
) ==
333 fastreboot_disabled
= 1;
350 (void) ap_rcm_ctl(a
, CMD_RCM_RESUME
);
353 * Check if any operations failed. If so, attempt to rollback
354 * to previously known states.
355 * Note: The rollback is currently limited to RCM operations.
358 if (c
== CMD_UNCONFIGURE
||
359 c
== CMD_RCM_OFFLINE
||
360 c
== CMD_RCM_CAP_DEL
) {
361 DBG("ap_seq_exec: %s failed\n", ap_cmd_name(c
));
364 case CMD_UNCONFIGURE
:
366 * If the unconfigure operation fails, perform
367 * an RCM_ONLINE and RCM_CAP_NOTIFY only. This
368 * keeps RCM clients consistent with the domain.
370 recover_f
= CMD_RCM_ONLINE
;
371 recover_l
= CMD_RCM_ONLINE
;
372 DBG_RECOVER_MSG(recover_f
, recover_l
);
373 (void) ap_seq_exec(a
, cmd
, recover_f
,
376 recover_f
= CMD_RCM_CAP_NOTIFY
;
377 recover_l
= CMD_RCM_CAP_NOTIFY
;
378 DBG_RECOVER_MSG(recover_f
, recover_l
);
379 (void) ap_seq_exec(a
, cmd
, recover_f
,
382 case CMD_RCM_OFFLINE
:
383 recover_f
= CMD_RCM_ONLINE
;
384 recover_l
= CMD_RCM_CAP_ADD
;
385 DBG_RECOVER_MSG(recover_f
, recover_l
);
386 (void) ap_seq_exec(a
, cmd
, recover_f
,
389 case CMD_RCM_CAP_DEL
:
390 recover_f
= CMD_RCM_CAP_ADD
;
391 recover_l
= CMD_RCM_CAP_ADD
;
392 DBG_RECOVER_MSG(recover_f
, recover_l
);
393 (void) ap_seq_exec(a
, cmd
, recover_f
,
400 DBG("recovery complete!\n");
407 ap_cmd_exec(apd_t
*a
, int cmd
)
409 return (ap_seq_exec(a
, cmd
, cmd
, cmd
));
413 ap_cmd_seq(apd_t
*a
, int cmd
)
418 switch (ap_seq_get(a
, cmd
, &first
, &last
)) {
420 rc
= ap_seq_exec(a
, cmd
, first
, last
);