1*aed5247fSJoshua M. Clulow /*
2*aed5247fSJoshua M. Clulow * This file and its contents are supplied under the terms of the
3*aed5247fSJoshua M. Clulow * Common Development and Distribution License ("CDDL"), version 1.0.
4*aed5247fSJoshua M. Clulow * You may only use this file in accordance with the terms of version
5*aed5247fSJoshua M. Clulow * 1.0 of the CDDL.
6*aed5247fSJoshua M. Clulow *
7*aed5247fSJoshua M. Clulow * A full copy of the text of the CDDL should have accompanied this
8*aed5247fSJoshua M. Clulow * source. A copy of the CDDL is also available via the Internet at
9*aed5247fSJoshua M. Clulow * http://www.illumos.org/license/CDDL.
10*aed5247fSJoshua M. Clulow */
11*aed5247fSJoshua M. Clulow
12*aed5247fSJoshua M. Clulow /*
13*aed5247fSJoshua M. Clulow * Copyright (c) 2013, Joyent, Inc. All rights reserved.
14*aed5247fSJoshua M. Clulow */
15*aed5247fSJoshua M. Clulow
16*aed5247fSJoshua M. Clulow #include <unistd.h>
17*aed5247fSJoshua M. Clulow #include <stdio.h>
18*aed5247fSJoshua M. Clulow #include <stdlib.h>
19*aed5247fSJoshua M. Clulow #include <fcntl.h>
20*aed5247fSJoshua M. Clulow #include <string.h>
21*aed5247fSJoshua M. Clulow #include <strings.h>
22*aed5247fSJoshua M. Clulow #include <limits.h>
23*aed5247fSJoshua M. Clulow #include <alloca.h>
24*aed5247fSJoshua M. Clulow #include <errno.h>
25*aed5247fSJoshua M. Clulow #include <libnvpair.h>
26*aed5247fSJoshua M. Clulow #include <sys/types.h>
27*aed5247fSJoshua M. Clulow #include <sys/stat.h>
28*aed5247fSJoshua M. Clulow #include <sys/param.h>
29*aed5247fSJoshua M. Clulow #include <sys/fm/protocol.h>
30*aed5247fSJoshua M. Clulow #include <fm/libtopo.h>
31*aed5247fSJoshua M. Clulow #include <fm/topo_mod.h>
32*aed5247fSJoshua M. Clulow
33*aed5247fSJoshua M. Clulow #include "sys/scsi/adapters/mpt_sas/mptsas_ioctl.h"
34*aed5247fSJoshua M. Clulow
35*aed5247fSJoshua M. Clulow #define TOPO_METH_MPTSAS_LED_MODE_VERSION 0
36*aed5247fSJoshua M. Clulow
37*aed5247fSJoshua M. Clulow static int fac_prov_mptsas_enum(topo_mod_t *, tnode_t *, const char *,
38*aed5247fSJoshua M. Clulow topo_instance_t, topo_instance_t, void *, void *);
39*aed5247fSJoshua M. Clulow
40*aed5247fSJoshua M. Clulow /*
41*aed5247fSJoshua M. Clulow * mpt_sas facility provider methods
42*aed5247fSJoshua M. Clulow */
43*aed5247fSJoshua M. Clulow static int mptsas_led_mode(topo_mod_t *, tnode_t *, topo_version_t,
44*aed5247fSJoshua M. Clulow nvlist_t *, nvlist_t **);
45*aed5247fSJoshua M. Clulow
46*aed5247fSJoshua M. Clulow const topo_modops_t mptsas_ops = { fac_prov_mptsas_enum, NULL };
47*aed5247fSJoshua M. Clulow
48*aed5247fSJoshua M. Clulow const topo_modinfo_t mptsas_info =
49*aed5247fSJoshua M. Clulow { "mpt_sas facility provider", FM_FMRI_SCHEME_HC, TOPO_VERSION,
50*aed5247fSJoshua M. Clulow &mptsas_ops };
51*aed5247fSJoshua M. Clulow
52*aed5247fSJoshua M. Clulow static const topo_method_t mptsas_fac_methods[] = {
53*aed5247fSJoshua M. Clulow { "mptsas_led_mode", TOPO_PROP_METH_DESC,
54*aed5247fSJoshua M. Clulow TOPO_METH_MPTSAS_LED_MODE_VERSION,
55*aed5247fSJoshua M. Clulow TOPO_STABILITY_INTERNAL, mptsas_led_mode },
56*aed5247fSJoshua M. Clulow { NULL }
57*aed5247fSJoshua M. Clulow };
58*aed5247fSJoshua M. Clulow
59*aed5247fSJoshua M. Clulow /*ARGSUSED*/
60*aed5247fSJoshua M. Clulow int
_topo_init(topo_mod_t * mod,topo_version_t version)61*aed5247fSJoshua M. Clulow _topo_init(topo_mod_t *mod, topo_version_t version)
62*aed5247fSJoshua M. Clulow {
63*aed5247fSJoshua M. Clulow if (getenv("TOPOFACMPTSASDEBUG") != NULL)
64*aed5247fSJoshua M. Clulow topo_mod_setdebug(mod);
65*aed5247fSJoshua M. Clulow
66*aed5247fSJoshua M. Clulow return (topo_mod_register(mod, &mptsas_info, TOPO_VERSION));
67*aed5247fSJoshua M. Clulow }
68*aed5247fSJoshua M. Clulow
69*aed5247fSJoshua M. Clulow void
_topo_fini(topo_mod_t * mod)70*aed5247fSJoshua M. Clulow _topo_fini(topo_mod_t *mod)
71*aed5247fSJoshua M. Clulow {
72*aed5247fSJoshua M. Clulow topo_mod_unregister(mod);
73*aed5247fSJoshua M. Clulow }
74*aed5247fSJoshua M. Clulow
75*aed5247fSJoshua M. Clulow static int
do_led_control(topo_mod_t * mod,char * devctl,uint16_t enclosure,uint16_t slot,uint8_t led,uint32_t * ledmode,boolean_t set)76*aed5247fSJoshua M. Clulow do_led_control(topo_mod_t *mod, char *devctl, uint16_t enclosure,
77*aed5247fSJoshua M. Clulow uint16_t slot, uint8_t led, uint32_t *ledmode, boolean_t set)
78*aed5247fSJoshua M. Clulow {
79*aed5247fSJoshua M. Clulow int fd;
80*aed5247fSJoshua M. Clulow mptsas_led_control_t lc;
81*aed5247fSJoshua M. Clulow
82*aed5247fSJoshua M. Clulow bzero(&lc, sizeof (lc));
83*aed5247fSJoshua M. Clulow
84*aed5247fSJoshua M. Clulow lc.Command = set ? MPTSAS_LEDCTL_FLAG_SET : MPTSAS_LEDCTL_FLAG_GET;
85*aed5247fSJoshua M. Clulow lc.Enclosure = enclosure;
86*aed5247fSJoshua M. Clulow lc.Slot = slot;
87*aed5247fSJoshua M. Clulow lc.Led = led;
88*aed5247fSJoshua M. Clulow lc.LedStatus = *ledmode;
89*aed5247fSJoshua M. Clulow
90*aed5247fSJoshua M. Clulow if ((fd = open(devctl, (set ? O_RDWR : O_RDONLY))) == -1) {
91*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "devctl open failed: %s",
92*aed5247fSJoshua M. Clulow strerror(errno));
93*aed5247fSJoshua M. Clulow return (-1);
94*aed5247fSJoshua M. Clulow }
95*aed5247fSJoshua M. Clulow
96*aed5247fSJoshua M. Clulow if (ioctl(fd, MPTIOCTL_LED_CONTROL, &lc) == -1) {
97*aed5247fSJoshua M. Clulow if (errno == ENOENT) {
98*aed5247fSJoshua M. Clulow /*
99*aed5247fSJoshua M. Clulow * If there is not presently a target attached for
100*aed5247fSJoshua M. Clulow * a particular enclosure/slot pair then the driver
101*aed5247fSJoshua M. Clulow * does not track LED status for this bay. Assume
102*aed5247fSJoshua M. Clulow * all LEDs are off.
103*aed5247fSJoshua M. Clulow */
104*aed5247fSJoshua M. Clulow lc.LedStatus = 0;
105*aed5247fSJoshua M. Clulow } else {
106*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "led control ioctl failed: %s",
107*aed5247fSJoshua M. Clulow strerror(errno));
108*aed5247fSJoshua M. Clulow (void) close(fd);
109*aed5247fSJoshua M. Clulow return (-1);
110*aed5247fSJoshua M. Clulow }
111*aed5247fSJoshua M. Clulow }
112*aed5247fSJoshua M. Clulow
113*aed5247fSJoshua M. Clulow *ledmode = lc.LedStatus ? TOPO_LED_STATE_ON : TOPO_LED_STATE_OFF;
114*aed5247fSJoshua M. Clulow
115*aed5247fSJoshua M. Clulow (void) close(fd);
116*aed5247fSJoshua M. Clulow return (0);
117*aed5247fSJoshua M. Clulow }
118*aed5247fSJoshua M. Clulow
119*aed5247fSJoshua M. Clulow static int
mptsas_led_mode(topo_mod_t * mod,tnode_t * node,topo_version_t vers,nvlist_t * in,nvlist_t ** nvout)120*aed5247fSJoshua M. Clulow mptsas_led_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
121*aed5247fSJoshua M. Clulow nvlist_t *in, nvlist_t **nvout)
122*aed5247fSJoshua M. Clulow {
123*aed5247fSJoshua M. Clulow int err, ret = 0;
124*aed5247fSJoshua M. Clulow tnode_t *pnode = topo_node_parent(node);
125*aed5247fSJoshua M. Clulow uint32_t type, ledmode = 0;
126*aed5247fSJoshua M. Clulow nvlist_t *pargs, *nvl;
127*aed5247fSJoshua M. Clulow char *driver = NULL, *devctl = NULL;
128*aed5247fSJoshua M. Clulow uint32_t enclosure, slot;
129*aed5247fSJoshua M. Clulow uint8_t mptsas_led;
130*aed5247fSJoshua M. Clulow boolean_t set;
131*aed5247fSJoshua M. Clulow
132*aed5247fSJoshua M. Clulow if (vers > TOPO_METH_MPTSAS_LED_MODE_VERSION)
133*aed5247fSJoshua M. Clulow return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
134*aed5247fSJoshua M. Clulow
135*aed5247fSJoshua M. Clulow if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING,
136*aed5247fSJoshua M. Clulow TOPO_BINDING_DRIVER, &driver, &err) != 0 ||
137*aed5247fSJoshua M. Clulow strcmp("mpt_sas", driver) != 0) {
138*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Facility driver was not mpt_sas",
139*aed5247fSJoshua M. Clulow __func__);
140*aed5247fSJoshua M. Clulow ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
141*aed5247fSJoshua M. Clulow goto out;
142*aed5247fSJoshua M. Clulow }
143*aed5247fSJoshua M. Clulow if (topo_prop_get_uint32(node, TOPO_PGROUP_FACILITY, TOPO_FACILITY_TYPE,
144*aed5247fSJoshua M. Clulow &type, &err) != 0) {
145*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Failed to lookup %s property "
146*aed5247fSJoshua M. Clulow "(%s)", __func__, TOPO_FACILITY_TYPE, topo_strerror(err));
147*aed5247fSJoshua M. Clulow return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
148*aed5247fSJoshua M. Clulow }
149*aed5247fSJoshua M. Clulow switch (type) {
150*aed5247fSJoshua M. Clulow case (TOPO_LED_TYPE_SERVICE):
151*aed5247fSJoshua M. Clulow mptsas_led = MPTSAS_LEDCTL_LED_FAIL;
152*aed5247fSJoshua M. Clulow break;
153*aed5247fSJoshua M. Clulow case (TOPO_LED_TYPE_LOCATE):
154*aed5247fSJoshua M. Clulow mptsas_led = MPTSAS_LEDCTL_LED_IDENT;
155*aed5247fSJoshua M. Clulow break;
156*aed5247fSJoshua M. Clulow case (TOPO_LED_TYPE_OK2RM):
157*aed5247fSJoshua M. Clulow mptsas_led = MPTSAS_LEDCTL_LED_OK2RM;
158*aed5247fSJoshua M. Clulow break;
159*aed5247fSJoshua M. Clulow default:
160*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Invalid LED type: 0x%x\n", __func__,
161*aed5247fSJoshua M. Clulow type);
162*aed5247fSJoshua M. Clulow return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
163*aed5247fSJoshua M. Clulow }
164*aed5247fSJoshua M. Clulow if (topo_prop_get_string(pnode, TOPO_PGROUP_BINDING,
165*aed5247fSJoshua M. Clulow TOPO_BINDING_DEVCTL, &devctl, &err) != 0 ||
166*aed5247fSJoshua M. Clulow topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING,
167*aed5247fSJoshua M. Clulow TOPO_BINDING_ENCLOSURE, &enclosure, &err) != 0 ||
168*aed5247fSJoshua M. Clulow topo_prop_get_uint32(pnode, TOPO_PGROUP_BINDING,
169*aed5247fSJoshua M. Clulow TOPO_BINDING_SLOT, &slot, &err) != 0) {
170*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Facility was missing mpt_sas binding"
171*aed5247fSJoshua M. Clulow " properties\n", __func__);
172*aed5247fSJoshua M. Clulow ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
173*aed5247fSJoshua M. Clulow goto out;
174*aed5247fSJoshua M. Clulow }
175*aed5247fSJoshua M. Clulow
176*aed5247fSJoshua M. Clulow if ((nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs) == 0) &&
177*aed5247fSJoshua M. Clulow nvlist_exists(pargs, TOPO_PROP_VAL_VAL)) {
178*aed5247fSJoshua M. Clulow /*
179*aed5247fSJoshua M. Clulow * Set the LED mode
180*aed5247fSJoshua M. Clulow */
181*aed5247fSJoshua M. Clulow set = B_TRUE;
182*aed5247fSJoshua M. Clulow if ((ret = nvlist_lookup_uint32(pargs, TOPO_PROP_VAL_VAL,
183*aed5247fSJoshua M. Clulow &ledmode)) != 0) {
184*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Failed to lookup %s nvpair "
185*aed5247fSJoshua M. Clulow "(%s)\n", __func__, TOPO_PROP_VAL_VAL,
186*aed5247fSJoshua M. Clulow strerror(ret));
187*aed5247fSJoshua M. Clulow ret = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
188*aed5247fSJoshua M. Clulow goto out;
189*aed5247fSJoshua M. Clulow }
190*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Setting LED mode to %s\n", __func__,
191*aed5247fSJoshua M. Clulow ledmode ? "ON" : "OFF");
192*aed5247fSJoshua M. Clulow } else {
193*aed5247fSJoshua M. Clulow /*
194*aed5247fSJoshua M. Clulow * Get the LED mode
195*aed5247fSJoshua M. Clulow */
196*aed5247fSJoshua M. Clulow set = B_FALSE;
197*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Getting LED mode\n", __func__);
198*aed5247fSJoshua M. Clulow }
199*aed5247fSJoshua M. Clulow
200*aed5247fSJoshua M. Clulow if (do_led_control(mod, devctl, enclosure, slot, mptsas_led, &ledmode,
201*aed5247fSJoshua M. Clulow set) != 0) {
202*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: do_led_control failed", __func__);
203*aed5247fSJoshua M. Clulow ret = topo_mod_seterrno(mod, EMOD_UNKNOWN);
204*aed5247fSJoshua M. Clulow goto out;
205*aed5247fSJoshua M. Clulow }
206*aed5247fSJoshua M. Clulow
207*aed5247fSJoshua M. Clulow if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
208*aed5247fSJoshua M. Clulow nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, TOPO_LED_MODE) != 0 ||
209*aed5247fSJoshua M. Clulow nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_UINT32) != 0 ||
210*aed5247fSJoshua M. Clulow nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, ledmode) != 0) {
211*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: Failed to allocate 'out' nvlist\n",
212*aed5247fSJoshua M. Clulow __func__);
213*aed5247fSJoshua M. Clulow nvlist_free(nvl);
214*aed5247fSJoshua M. Clulow ret = topo_mod_seterrno(mod, EMOD_NOMEM);
215*aed5247fSJoshua M. Clulow goto out;
216*aed5247fSJoshua M. Clulow }
217*aed5247fSJoshua M. Clulow *nvout = nvl;
218*aed5247fSJoshua M. Clulow
219*aed5247fSJoshua M. Clulow out:
220*aed5247fSJoshua M. Clulow if (driver != NULL)
221*aed5247fSJoshua M. Clulow topo_mod_strfree(mod, driver);
222*aed5247fSJoshua M. Clulow if (devctl != NULL)
223*aed5247fSJoshua M. Clulow topo_mod_strfree(mod, devctl);
224*aed5247fSJoshua M. Clulow return (ret);
225*aed5247fSJoshua M. Clulow }
226*aed5247fSJoshua M. Clulow
227*aed5247fSJoshua M. Clulow /*ARGSUSED*/
228*aed5247fSJoshua M. Clulow static int
fac_prov_mptsas_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * unused)229*aed5247fSJoshua M. Clulow fac_prov_mptsas_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
230*aed5247fSJoshua M. Clulow topo_instance_t min, topo_instance_t max, void *arg, void *unused)
231*aed5247fSJoshua M. Clulow {
232*aed5247fSJoshua M. Clulow if (topo_node_flags(rnode) == TOPO_NODE_FACILITY) {
233*aed5247fSJoshua M. Clulow if (topo_method_register(mod, rnode, mptsas_fac_methods) != 0) {
234*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: topo_method_register() "
235*aed5247fSJoshua M. Clulow "failed: %s", __func__, topo_mod_errmsg(mod));
236*aed5247fSJoshua M. Clulow return (-1);
237*aed5247fSJoshua M. Clulow }
238*aed5247fSJoshua M. Clulow return (0);
239*aed5247fSJoshua M. Clulow }
240*aed5247fSJoshua M. Clulow
241*aed5247fSJoshua M. Clulow topo_mod_dprintf(mod, "%s: unexpected node flags %x", __func__,
242*aed5247fSJoshua M. Clulow topo_node_flags(rnode));
243*aed5247fSJoshua M. Clulow return (-1);
244*aed5247fSJoshua M. Clulow }
245