root/usr/src/cmd/pcidr/plugins/default/pcidr_plugin.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/systeminfo.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dr.h>
#include <syslog.h>
#include <libnvpair.h>
#include <stdarg.h>
#include <assert.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <pcidr.h>
#include <pcidr_cfga.h>


PCIDR_PLUGIN_PROTO(attrlistp, optp)
{
        char *fn = PCIDR_PLUGIN_SYMSTR;
        int rv = 0;
        char *cfga_errstr = NULL;
        char *str, *apid;
        cfga_list_data_t *cfga_listp = NULL;
        cfga_cmd_t cmd;
        int cfga_list_len;
        pcidr_attrs_t dr;

        pcidr_set_logopt(&optp->logopt);

        if (pcidr_get_attrs(attrlistp, &dr) != 0 ||
            pcidr_check_attrs(&dr) != 0) {
                dprint(DWARN, "%s: invalid or missing attributes\n", fn);
                return (EINVAL);
        }

        /*
         * get state of APID; enforce the cfgadm pci plugin implementation of
         * returning one matching AP per supplied apid string
         */
        rv = config_list_ext(1, &dr.dr_ap_id, &cfga_listp, &cfga_list_len,
            NULL, NULL, &cfga_errstr, CFGA_FLAG_LIST_ALL);
        if (rv != CFGA_OK) {
                str = pcidr_cfga_err_name(rv);
                if (str == NULL)
                        str = "unrecognized rv!";
                dprint(DDEBUG, "%s: config_list_ext() on apid = \"%s\" "
                    "failed: rv = %d (%s)", fn, dr.dr_ap_id, rv, str);

                if (cfga_errstr != NULL) {
                        dprint(DDEBUG, ", error string = \"%s\"",
                            cfga_errstr);
                        free(cfga_errstr);
                }
                dprint(DDEBUG, "\n");
                rv = EINVAL;
                goto OUT;
        }
        if (cfga_list_len != 1) {
                dprint(DWARN, "%s: invalid condition - more than one AP was "
                    "found for the APID \"%s\"\n", fn, dr.dr_ap_id);
                rv = EINVAL;
                goto OUT;
        }

        /*
         * perform DR
         */
        dprint(DINFO, "%s: showing info and performing DR on APID(s) "
            "matching \"%s\"\n", fn, dr.dr_ap_id);

        cmd = CFGA_CMD_NONE;
        dprint(DINFO, "===========================================\n", fn);
        pcidr_print_cfga(DINFO, &cfga_listp[0], "  .. ");
        apid = cfga_listp[0].ap_phys_id;

        if (strcmp(dr.dr_req_type, DR_REQ_OUTGOING_RES) == 0) {
                cmd = CFGA_CMD_DISCONNECT;
                dprint(DINFO, "%s: disconnecting ...\n", fn, apid);

                rv = pcidr_cfga_do_cmd(cmd, &cfga_listp[0]);
                if (rv < 0) {
                        dprint(DINFO, "%s: disconnect FAILED\n", fn);
                        rv = EIO;
                }
                else
                        dprint(DINFO, "%s: disconnect OK\n", fn);

                goto OUT;
        }
        if (strcmp(dr.dr_req_type, DR_REQ_INCOMING_RES) == 0) {
                cmd = CFGA_CMD_CONFIGURE;
                dprint(DINFO, "%s: configuring ...\n", fn, apid);

                rv = pcidr_cfga_do_cmd(cmd, &cfga_listp[0]);
                if (rv < 0) {
                        dprint(DINFO, "%s: configure FAILED\n", fn);
                        rv = EIO;
                } else
                        dprint(DINFO, "%s: configure OK\n", fn);

                goto OUT;
        }

        /* we should not get here if pcidr_check_attrs() is correct */
        dprint(DWARN, "%s: invalid dr_req_type = %s\n", fn, dr.dr_req_type);
        assert(cmd != CFGA_CMD_NONE);
        return (EINVAL);
        /*NOTREACHED*/
OUT:
        if (cfga_listp != NULL)
                free(cfga_listp);
        return (rv);
}