Home | History | Annotate | Download | only in common
      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