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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <stdlib.h>
  28 #include <errno.h>
  29 #include <sys/types.h>
  30 #include <libnvpair.h>
  31 #include <sys/fcntl.h>
  32 #include <sys/devfm.h>
  33 #include <fmd_agent_impl.h>
  34 
  35 static int
  36 cleanup_set_errno(fmd_agent_hdl_t *hdl, nvlist_t *innvl, nvlist_t *outnvl,
  37     int err)
  38 {
  39         if (innvl != NULL)
  40                 nvlist_free(innvl);
  41         if (outnvl != NULL)
  42                 nvlist_free(outnvl);
  43         return (fmd_agent_seterrno(hdl, err));
  44 }
  45 
  46 static int
  47 fmd_agent_physcpu_info_v1(fmd_agent_hdl_t *hdl, nvlist_t ***cpusp,
  48     uint_t *ncpup)
  49 {
  50         int err;
  51         nvlist_t *nvl, **nvl_array, **cpus;
  52         uint_t i, n;
  53 
  54         if ((err = fmd_agent_nvl_ioctl(hdl, FM_IOC_PHYSCPU_INFO, 1,
  55             NULL, &nvl)) != 0)
  56                 return (cleanup_set_errno(hdl, NULL, NULL, err));
  57         if ((err = nvlist_lookup_nvlist_array(nvl, FM_PHYSCPU_INFO_CPUS,
  58             &cpus, &n)) != 0)
  59                 return (cleanup_set_errno(hdl, NULL, nvl, err));
  60 
  61         if ((nvl_array = umem_alloc(sizeof (nvlist_t *) * n, UMEM_DEFAULT))
  62             == NULL)
  63                 return (cleanup_set_errno(hdl, NULL, nvl, errno));
  64         for (i = 0; i < n; i++) {
  65                 if ((err = nvlist_dup(cpus[i], nvl_array + i, 0)) != 0) {
  66                         while (i > 0)
  67                                 nvlist_free(nvl_array[--i]);
  68                         umem_free(nvl_array, sizeof (nvlist_t *) * n);
  69                         return (cleanup_set_errno(hdl, NULL, nvl, err));
  70                 }
  71         }
  72 
  73         nvlist_free(nvl);
  74         *cpusp = nvl_array;
  75         *ncpup = n;
  76         return (0);
  77 }
  78 
  79 int
  80 fmd_agent_physcpu_info(fmd_agent_hdl_t *hdl, nvlist_t ***cpusp, uint_t *ncpu)
  81 {
  82         uint32_t ver;
  83 
  84         if (fmd_agent_version(hdl, FM_CPU_INFO_VERSION, &ver) == -1)
  85                 return (fmd_agent_seterrno(hdl, errno));
  86 
  87         switch (ver) {
  88         case 1:
  89                 return (fmd_agent_physcpu_info_v1(hdl, cpusp, ncpu));
  90 
  91         default:
  92                 return (fmd_agent_seterrno(hdl, ENOTSUP));
  93         }
  94 }
  95 
  96 static int
  97 fmd_agent_cpuop_v1(fmd_agent_hdl_t *hdl, int cmd, int chipid, int coreid,
  98     int strandid, int *old_status)
  99 {
 100         int err;
 101         nvlist_t *nvl = NULL, *outnvl = NULL;
 102         int32_t status;
 103 
 104         if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0 ||
 105             (err = nvlist_add_int32(nvl, FM_CPU_RETIRE_CHIP_ID, chipid)) != 0 ||
 106             (err = nvlist_add_int32(nvl, FM_CPU_RETIRE_CORE_ID, coreid)) != 0 ||
 107             (err = nvlist_add_int32(nvl, FM_CPU_RETIRE_STRAND_ID, strandid))
 108             != 0 || (err = fmd_agent_nvl_ioctl(hdl, cmd, 1, nvl, &outnvl)) != 0)
 109                 return (cleanup_set_errno(hdl, nvl, NULL, err));
 110 
 111         nvlist_free(nvl);
 112         if (outnvl != NULL) {
 113                 if (old_status != NULL) {
 114                         (void) nvlist_lookup_int32(outnvl,
 115                             FM_CPU_RETIRE_OLDSTATUS, &status);
 116                         *old_status = status;
 117                 }
 118                 nvlist_free(outnvl);
 119         }
 120 
 121         return (0);
 122 }
 123 
 124 static int
 125 fmd_agent_cpuop(fmd_agent_hdl_t *hdl, int cmd, int chipid, int coreid,
 126     int strandid, int *old_status)
 127 {
 128         uint32_t ver;
 129 
 130         if (fmd_agent_version(hdl, FM_CPU_OP_VERSION, &ver) == -1)
 131                 return (cleanup_set_errno(hdl, NULL, NULL, errno));
 132 
 133         switch (ver) {
 134         case 1:
 135                 return (fmd_agent_cpuop_v1(hdl, cmd, chipid, coreid, strandid,
 136                     old_status));
 137 
 138         default:
 139                 return (fmd_agent_seterrno(hdl, ENOTSUP));
 140         }
 141 }
 142 
 143 int
 144 fmd_agent_cpu_retire(fmd_agent_hdl_t *hdl, int chipid, int coreid, int strandid)
 145 {
 146         int ret;
 147 
 148         ret = fmd_agent_cpuop(hdl, FM_IOC_CPU_RETIRE, chipid, coreid, strandid,
 149             NULL);
 150 
 151         return (ret == 0 ? FMD_AGENT_RETIRE_DONE : FMD_AGENT_RETIRE_FAIL);
 152 }
 153 
 154 int
 155 fmd_agent_cpu_isretired(fmd_agent_hdl_t *hdl, int chipid, int coreid,
 156     int strandid)
 157 {
 158         int ret, status;
 159 
 160         ret = fmd_agent_cpuop(hdl, FM_IOC_CPU_STATUS, chipid, coreid, strandid,
 161             &status);
 162 
 163         return (ret == 0 && status != P_ONLINE ?
 164             FMD_AGENT_RETIRE_DONE : FMD_AGENT_RETIRE_FAIL);
 165 }
 166 
 167 int
 168 fmd_agent_cpu_unretire(fmd_agent_hdl_t *hdl, int chipid, int coreid,
 169     int strandid)
 170 {
 171         int ret;
 172 
 173         ret = fmd_agent_cpuop(hdl, FM_IOC_CPU_UNRETIRE, chipid, coreid,
 174             strandid, NULL);
 175 
 176         return (ret == 0 ? FMD_AGENT_RETIRE_DONE : FMD_AGENT_RETIRE_FAIL);
 177 }