1e4f5a11dSJames Kremer /*
2e4f5a11dSJames Kremer  * CDDL HEADER START
3e4f5a11dSJames Kremer  *
4e4f5a11dSJames Kremer  * The contents of this file are subject to the terms of the
5e4f5a11dSJames Kremer  * Common Development and Distribution License (the "License").
6e4f5a11dSJames Kremer  * You may not use this file except in compliance with the License.
7e4f5a11dSJames Kremer  *
8e4f5a11dSJames Kremer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e4f5a11dSJames Kremer  * or http://www.opensolaris.org/os/licensing.
10e4f5a11dSJames Kremer  * See the License for the specific language governing permissions
11e4f5a11dSJames Kremer  * and limitations under the License.
12e4f5a11dSJames Kremer  *
13e4f5a11dSJames Kremer  * When distributing Covered Code, include this CDDL HEADER in each
14e4f5a11dSJames Kremer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e4f5a11dSJames Kremer  * If applicable, add the following below this CDDL HEADER, with the
16e4f5a11dSJames Kremer  * fields enclosed by brackets "[]" replaced with your own identifying
17e4f5a11dSJames Kremer  * information: Portions Copyright [yyyy] [name of copyright owner]
18e4f5a11dSJames Kremer  *
19e4f5a11dSJames Kremer  * CDDL HEADER END
20e4f5a11dSJames Kremer  */
21e4f5a11dSJames Kremer /*
22e4f5a11dSJames Kremer  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23e4f5a11dSJames Kremer  */
24e4f5a11dSJames Kremer 
25e4f5a11dSJames Kremer /*
26e4f5a11dSJames Kremer  * SCSI Enclosure Services Log Transport Module
27e4f5a11dSJames Kremer  *
28e4f5a11dSJames Kremer  * This transport module is responsible for accessing the ses devices seen
29e4f5a11dSJames Kremer  * from this host, reading their logs, generating ereports for targeted
30e4f5a11dSJames Kremer  * entries, and then writing the log contents to a well known location in
31e4f5a11dSJames Kremer  * the filesystem.
32e4f5a11dSJames Kremer  *
33e4f5a11dSJames Kremer  */
34e4f5a11dSJames Kremer 
35e4f5a11dSJames Kremer #include <ctype.h>
36e4f5a11dSJames Kremer #include <fm/fmd_api.h>
37e4f5a11dSJames Kremer #include <fm/libtopo.h>
38e4f5a11dSJames Kremer #include <fm/topo_hc.h>
39e4f5a11dSJames Kremer #include <fm/topo_mod.h>
40e4f5a11dSJames Kremer #include <limits.h>
41e4f5a11dSJames Kremer #include <string.h>
42e4f5a11dSJames Kremer #include <sys/fm/io/scsi.h>
43e4f5a11dSJames Kremer #include <sys/fm/protocol.h>
44e4f5a11dSJames Kremer #include <stdio.h>
45e4f5a11dSJames Kremer #include <time.h>
46e4f5a11dSJames Kremer #include <fm/libseslog.h>
47e4f5a11dSJames Kremer #include <errno.h>
48e4f5a11dSJames Kremer #include <sys/types.h>
49e4f5a11dSJames Kremer #include <sys/stat.h>
50e4f5a11dSJames Kremer 
51e4f5a11dSJames Kremer /*
52e4f5a11dSJames Kremer  * This struct contains the default property values.  These may
53e4f5a11dSJames Kremer  * be overridden by entries in a ses_log_transport.conf file.
54744e50acSStephen Brooks  * The severity is set to -1 here so that the _fmd_init routine will
55744e50acSStephen Brooks  * determine the default severity based on the constants in libseslog.h.
56e4f5a11dSJames Kremer  */
57e4f5a11dSJames Kremer static const fmd_prop_t fmd_props[] = {
58*7656b922SStephen Brooks 	{ "interval",	FMD_TYPE_TIME,	    "60s"},
59*7656b922SStephen Brooks 	{ "severity",	FMD_TYPE_INT32,	    "-1"},
60*7656b922SStephen Brooks 	{ "path",	FMD_TYPE_STRING,    "/var/fm/fmd/ses_logs/"},
61*7656b922SStephen Brooks 	{ "logcount",	FMD_TYPE_UINT32,    "5"},
62*7656b922SStephen Brooks 	{ "maxlogsize", FMD_TYPE_UINT32,    "1000000"},
637a087849SStephen Brooks 	{ NULL, 0,	NULL}
64e4f5a11dSJames Kremer };
65e4f5a11dSJames Kremer 
66e4f5a11dSJames Kremer /* Maintains statistics on dropped ereports. */
67e4f5a11dSJames Kremer static struct slt_stat
68e4f5a11dSJames Kremer {
69e4f5a11dSJames Kremer 	fmd_stat_t dropped;
70e4f5a11dSJames Kremer } slt_stats = {
71e4f5a11dSJames Kremer 	{ "dropped", FMD_TYPE_UINT64, "number of dropped ereports"}
72e4f5a11dSJames Kremer };
73e4f5a11dSJames Kremer 
74e4f5a11dSJames Kremer /*
75e4f5a11dSJames Kremer  * This structure maintains a reference to the input values, transport, and
76e4f5a11dSJames Kremer  * other data which is held by FMD and retrieved whenever an entry point
77e4f5a11dSJames Kremer  * is called.
78e4f5a11dSJames Kremer  */
79e4f5a11dSJames Kremer typedef struct ses_log_monitor
80e4f5a11dSJames Kremer {
81*7656b922SStephen Brooks 	fmd_hdl_t *slt_hdl;	    /* opaque handle for this transport */
82*7656b922SStephen Brooks 	fmd_xprt_t *slt_xprt;	    /* ereport transport */
83*7656b922SStephen Brooks 	id_t slt_timer;		    /* Timer for FMD polling use */
84*7656b922SStephen Brooks 	hrtime_t slt_interval;	    /* Polling interval */
85*7656b922SStephen Brooks 	int32_t slt_severity;	    /* Min severity for logging ereports */
86*7656b922SStephen Brooks 	char *slt_path;		    /* Output path for log files */
87*7656b922SStephen Brooks 	int32_t slt_log_count;	    /* Max rolled logs to keep  */
88e4f5a11dSJames Kremer 	int32_t slt_max_log_size;   /* Max log size before rolling */
89e4f5a11dSJames Kremer 	nvlist_t *slt_expanders;    /* List of expander log entries */
90e4f5a11dSJames Kremer } ses_log_monitor_t;
91e4f5a11dSJames Kremer 
92e4f5a11dSJames Kremer /* Contains expander log data retrieved from a topology node */
93e4f5a11dSJames Kremer typedef struct expander
94e4f5a11dSJames Kremer {
957a087849SStephen Brooks 	char slt_label[MAXNAMELEN]; /* The expander name */
967a087849SStephen Brooks 	char slt_pid[MAXNAMELEN];   /* The system product id */
977a087849SStephen Brooks 	char slt_key[MAXNAMELEN];   /* The expander key (sas address) */
98e4f5a11dSJames Kremer 	char slt_path[MAXPATHLEN];  /* The ses path to the expander */
99e4f5a11dSJames Kremer 	nvlist_t *fmri;		    /* The fmri for this target */
100e4f5a11dSJames Kremer } expander_t;
101e4f5a11dSJames Kremer 
102*7656b922SStephen Brooks #define	DATA_FIELD		"data"	    /* Label for the expander details */
103*7656b922SStephen Brooks #define	DEFAULT_DATA		"0"	    /* Default expander details value */
104*7656b922SStephen Brooks #define	MIN_LOG_SIZE		100000	    /* The minimum log file size. */
105*7656b922SStephen Brooks #define	MIN_LOG_COUNT		1	    /* Num of rolled files to keep */
106*7656b922SStephen Brooks #define	EXAMINE_FMRI_VALUE	0	    /* Extract fmri val */
107*7656b922SStephen Brooks #define	INVERT_FMRI_INSTANCE	1	    /* Invert an FMRI instance value */
108*7656b922SStephen Brooks #define	FATAL_ERROR		"fatal"	    /* ereport val for fatal errors */
1097a087849SStephen Brooks #define	NON_FATAL_ERROR		"non-fatal" /* val for non fatal errors */
110*7656b922SStephen Brooks #define	INVALID_OPERATION	0x01	    /* Invalid access_fmri operation */
111*7656b922SStephen Brooks #define	NULL_LOG_DATA		0x02	    /* Lib returned NULL log ref */
112*7656b922SStephen Brooks #define	INVALID_SEVERITY	0x03	    /* Invalid severity value */
113*7656b922SStephen Brooks #define	DATE_STRING_SIZE	16	    /* Size of date string prefix. */
114e4f5a11dSJames Kremer 
115e4f5a11dSJames Kremer /* Prototype needed for use in declaring and populating tables */
116e4f5a11dSJames Kremer static int invert_fmri(ses_log_monitor_t *, nvlist_t *);
117e4f5a11dSJames Kremer 
118e4f5a11dSJames Kremer /* Holds a code-operation pair.  Contains a log code an a function ptr */
119e4f5a11dSJames Kremer typedef struct code_operation {
120e4f5a11dSJames Kremer 	int code;
121e4f5a11dSJames Kremer 	int (*func_ptr)(ses_log_monitor_t *, nvlist_t *);
122e4f5a11dSJames Kremer } code_operation_t;
123e4f5a11dSJames Kremer 
124e4f5a11dSJames Kremer /* Holds a platform type and a list of code-operation structures */
125e4f5a11dSJames Kremer typedef struct platform {
126e4f5a11dSJames Kremer 	const char *pid;
127e4f5a11dSJames Kremer 	int count;
128e4f5a11dSJames Kremer 	code_operation_t *codes;
129e4f5a11dSJames Kremer } platform_t;
130e4f5a11dSJames Kremer 
131e4f5a11dSJames Kremer /* Holds a reference to all of the platforms */
132e4f5a11dSJames Kremer typedef struct platforms {
133e4f5a11dSJames Kremer 	int pcount;
134e4f5a11dSJames Kremer 	platform_t *plist;
135e4f5a11dSJames Kremer } platforms_t;
136e4f5a11dSJames Kremer 
137e4f5a11dSJames Kremer /* This is the genesis list of codes and functions. */
1387a087849SStephen Brooks static code_operation_t genesis_codes[] = {
139*7656b922SStephen Brooks 	{ 684002, invert_fmri },    /* Alternate expander is down */
140*7656b922SStephen Brooks 	{ 685002, invert_fmri }	    /* Alternate expander is down */
141e4f5a11dSJames Kremer };
142e4f5a11dSJames Kremer 
143e4f5a11dSJames Kremer /* This is the list of all platforms and their associated code op pairs. */
1447a087849SStephen Brooks static platform_t platform_list[] = {
145e4f5a11dSJames Kremer 	{ "SUN-GENESIS",
146e4f5a11dSJames Kremer 	    sizeof (genesis_codes) / sizeof (code_operation_t),
147e4f5a11dSJames Kremer 	    genesis_codes }
148e4f5a11dSJames Kremer };
149e4f5a11dSJames Kremer 
150e4f5a11dSJames Kremer /* This structure holds a reference to the platform list. */
151744e50acSStephen Brooks static const platforms_t platforms = {
152e4f5a11dSJames Kremer 	sizeof (platform_list) / sizeof (platform_t),
153e4f5a11dSJames Kremer 	platform_list
154e4f5a11dSJames Kremer };
155e4f5a11dSJames Kremer 
156e4f5a11dSJames Kremer /*
157e4f5a11dSJames Kremer  * Post ereports using this method.
158e4f5a11dSJames Kremer  */
159e4f5a11dSJames Kremer static void
slt_post_ereport(fmd_hdl_t * hdl,fmd_xprt_t * xprt,const char * ereport_class,uint64_t ena,nvlist_t * detector,nvlist_t * payload)160e4f5a11dSJames Kremer slt_post_ereport(fmd_hdl_t *hdl, fmd_xprt_t *xprt, const char *ereport_class,
161e4f5a11dSJames Kremer     uint64_t ena, nvlist_t *detector, nvlist_t *payload)
162e4f5a11dSJames Kremer {
163e4f5a11dSJames Kremer 	nvlist_t *nvl;
164e4f5a11dSJames Kremer 	int e = 0;
165e4f5a11dSJames Kremer 	char fullclass[PATH_MAX];
166e4f5a11dSJames Kremer 
167e4f5a11dSJames Kremer 	(void) snprintf(fullclass, sizeof (fullclass), "%s.io.sas.log.%s",
168e4f5a11dSJames Kremer 	    FM_EREPORT_CLASS, ereport_class);
169e4f5a11dSJames Kremer 
170e4f5a11dSJames Kremer 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) == 0) {
171e4f5a11dSJames Kremer 
172e4f5a11dSJames Kremer 		e |= nvlist_add_string(nvl, FM_CLASS, fullclass);
173e4f5a11dSJames Kremer 		e |= nvlist_add_uint8(nvl, FM_VERSION, FM_EREPORT_VERSION);
174e4f5a11dSJames Kremer 		e |= nvlist_add_uint64(nvl, FM_EREPORT_ENA, ena);
175e4f5a11dSJames Kremer 		e |= nvlist_add_nvlist(nvl, FM_EREPORT_DETECTOR, detector);
176e4f5a11dSJames Kremer 		e |= nvlist_merge(nvl, payload, 0);
177e4f5a11dSJames Kremer 
178e4f5a11dSJames Kremer 		if (e == 0) {
179e4f5a11dSJames Kremer 			fmd_xprt_post(hdl, xprt, nvl, 0);
180e4f5a11dSJames Kremer 		} else {
181e4f5a11dSJames Kremer 			nvlist_free(nvl);
182e4f5a11dSJames Kremer 			fmd_hdl_debug(hdl, "Error adding fields to ereport");
183e4f5a11dSJames Kremer 			slt_stats.dropped.fmds_value.ui64++;
184e4f5a11dSJames Kremer 		}
185e4f5a11dSJames Kremer 	} else {
186e4f5a11dSJames Kremer 		fmd_hdl_debug(hdl, "Could not allocate space for ereport");
187e4f5a11dSJames Kremer 		slt_stats.dropped.fmds_value.ui64++;
188e4f5a11dSJames Kremer 	}
189e4f5a11dSJames Kremer }
190e4f5a11dSJames Kremer 
191e4f5a11dSJames Kremer /*
192e4f5a11dSJames Kremer  * Create a directory if it doesn't exist.
193e4f5a11dSJames Kremer  * Parameters:
194e4f5a11dSJames Kremer  * path: The directory path to create.
195e4f5a11dSJames Kremer  * mode: The mode used when creating the directory.
196e4f5a11dSJames Kremer  */
197e4f5a11dSJames Kremer static int
do_mkdir(const char * path,mode_t mode)198e4f5a11dSJames Kremer do_mkdir(const char *path, mode_t mode)
199e4f5a11dSJames Kremer {
200e4f5a11dSJames Kremer 	struct stat st;
201e4f5a11dSJames Kremer 	int status = 0;
202e4f5a11dSJames Kremer 
203e4f5a11dSJames Kremer 	if (stat(path, &st) != 0) {
204e4f5a11dSJames Kremer 		/* Directory does not exist */
205e4f5a11dSJames Kremer 		if (mkdir(path, mode) != 0)
206e4f5a11dSJames Kremer 			status = -1;
207e4f5a11dSJames Kremer 	} else if (!S_ISDIR(st.st_mode)) {
208e4f5a11dSJames Kremer 		errno = ENOTDIR;
209e4f5a11dSJames Kremer 		status = -1;
210e4f5a11dSJames Kremer 	}
211e4f5a11dSJames Kremer 
212e4f5a11dSJames Kremer 	return (status);
213e4f5a11dSJames Kremer }
214e4f5a11dSJames Kremer 
215e4f5a11dSJames Kremer /*
216e4f5a11dSJames Kremer  * Validates that all directories in path exist
217e4f5a11dSJames Kremer  * path: The directory path to create.
218e4f5a11dSJames Kremer  * mode: The mode used when creating the directory.
219e4f5a11dSJames Kremer  */
220e4f5a11dSJames Kremer static int
mkpath(char * path,mode_t mode)221e4f5a11dSJames Kremer mkpath(char *path, mode_t mode)
222e4f5a11dSJames Kremer {
223e4f5a11dSJames Kremer 	char *pp;
224e4f5a11dSJames Kremer 	char *sp;
225e4f5a11dSJames Kremer 	int status = 0;
226e4f5a11dSJames Kremer 
227e4f5a11dSJames Kremer 	pp = path;
228e4f5a11dSJames Kremer 	while (status == 0 && (sp = strchr(pp, '/')) != 0) {
229e4f5a11dSJames Kremer 		if (sp != pp) {
230e4f5a11dSJames Kremer 			/* Neither root nor double slash in path */
231e4f5a11dSJames Kremer 			*sp = '\0';
232e4f5a11dSJames Kremer 			status = do_mkdir(path, mode);
233e4f5a11dSJames Kremer 			*sp = '/';
234e4f5a11dSJames Kremer 		}
235e4f5a11dSJames Kremer 		pp = sp + 1;
236e4f5a11dSJames Kremer 	}
237e4f5a11dSJames Kremer 
238e4f5a11dSJames Kremer 	return (status);
239e4f5a11dSJames Kremer }
240e4f5a11dSJames Kremer 
241e4f5a11dSJames Kremer /*
242e4f5a11dSJames Kremer  * Rotate the file from base.max-1->base.max, ... base.1->base.2, base->base.1
243e4f5a11dSJames Kremer  * Parameter:
244e4f5a11dSJames Kremer  * file: The name of the current log file.
245e4f5a11dSJames Kremer  */
246e4f5a11dSJames Kremer void
check_file_size(ses_log_monitor_t * slmp,char * file,int byte_count)247e4f5a11dSJames Kremer check_file_size(ses_log_monitor_t *slmp, char *file, int byte_count)
248e4f5a11dSJames Kremer {
249e4f5a11dSJames Kremer 	int i;
250e4f5a11dSJames Kremer 	char newFile[MAXPATHLEN];
251e4f5a11dSJames Kremer 	char oldName[MAXPATHLEN];
252e4f5a11dSJames Kremer 	struct stat st;
253e4f5a11dSJames Kremer 	int size;
254e4f5a11dSJames Kremer 
255e4f5a11dSJames Kremer 	stat(file, &st);
256e4f5a11dSJames Kremer 	size = st.st_size;
257e4f5a11dSJames Kremer 	/*
258e4f5a11dSJames Kremer 	 * If current file size plus what will be added is larger
259e4f5a11dSJames Kremer 	 * than max file size, rotate the logs
260e4f5a11dSJames Kremer 	 * For check to see if larger than configured max size.
261e4f5a11dSJames Kremer 	 */
262e4f5a11dSJames Kremer 	if (size + byte_count < slmp->slt_max_log_size) {
263e4f5a11dSJames Kremer 		/* next log entries can fit */
264e4f5a11dSJames Kremer 		return;
265e4f5a11dSJames Kremer 	}
266e4f5a11dSJames Kremer 	/* next log entries could make log entries too large */
267e4f5a11dSJames Kremer 	for (i = slmp->slt_log_count; i > 1; i--) {
268e4f5a11dSJames Kremer 		(void) snprintf(newFile, MAXPATHLEN, "%s.%x", file, i);
269e4f5a11dSJames Kremer 		(void) snprintf(oldName, MAXPATHLEN, "%s.%x", file, i - 1);
270e4f5a11dSJames Kremer 		(void) rename(oldName, newFile);
271e4f5a11dSJames Kremer 	}
272e4f5a11dSJames Kremer 	/* Finally move base to base.1 */
273e4f5a11dSJames Kremer 	(void) rename(file, oldName);
274e4f5a11dSJames Kremer 
275e4f5a11dSJames Kremer }
276e4f5a11dSJames Kremer 
277e4f5a11dSJames Kremer /*
278e4f5a11dSJames Kremer  * This method exists to give access into the fmri.  One purpose is to flip the
279e4f5a11dSJames Kremer  * instance number on the FMRI for a given hc-list entry. It is also
280e4f5a11dSJames Kremer  * used to pull the value of an hc-list entry.  In all cases, the function
281e4f5a11dSJames Kremer  * returns the value of the hc-list entry found, NULL if no value was found.
282e4f5a11dSJames Kremer  */
283e4f5a11dSJames Kremer static char *
access_fmri(ses_log_monitor_t * slmp,nvlist_t * fmri,char * target,int operation,int * err)284e4f5a11dSJames Kremer access_fmri(ses_log_monitor_t *slmp, nvlist_t *fmri, char *target,
285e4f5a11dSJames Kremer     int operation, int *err)
286e4f5a11dSJames Kremer {
287e4f5a11dSJames Kremer 	int i;
288e4f5a11dSJames Kremer 	nvpair_t *nvp;
289e4f5a11dSJames Kremer 	nvpair_t *nvp2;
290e4f5a11dSJames Kremer 	uint_t nelem;
291e4f5a11dSJames Kremer 	nvlist_t **nvl_array;
292e4f5a11dSJames Kremer 	char *name;
293e4f5a11dSJames Kremer 	int ival;
294e4f5a11dSJames Kremer 	char ivs[25];
295e4f5a11dSJames Kremer 	char *target_val = NULL;
296e4f5a11dSJames Kremer 
297e4f5a11dSJames Kremer 	if ((*err = nvlist_lookup_nvpair(fmri, "hc-list", &nvp)) != 0) {
298744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl, "No hc-list in the fmri");
299e4f5a11dSJames Kremer 		return (NULL);
300e4f5a11dSJames Kremer 	}
301e4f5a11dSJames Kremer 
302e4f5a11dSJames Kremer 	/* hc-list is an array of nvlists */
303e4f5a11dSJames Kremer 	(void) nvpair_value_nvlist_array(nvp, &nvl_array, &nelem);
304e4f5a11dSJames Kremer 
305e4f5a11dSJames Kremer 	/*
306e4f5a11dSJames Kremer 	 * Loop until you find the list that has hc-name that equals the
307e4f5a11dSJames Kremer 	 * passed in "target" value (such as controller) in it.
308e4f5a11dSJames Kremer 	 */
309e4f5a11dSJames Kremer 	for (i = 0; i < nelem; i++) {
310e4f5a11dSJames Kremer 
311e4f5a11dSJames Kremer 		/* Skip this pair if it is not labeled hc-name */
312e4f5a11dSJames Kremer 		if ((nvlist_lookup_nvpair(nvl_array[i], "hc-name", &nvp2))
313e4f5a11dSJames Kremer 		    != 0) {
314e4f5a11dSJames Kremer 			continue;
315e4f5a11dSJames Kremer 		}
316e4f5a11dSJames Kremer 
317e4f5a11dSJames Kremer 		/*
318e4f5a11dSJames Kremer 		 * Extract the value of the name. Continue on an error because
319e4f5a11dSJames Kremer 		 * we want to check all of the hc-name entries.
320e4f5a11dSJames Kremer 		 */
321e4f5a11dSJames Kremer 		if (nvpair_value_string(nvp2, &name) != 0) {
322e4f5a11dSJames Kremer 			continue;
323e4f5a11dSJames Kremer 		}
324e4f5a11dSJames Kremer 
325e4f5a11dSJames Kremer 		/* If this isn't the target, go to the next pair. */
326e4f5a11dSJames Kremer 		if (strcmp(name, target) != 0) {
327e4f5a11dSJames Kremer 			continue;
328e4f5a11dSJames Kremer 		}
329e4f5a11dSJames Kremer 
330e4f5a11dSJames Kremer 		if ((*err = nvlist_lookup_nvpair(nvl_array[i], "hc-id", &nvp2))
331e4f5a11dSJames Kremer 		    != 0) {
332e4f5a11dSJames Kremer 
333744e50acSStephen Brooks 			fmd_hdl_debug(slmp->slt_hdl,
334e4f5a11dSJames Kremer 			    "Could not find hc-id in the fmri for %s", target);
335e4f5a11dSJames Kremer 			return (NULL);
336e4f5a11dSJames Kremer 		}
337e4f5a11dSJames Kremer 
338e4f5a11dSJames Kremer 		/*
339e4f5a11dSJames Kremer 		 * This is the target pair.  If we can't get the value then
340e4f5a11dSJames Kremer 		 * exit out and log an error.
341e4f5a11dSJames Kremer 		 */
342e4f5a11dSJames Kremer 		if ((*err = nvpair_value_string(nvp2, &target_val)) != 0) {
343744e50acSStephen Brooks 			fmd_hdl_debug(slmp->slt_hdl,
344e4f5a11dSJames Kremer 			    "Target value not returned.");
345e4f5a11dSJames Kremer 			return (NULL);
346e4f5a11dSJames Kremer 		}
347e4f5a11dSJames Kremer 
348e4f5a11dSJames Kremer 		switch (operation) {
349e4f5a11dSJames Kremer 
350*7656b922SStephen Brooks 		case INVERT_FMRI_INSTANCE:
351e4f5a11dSJames Kremer 
352e4f5a11dSJames Kremer 			ival = atoi(target_val);
353e4f5a11dSJames Kremer 			ival = (ival + 1) % 2;
354e4f5a11dSJames Kremer 
355e4f5a11dSJames Kremer 			(void) snprintf(ivs, sizeof (ivs), "%d", ival);
356e4f5a11dSJames Kremer 
357e4f5a11dSJames Kremer 			if ((*err = nvlist_remove_nvpair(nvl_array[i], nvp2))
358e4f5a11dSJames Kremer 			    == 0) {
359e4f5a11dSJames Kremer 
360e4f5a11dSJames Kremer 				if ((*err = nvlist_add_string(nvl_array[i],
361e4f5a11dSJames Kremer 				    "hc-id", ivs)) != 0) {
362e4f5a11dSJames Kremer 
363744e50acSStephen Brooks 					fmd_hdl_debug(slmp->slt_hdl,
364e4f5a11dSJames Kremer 					    "Error setting ivalue.");
365e4f5a11dSJames Kremer 				}
366e4f5a11dSJames Kremer 			} else {
367744e50acSStephen Brooks 				fmd_hdl_debug(slmp->slt_hdl,
368e4f5a11dSJames Kremer 				    "Error removing original ivalue.");
369e4f5a11dSJames Kremer 			}
370e4f5a11dSJames Kremer 
371e4f5a11dSJames Kremer 			break;
372e4f5a11dSJames Kremer 
373*7656b922SStephen Brooks 		case EXAMINE_FMRI_VALUE:
374e4f5a11dSJames Kremer 			/*
375e4f5a11dSJames Kremer 			 * target_val is already set. Return without modifying
376e4f5a11dSJames Kremer 			 * its value.
377e4f5a11dSJames Kremer 			 */
378e4f5a11dSJames Kremer 			break;
379e4f5a11dSJames Kremer 
380e4f5a11dSJames Kremer 		/* Can return target_val as is (NULL) */
381*7656b922SStephen Brooks 		default:
382e4f5a11dSJames Kremer 			*err = INVALID_OPERATION;
383e4f5a11dSJames Kremer 			break;
384e4f5a11dSJames Kremer 
385e4f5a11dSJames Kremer 		} /* End switch on operation */
386e4f5a11dSJames Kremer 
387e4f5a11dSJames Kremer 
388e4f5a11dSJames Kremer 		/* Exit the loop.  You have found the target */
389e4f5a11dSJames Kremer 		break;
390e4f5a11dSJames Kremer 	}
391e4f5a11dSJames Kremer 
392e4f5a11dSJames Kremer 	return (target_val);
393e4f5a11dSJames Kremer }
394e4f5a11dSJames Kremer 
395e4f5a11dSJames Kremer /*
396e4f5a11dSJames Kremer  * Generate a filename based on the target path
397e4f5a11dSJames Kremer  * Parameters:
398e4f5a11dSJames Kremer  * filename: The space for the generated output log file name.
399e4f5a11dSJames Kremer  * expander: An expander_t struct containing path, pid etc info from the node.
400e4f5a11dSJames Kremer  * slmp: A pointer to the transport data structure which contains the
401e4f5a11dSJames Kremer  * configurable file parameters.
4027a087849SStephen Brooks  * byte_count: The number of bytes that will be added to the target file for
4037a087849SStephen Brooks  * this expander.
404e4f5a11dSJames Kremer  */
405e4f5a11dSJames Kremer static int
create_filename(char * fileName,expander_t * expander,ses_log_monitor_t * slmp,int byte_count)406e4f5a11dSJames Kremer create_filename(char *fileName, expander_t *expander, ses_log_monitor_t *slmp,
407e4f5a11dSJames Kremer     int byte_count)
408e4f5a11dSJames Kremer {
409e4f5a11dSJames Kremer 	char *ses_node;
410e4f5a11dSJames Kremer 	int i;
411e4f5a11dSJames Kremer 	int label_length;
412e4f5a11dSJames Kremer 	int status = 0;
413e4f5a11dSJames Kremer 	char *subchassis_val = NULL;
414e4f5a11dSJames Kremer 
415e4f5a11dSJames Kremer 	/*
416e4f5a11dSJames Kremer 	 * Add the file name with the path root
417e4f5a11dSJames Kremer 	 * and append a forward slash if one is not there.
418e4f5a11dSJames Kremer 	 */
419e4f5a11dSJames Kremer 	(void) snprintf(fileName, MAXPATHLEN, "%s", slmp->slt_path);
420e4f5a11dSJames Kremer 
421e4f5a11dSJames Kremer 	ses_node = strrchr(fileName, '/');
422e4f5a11dSJames Kremer 
423744e50acSStephen Brooks 	if ((ses_node != NULL) && (ses_node[0] != '\0')) {
4247a087849SStephen Brooks 		(void) strlcat(fileName, "/", MAXPATHLEN);
425e4f5a11dSJames Kremer 	}
426e4f5a11dSJames Kremer 
427e4f5a11dSJames Kremer 	ses_node = strrchr(expander->slt_path, '/');
428e4f5a11dSJames Kremer 
429e4f5a11dSJames Kremer 	(void) strlcat(fileName, ses_node + 1, MAXPATHLEN);
430e4f5a11dSJames Kremer 
431e4f5a11dSJames Kremer 	/*
432e4f5a11dSJames Kremer 	 * If a subchassis is defined, include it in the file name.
433e4f5a11dSJames Kremer 	 * Errors are logged in the function.  There may legitimately be no
434e4f5a11dSJames Kremer 	 * subchassis, so simply continue if none is found.
435e4f5a11dSJames Kremer 	 */
436e4f5a11dSJames Kremer 	subchassis_val =  access_fmri(slmp, expander->fmri, SUBCHASSIS,
437e4f5a11dSJames Kremer 	    EXAMINE_FMRI_VALUE, &status);
438e4f5a11dSJames Kremer 
439e4f5a11dSJames Kremer 	if (subchassis_val != NULL) {
440e4f5a11dSJames Kremer 		(void) strlcat(fileName, "_", MAXPATHLEN);
441e4f5a11dSJames Kremer 		(void) strlcat(fileName, SUBCHASSIS, MAXPATHLEN);
442e4f5a11dSJames Kremer 		(void) strlcat(fileName, subchassis_val, MAXPATHLEN);
443e4f5a11dSJames Kremer 	}
444e4f5a11dSJames Kremer 
445e4f5a11dSJames Kremer 	(void) strlcat(fileName, "_", MAXPATHLEN);
446e4f5a11dSJames Kremer 	/* remove spaces and forward slashes from name */
447e4f5a11dSJames Kremer 	label_length = strlen(expander->slt_label);
448e4f5a11dSJames Kremer 	for (i = 0; i < label_length; i++) {
449e4f5a11dSJames Kremer 		if ((!isspace(expander->slt_label[i])) &&
450e4f5a11dSJames Kremer 		    ('/' != expander->slt_label[i])) {
451e4f5a11dSJames Kremer 			(void) strncat(fileName, &expander->slt_label[i], 1);
452e4f5a11dSJames Kremer 		}
453e4f5a11dSJames Kremer 	}
454e4f5a11dSJames Kremer 	(void) strlcat(fileName, "/log", MAXPATHLEN);
455e4f5a11dSJames Kremer 
456e4f5a11dSJames Kremer 	/*
457e4f5a11dSJames Kremer 	 * Ensure directory structure exists for log file.
458e4f5a11dSJames Kremer 	 */
459e4f5a11dSJames Kremer 	status = mkpath(fileName, 0744);
460e4f5a11dSJames Kremer 
461e4f5a11dSJames Kremer 	/*
462e4f5a11dSJames Kremer 	 * Check size of file and rotate if necessary.
463e4f5a11dSJames Kremer 	 */
464e4f5a11dSJames Kremer 	check_file_size(slmp, fileName, byte_count);
465e4f5a11dSJames Kremer 
466e4f5a11dSJames Kremer 	return (status);
467e4f5a11dSJames Kremer 
468e4f5a11dSJames Kremer }
469e4f5a11dSJames Kremer 
470e4f5a11dSJames Kremer /*
471e4f5a11dSJames Kremer  * Determines the error class type based on the severity of the entry.
472e4f5a11dSJames Kremer  * Parameter
473e4f5a11dSJames Kremer  * severity: A severity level from a log entry.
474e4f5a11dSJames Kremer  */
475e4f5a11dSJames Kremer static char *
error_type(int severity)476e4f5a11dSJames Kremer error_type(int severity)
477e4f5a11dSJames Kremer {
478e4f5a11dSJames Kremer 	char *rval;
479e4f5a11dSJames Kremer 
480e4f5a11dSJames Kremer 	switch (severity) {
481*7656b922SStephen Brooks 	case SES_LOG_LEVEL_FATAL:
4827a087849SStephen Brooks 		rval = FATAL_ERROR;
4837a087849SStephen Brooks 		break;
484e4f5a11dSJames Kremer 
485*7656b922SStephen Brooks 	case SES_LOG_LEVEL_ERROR:
4867a087849SStephen Brooks 		rval = NON_FATAL_ERROR;
4877a087849SStephen Brooks 		break;
488e4f5a11dSJames Kremer 
489*7656b922SStephen Brooks 	default:
4907a087849SStephen Brooks 		rval = NULL;
4917a087849SStephen Brooks 		break;
492e4f5a11dSJames Kremer 	}
493e4f5a11dSJames Kremer 
494e4f5a11dSJames Kremer 	return (rval);
495e4f5a11dSJames Kremer }
496e4f5a11dSJames Kremer 
497e4f5a11dSJames Kremer /*
498e4f5a11dSJames Kremer  * Allocates and adds an entry for a given expander to the expander list.
499e4f5a11dSJames Kremer  * Parameters
500e4f5a11dSJames Kremer  * slmp: A pointer to the ses_log_monitor_t struct for this transport.
501e4f5a11dSJames Kremer  * key: A unique identifier for this expander.
502e4f5a11dSJames Kremer  */
503e4f5a11dSJames Kremer static int
add_expander_record(ses_log_monitor_t * slmp,char * key)504e4f5a11dSJames Kremer add_expander_record(ses_log_monitor_t *slmp, char *key)
505e4f5a11dSJames Kremer {
506e4f5a11dSJames Kremer 	nvlist_t *expanderDetails;
507e4f5a11dSJames Kremer 	int status = 0;
508e4f5a11dSJames Kremer 
509e4f5a11dSJames Kremer 
510e4f5a11dSJames Kremer 	if ((status = nvlist_alloc(&expanderDetails, NV_UNIQUE_NAME, 0)) != 0) {
511744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
512e4f5a11dSJames Kremer 		    "Error allocating expander detail space (%d)", status);
513e4f5a11dSJames Kremer 		return (status);
514e4f5a11dSJames Kremer 	}
515e4f5a11dSJames Kremer 
516e4f5a11dSJames Kremer 	if ((status = nvlist_add_string(expanderDetails, DATA_FIELD,
517e4f5a11dSJames Kremer 	    DEFAULT_DATA)) != 0) {
518e4f5a11dSJames Kremer 
519744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
520e4f5a11dSJames Kremer 		    "Error adding default data to expander details (%d)",
521e4f5a11dSJames Kremer 		    status);
522e4f5a11dSJames Kremer 	} else {
523e4f5a11dSJames Kremer 
524e4f5a11dSJames Kremer 		if ((status = nvlist_add_nvlist(slmp->slt_expanders, key,
525e4f5a11dSJames Kremer 		    expanderDetails)) != 0) {
526e4f5a11dSJames Kremer 
527744e50acSStephen Brooks 			fmd_hdl_debug(slmp->slt_hdl,
528e4f5a11dSJames Kremer 			    "Error storing the default expander details (%d)",
529e4f5a11dSJames Kremer 			    status);
530e4f5a11dSJames Kremer 		}
531e4f5a11dSJames Kremer 	}
532e4f5a11dSJames Kremer 
533e4f5a11dSJames Kremer 	nvlist_free(expanderDetails);
534e4f5a11dSJames Kremer 
535e4f5a11dSJames Kremer 	return (status);
536e4f5a11dSJames Kremer 
537e4f5a11dSJames Kremer }
538e4f5a11dSJames Kremer 
539e4f5a11dSJames Kremer /*
540e4f5a11dSJames Kremer  * Retrieves the expander record nvlist that is associated with the
541e4f5a11dSJames Kremer  * expander identified by the given key.  If no match is found, an
542e4f5a11dSJames Kremer  * entry is created with default values.
543e4f5a11dSJames Kremer  * Parameters
544e4f5a11dSJames Kremer  * slmp: A pointer to the ses_log_monitor_t struct for this transport.
545e4f5a11dSJames Kremer  * key: A pointer to the key for an expander.
546e4f5a11dSJames Kremer  * expdata: A pointer to a pointer for the last log entry data for this
547e4f5a11dSJames Kremer  * expander.
548e4f5a11dSJames Kremer  */
549e4f5a11dSJames Kremer static int
get_last_entry(ses_log_monitor_t * slmp,char * key,char ** expdata)550e4f5a11dSJames Kremer get_last_entry(ses_log_monitor_t *slmp, char *key, char **expdata)
551e4f5a11dSJames Kremer {
552e4f5a11dSJames Kremer 	nvlist_t *expanderRecord;
553e4f5a11dSJames Kremer 	int err = 0;
554e4f5a11dSJames Kremer 
555e4f5a11dSJames Kremer 	/*
556e4f5a11dSJames Kremer 	 * Retrieve the expander record that matches this expander.  A default
557e4f5a11dSJames Kremer 	 * entry will be returned if no matching entry is found.
558e4f5a11dSJames Kremer 	 */
559e4f5a11dSJames Kremer 	if ((err = nvlist_lookup_nvlist(slmp->slt_expanders, key,
560e4f5a11dSJames Kremer 	    &expanderRecord)) != 0) {
561e4f5a11dSJames Kremer 
562e4f5a11dSJames Kremer 		if ((err = add_expander_record(slmp, key)) != 0) {
563e4f5a11dSJames Kremer 			fmd_hdl_debug(slmp->slt_hdl,
564e4f5a11dSJames Kremer 			    "Expander add failed for %s", key);
565e4f5a11dSJames Kremer 			return (err);
566e4f5a11dSJames Kremer 		}
567e4f5a11dSJames Kremer 
568e4f5a11dSJames Kremer 		if ((err = nvlist_lookup_nvlist(slmp->slt_expanders, key,
569e4f5a11dSJames Kremer 		    &expanderRecord)) != 0) {
570e4f5a11dSJames Kremer 
571e4f5a11dSJames Kremer 			fmd_hdl_debug(slmp->slt_hdl,
572e4f5a11dSJames Kremer 			    "Could not retrieve the data after adding it", key);
573e4f5a11dSJames Kremer 			return (err);
574e4f5a11dSJames Kremer 		}
575e4f5a11dSJames Kremer 	}
576e4f5a11dSJames Kremer 
577e4f5a11dSJames Kremer 
578e4f5a11dSJames Kremer 	if ((err = nvlist_lookup_string(expanderRecord, DATA_FIELD, expdata))
579e4f5a11dSJames Kremer 	    != 0) {
580e4f5a11dSJames Kremer 
581e4f5a11dSJames Kremer 		fmd_hdl_debug(slmp->slt_hdl,
582e4f5a11dSJames Kremer 		    "Could not retrieve the expander data field (%d)", err);
583e4f5a11dSJames Kremer 		return (err);
584e4f5a11dSJames Kremer 	}
585e4f5a11dSJames Kremer 
586e4f5a11dSJames Kremer 	return (err);
587e4f5a11dSJames Kremer }
588e4f5a11dSJames Kremer 
589e4f5a11dSJames Kremer /*
590e4f5a11dSJames Kremer  * Searches the platform lists for target codes.  If a match is found then
591e4f5a11dSJames Kremer  * it calls then indicated function.
592e4f5a11dSJames Kremer  */
593e4f5a11dSJames Kremer static int
check_code(ses_log_monitor_t * slmp,nvlist_t * fmri,char * pid,int code)594e4f5a11dSJames Kremer check_code(ses_log_monitor_t *slmp, nvlist_t *fmri, char *pid, int code)
595e4f5a11dSJames Kremer {
596e4f5a11dSJames Kremer 	int status = 0;
597e4f5a11dSJames Kremer 	int i, x;
598e4f5a11dSJames Kremer 
599e4f5a11dSJames Kremer 	for (i = 0; i < platforms.pcount; i++) {
600e4f5a11dSJames Kremer 		if (strcmp(platforms.plist[i].pid, pid) == 0) {
601e4f5a11dSJames Kremer 
602e4f5a11dSJames Kremer 			for (x = 0; x < platforms.plist[i].count; x++) {
603e4f5a11dSJames Kremer 				if (code == platforms.plist[i].codes[x].code) {
604e4f5a11dSJames Kremer 					status = platforms.plist[i].codes[x].
605e4f5a11dSJames Kremer 					    func_ptr(slmp, fmri);
606e4f5a11dSJames Kremer 
607e4f5a11dSJames Kremer 					break;
608e4f5a11dSJames Kremer 				}
609e4f5a11dSJames Kremer 			}
610e4f5a11dSJames Kremer 			break;
611e4f5a11dSJames Kremer 		}
612e4f5a11dSJames Kremer 	}
613e4f5a11dSJames Kremer 
614e4f5a11dSJames Kremer 	if (status != 0) {
615e4f5a11dSJames Kremer 		fmd_hdl_debug(slmp->slt_hdl,
616e4f5a11dSJames Kremer 		    "Error checking for a code action (%d)", status);
617e4f5a11dSJames Kremer 	}
618e4f5a11dSJames Kremer 
619e4f5a11dSJames Kremer 	return (status);
620e4f5a11dSJames Kremer }
621e4f5a11dSJames Kremer 
6227a087849SStephen Brooks /*
6237a087849SStephen Brooks  * Searches the platform lists for for a match on the supplied product id.
624744e50acSStephen Brooks  * Returns non zero if supported, zero otherwise.
6257a087849SStephen Brooks  */
6267a087849SStephen Brooks static int
platform_supported(char * pid)6277a087849SStephen Brooks platform_supported(char *pid)
6287a087849SStephen Brooks {
629744e50acSStephen Brooks 	int supported = 0;
6307a087849SStephen Brooks 	int i;
6317a087849SStephen Brooks 
6327a087849SStephen Brooks 	for (i = 0; i < platforms.pcount; i++) {
6337a087849SStephen Brooks 		if (strcmp(platforms.plist[i].pid, pid) == 0) {
634744e50acSStephen Brooks 			supported = 1;
6357a087849SStephen Brooks 			break;
6367a087849SStephen Brooks 		}
6377a087849SStephen Brooks 	}
6387a087849SStephen Brooks 
6397a087849SStephen Brooks 	return (supported);
6407a087849SStephen Brooks }
6417a087849SStephen Brooks 
642e4f5a11dSJames Kremer /*
643*7656b922SStephen Brooks  * Inverts the controller instance and the expander instance in the
644*7656b922SStephen Brooks  * specified FMRI.
645e4f5a11dSJames Kremer  */
646e4f5a11dSJames Kremer static int
invert_fmri(ses_log_monitor_t * slmp,nvlist_t * fmri)647e4f5a11dSJames Kremer invert_fmri(ses_log_monitor_t *slmp, nvlist_t *fmri)
648e4f5a11dSJames Kremer {
649e4f5a11dSJames Kremer 	int err = 0;
650e4f5a11dSJames Kremer 
651e4f5a11dSJames Kremer 	(void) access_fmri(slmp, fmri, CONTROLLER, INVERT_FMRI_INSTANCE, &err);
652*7656b922SStephen Brooks 	if (err != 0) {
653*7656b922SStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
654*7656b922SStephen Brooks 		    "error inverting the controller instance: %d", err);
655*7656b922SStephen Brooks 		return (err);
656*7656b922SStephen Brooks 	}
657e4f5a11dSJames Kremer 
658*7656b922SStephen Brooks 	(void) access_fmri(slmp, fmri, SASEXPANDER, INVERT_FMRI_INSTANCE, &err);
659e4f5a11dSJames Kremer 	if (err != 0) {
660e4f5a11dSJames Kremer 		fmd_hdl_debug(slmp->slt_hdl,
661*7656b922SStephen Brooks 		    "error inverting sas-expander instance: %d", err);
662e4f5a11dSJames Kremer 	}
663e4f5a11dSJames Kremer 
664e4f5a11dSJames Kremer 	return (err);
665e4f5a11dSJames Kremer }
666e4f5a11dSJames Kremer 
667e4f5a11dSJames Kremer /*
668e4f5a11dSJames Kremer  * Checks the severity of the log entry against the configured boundary,
669e4f5a11dSJames Kremer  * generates and ereport, and writes the data out to the log file.
670e4f5a11dSJames Kremer  * Parameters
671e4f5a11dSJames Kremer  * slmp: A pointer to the ses_log_monitor_t struct for this transport.
672e4f5a11dSJames Kremer  * entry: The log entry
673e4f5a11dSJames Kremer  * ena: the ena for this transport.
674e4f5a11dSJames Kremer  * expander: Contains derived information for this expander.
675e4f5a11dSJames Kremer  * format_time: The formatted time to append to this entry.
676e4f5a11dSJames Kremer  * fp: A file pointer for the data to be written out to.
677e4f5a11dSJames Kremer  */
678e4f5a11dSJames Kremer static int
handle_log_entry(ses_log_monitor_t * slmp,nvpair_t * entry,expander_t * expander,char * format_time,FILE * fp)679e4f5a11dSJames Kremer handle_log_entry(ses_log_monitor_t *slmp, nvpair_t *entry,
680e4f5a11dSJames Kremer     expander_t *expander, char *format_time, FILE *fp)
681e4f5a11dSJames Kremer {
682e4f5a11dSJames Kremer 	nvlist_t *entry_data;
683e4f5a11dSJames Kremer 	char *log_entry;
684e4f5a11dSJames Kremer 	char *severity;
685e4f5a11dSJames Kremer 	int severityValue = 0;
686e4f5a11dSJames Kremer 	char *code;
687e4f5a11dSJames Kremer 	char *class_sev = NULL;
688e4f5a11dSJames Kremer 	uint64_t ena;
689e4f5a11dSJames Kremer 	int rval = 0;
690e4f5a11dSJames Kremer 
691e4f5a11dSJames Kremer 	if ((rval = nvpair_value_nvlist(entry, &entry_data)) != 0) {
692e4f5a11dSJames Kremer 		fmd_hdl_debug(slmp->slt_hdl, "Unable to retrieve entry");
693e4f5a11dSJames Kremer 		return (rval);
694e4f5a11dSJames Kremer 	}
695e4f5a11dSJames Kremer 
696e4f5a11dSJames Kremer 	if ((rval = nvlist_lookup_string(entry_data, ENTRY_SEVERITY, &severity))
697e4f5a11dSJames Kremer 	    == 0) {
698e4f5a11dSJames Kremer 
699e4f5a11dSJames Kremer 		severityValue = atoi(severity);
700e4f5a11dSJames Kremer 
701e4f5a11dSJames Kremer 		if (severityValue >= slmp->slt_severity) {
702e4f5a11dSJames Kremer 			/*
703e4f5a11dSJames Kremer 			 * Pull the code and check to see if there are any
704e4f5a11dSJames Kremer 			 * special operations to perform for it on the given
705e4f5a11dSJames Kremer 			 * platform.
706e4f5a11dSJames Kremer 			 */
707*7656b922SStephen Brooks 			if ((rval = nvlist_lookup_string(entry_data, ENTRY_CODE,
708*7656b922SStephen Brooks 			    &code)) != 0) {
709*7656b922SStephen Brooks 
710*7656b922SStephen Brooks 				fmd_hdl_debug(slmp->slt_hdl,
711*7656b922SStephen Brooks 				    "Error retrieving code: %d", rval);
712*7656b922SStephen Brooks 				return (rval);
713e4f5a11dSJames Kremer 			}
714e4f5a11dSJames Kremer 
715*7656b922SStephen Brooks 			/*
716*7656b922SStephen Brooks 			 * Check this code for any actions specific
717*7656b922SStephen Brooks 			 * to this platform.
718*7656b922SStephen Brooks 			 */
719*7656b922SStephen Brooks 			(void) check_code(slmp, expander->fmri,
720*7656b922SStephen Brooks 			    expander->slt_pid, atoi(code));
721*7656b922SStephen Brooks 
722e4f5a11dSJames Kremer 			class_sev = error_type(severityValue);
723e4f5a11dSJames Kremer 			if (class_sev == NULL) {
724e4f5a11dSJames Kremer 				fmd_hdl_debug(slmp->slt_hdl,
725e4f5a11dSJames Kremer 				    "log severity %d mapped to NULL", severity);
726*7656b922SStephen Brooks 				return (INVALID_SEVERITY);
727e4f5a11dSJames Kremer 			}
728e4f5a11dSJames Kremer 
7297a087849SStephen Brooks 			/* Create the ENA for this ereport */
730e4f5a11dSJames Kremer 			ena = fmd_event_ena_create(slmp->slt_hdl);
731e4f5a11dSJames Kremer 
732e4f5a11dSJames Kremer 			slt_post_ereport(slmp->slt_hdl, slmp->slt_xprt,
733e4f5a11dSJames Kremer 			    class_sev, ena, expander->fmri, entry_data);
734e4f5a11dSJames Kremer 
735e4f5a11dSJames Kremer 		}
736e4f5a11dSJames Kremer 	} else {
737e4f5a11dSJames Kremer 
738744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
739e4f5a11dSJames Kremer 		    "Unable to pull severity from the entry.");
740e4f5a11dSJames Kremer 		return (rval);
741e4f5a11dSJames Kremer 	}
742e4f5a11dSJames Kremer 
743e4f5a11dSJames Kremer 	/*
744e4f5a11dSJames Kremer 	 * Append the log entry to the log file.
745e4f5a11dSJames Kremer 	 */
746e4f5a11dSJames Kremer 	if (fp) {
747e4f5a11dSJames Kremer 
748e4f5a11dSJames Kremer 		if ((rval = nvlist_lookup_string(entry_data, ENTRY_LOG,
749e4f5a11dSJames Kremer 		    &log_entry)) == 0) {
750e4f5a11dSJames Kremer 
751e4f5a11dSJames Kremer 			(void) fprintf(fp, "%s %s\n", format_time,
752e4f5a11dSJames Kremer 			    log_entry);
753e4f5a11dSJames Kremer 		} else {
754e4f5a11dSJames Kremer 
755744e50acSStephen Brooks 			fmd_hdl_debug(slmp->slt_hdl,
756e4f5a11dSJames Kremer 			    "Unable to pull log from the entry.");
757e4f5a11dSJames Kremer 		}
758e4f5a11dSJames Kremer 	}
759e4f5a11dSJames Kremer 
760e4f5a11dSJames Kremer 	return (rval);
761e4f5a11dSJames Kremer 
762e4f5a11dSJames Kremer }
763e4f5a11dSJames Kremer 
764e4f5a11dSJames Kremer /*
765e4f5a11dSJames Kremer  * The function performs the work of deallocating the space used for an
766e4f5a11dSJames Kremer  * expander_t structure.
767e4f5a11dSJames Kremer  * Parameters:
768e4f5a11dSJames Kremer  * slmp: A pointer to t ses_log_monitor_t struct for this transport.
769e4f5a11dSJames Kremer  * exp: A pointer to an expander_t structure that identifies an expander.
770e4f5a11dSJames Kremer  */
771e4f5a11dSJames Kremer static void
free_expander(ses_log_monitor_t * slmp,expander_t * exp)772e4f5a11dSJames Kremer free_expander(ses_log_monitor_t *slmp, expander_t *exp)
773e4f5a11dSJames Kremer {
774e4f5a11dSJames Kremer 	if (exp != NULL) {
775e4f5a11dSJames Kremer 		if (exp->fmri != NULL) {
776e4f5a11dSJames Kremer 			nvlist_free(exp->fmri);
777e4f5a11dSJames Kremer 		}
778e4f5a11dSJames Kremer 		fmd_hdl_free(slmp->slt_hdl, exp, sizeof (expander_t));
779e4f5a11dSJames Kremer 	}
780e4f5a11dSJames Kremer }
781e4f5a11dSJames Kremer 
782e4f5a11dSJames Kremer /*
783e4f5a11dSJames Kremer  * This function performs the log read on a target
784e4f5a11dSJames Kremer  *
785e4f5a11dSJames Kremer  * Parameters:
786e4f5a11dSJames Kremer  * slmp: A pointer to the ses log monitor structure.
787e4f5a11dSJames Kremer  * expander: A pointer to an expander object that contains info required
788e4f5a11dSJames Kremer  * for a call to the libseslog library.
789e4f5a11dSJames Kremer  * lib_param: The structure used to pass data to and from the library.  This
790e4f5a11dSJames Kremer  * contains the target's information as well as a ponter to returned data.
791e4f5a11dSJames Kremer  */
792e4f5a11dSJames Kremer static int
get_log(ses_log_monitor_t * slmp,expander_t * expander,struct ses_log_call_struct * lib_param)793e4f5a11dSJames Kremer get_log(ses_log_monitor_t *slmp, expander_t *expander,
794e4f5a11dSJames Kremer     struct ses_log_call_struct *lib_param)
795e4f5a11dSJames Kremer {
796e4f5a11dSJames Kremer 	char *expdata;
797e4f5a11dSJames Kremer 	int err;
798e4f5a11dSJames Kremer 	nvlist_t *expanderRecord;
799e4f5a11dSJames Kremer 
800e4f5a11dSJames Kremer 	/* Retrieve the last entry for this expander for the lib call */
801e4f5a11dSJames Kremer 	if ((err = get_last_entry(slmp, expander->slt_key, &expdata)) != 0) {
802e4f5a11dSJames Kremer 
803744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl, "Error collecting expander entry");
804e4f5a11dSJames Kremer 		return (err);
805e4f5a11dSJames Kremer 	}
806e4f5a11dSJames Kremer 	(void) strncpy(lib_param->target_path, expander->slt_path, MAXPATHLEN);
807e4f5a11dSJames Kremer 	(void) strncpy(lib_param->product_id, expander->slt_pid, MAXNAMELEN);
808e4f5a11dSJames Kremer 	(void) strncpy(lib_param->last_log_entry, expdata, MAXNAMELEN);
809e4f5a11dSJames Kremer 	lib_param->poll_time = slmp->slt_interval;
810e4f5a11dSJames Kremer 
811e4f5a11dSJames Kremer 	/*
812e4f5a11dSJames Kremer 	 * If the library call returned non zero, log it, however, the call
813e4f5a11dSJames Kremer 	 * may still have returned valid log data.  Check the log data.  If it
814e4f5a11dSJames Kremer 	 * is NULL, return an error.  Otherwise continue processing.
815e4f5a11dSJames Kremer 	 */
816e4f5a11dSJames Kremer 	if ((err = access_ses_log(lib_param)) != 0) {
817744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl, "Library access error: %d", err);
818e4f5a11dSJames Kremer 	}
819e4f5a11dSJames Kremer 
820e4f5a11dSJames Kremer 	/* Double check that log data actually exists. */
821e4f5a11dSJames Kremer 	if (lib_param->log_data == NULL) {
822744e50acSStephen Brooks 		if (err != 0) {
823744e50acSStephen Brooks 			return (err);
824744e50acSStephen Brooks 		}
825e4f5a11dSJames Kremer 		return (NULL_LOG_DATA);
826e4f5a11dSJames Kremer 	}
827e4f5a11dSJames Kremer 
828e4f5a11dSJames Kremer 	/*
829e4f5a11dSJames Kremer 	 * If we can retrieve the expander details for this expander then store
830e4f5a11dSJames Kremer 	 * the last log entry returned from the library.  Otherwise log it
831e4f5a11dSJames Kremer 	 * and continue processing.
832e4f5a11dSJames Kremer 	 */
833e4f5a11dSJames Kremer 	if ((err = nvlist_lookup_nvlist(slmp->slt_expanders, expander->slt_key,
834e4f5a11dSJames Kremer 	    &expanderRecord)) == 0) {
835e4f5a11dSJames Kremer 
836e4f5a11dSJames Kremer 		if (nvlist_add_string(expanderRecord, DATA_FIELD,
837e4f5a11dSJames Kremer 		    lib_param->last_log_entry) != 0) {
838e4f5a11dSJames Kremer 
839e4f5a11dSJames Kremer 			fmd_hdl_debug(slmp->slt_hdl,
840e4f5a11dSJames Kremer 			    "Error saving buffer data in expander details");
841e4f5a11dSJames Kremer 		}
842e4f5a11dSJames Kremer 	} else {
843e4f5a11dSJames Kremer 		fmd_hdl_debug(slmp->slt_hdl,
844e4f5a11dSJames Kremer 		    "Could not retrieve expander to store last entry: %d", err);
845e4f5a11dSJames Kremer 	}
846e4f5a11dSJames Kremer 
847e4f5a11dSJames Kremer 	return (err);
848e4f5a11dSJames Kremer 
849e4f5a11dSJames Kremer }
850e4f5a11dSJames Kremer 
851e4f5a11dSJames Kremer /*
852e4f5a11dSJames Kremer  * This function processes the log data from a target.  This includes
853e4f5a11dSJames Kremer  * writing the data to the filesystem and initiating generation of ereports
854e4f5a11dSJames Kremer  * as needed by calling slt_post_ereport.
855e4f5a11dSJames Kremer  *
856e4f5a11dSJames Kremer  *
857e4f5a11dSJames Kremer  * Parameters:
858e4f5a11dSJames Kremer  * slmp: A pointer to the ses log monitor structure.
859e4f5a11dSJames Kremer  * expander: A pointer to an expander object that contains info about the
860e4f5a11dSJames Kremer  * expander.
861e4f5a11dSJames Kremer  * lib_param: The structure used to pass data to and from the library.  This
862e4f5a11dSJames Kremer  * contains the target's information as well as a ponter to returned data.
863e4f5a11dSJames Kremer  */
864e4f5a11dSJames Kremer static int
process_log(ses_log_monitor_t * slmp,expander_t * expander,struct ses_log_call_struct * lib_param)865e4f5a11dSJames Kremer process_log(ses_log_monitor_t *slmp, expander_t *expander,
866e4f5a11dSJames Kremer     struct ses_log_call_struct *lib_param)
867e4f5a11dSJames Kremer {
868e4f5a11dSJames Kremer 	nvlist_t *result;
869e4f5a11dSJames Kremer 	int err;
870e4f5a11dSJames Kremer 
871e4f5a11dSJames Kremer 	char *pairName;
872e4f5a11dSJames Kremer 	nvpair_t *entry = NULL;
873e4f5a11dSJames Kremer 	FILE *fp = NULL;
874e4f5a11dSJames Kremer 	char fileName[MAXPATHLEN];
875e4f5a11dSJames Kremer 	time_t now;
876e4f5a11dSJames Kremer 	char format_time[30];
877e4f5a11dSJames Kremer 	struct tm tim;
878e4f5a11dSJames Kremer 	int output_count;
879e4f5a11dSJames Kremer 
880e4f5a11dSJames Kremer 	/*
881e4f5a11dSJames Kremer 	 * Determine how many bytes will be written out with this response,
882e4f5a11dSJames Kremer 	 * pass this count to a function that will determine whether or not
883e4f5a11dSJames Kremer 	 * to roll the logs, and will return the name of the file path to use.
884e4f5a11dSJames Kremer 	 */
885e4f5a11dSJames Kremer 	output_count = lib_param->number_log_entries * DATE_STRING_SIZE +
886e4f5a11dSJames Kremer 	    lib_param->size_of_log_entries;
887e4f5a11dSJames Kremer 
888e4f5a11dSJames Kremer 	err = create_filename(fileName, expander, slmp, output_count);
889e4f5a11dSJames Kremer 
890e4f5a11dSJames Kremer 	if (err == 0) {
891e4f5a11dSJames Kremer 		fp = fopen(fileName, "a");
892e4f5a11dSJames Kremer 		if (fp == NULL) {
893e4f5a11dSJames Kremer 			fmd_hdl_debug(slmp->slt_hdl, "File open failed");
894e4f5a11dSJames Kremer 		}
895e4f5a11dSJames Kremer 	}
896e4f5a11dSJames Kremer 
897e4f5a11dSJames Kremer 	/* Format the time to prepend to the log entry */
898e4f5a11dSJames Kremer 	now = time(NULL);
899e4f5a11dSJames Kremer 	tim = *(localtime(&now));
900e4f5a11dSJames Kremer 	(void) strftime(format_time, 30, "%b %d %H:%M:%S ", &tim);
901e4f5a11dSJames Kremer 
902e4f5a11dSJames Kremer 	/*
903e4f5a11dSJames Kremer 	 * For each entry returned, generate an ereport if the severity
904e4f5a11dSJames Kremer 	 * is at or above the target level, then append all entries to
905e4f5a11dSJames Kremer 	 * the appropriate log file.
906e4f5a11dSJames Kremer 	 */
907e4f5a11dSJames Kremer 	result = lib_param->log_data;
908e4f5a11dSJames Kremer 	while ((entry = nvlist_next_nvpair(result, entry)) != NULL) {
909e4f5a11dSJames Kremer 
910e4f5a11dSJames Kremer 		pairName = nvpair_name(entry);
911e4f5a11dSJames Kremer 		/*
912e4f5a11dSJames Kremer 		 * Process each entry in the result data returned from
913e4f5a11dSJames Kremer 		 * the library call.  These are log entries and may
914e4f5a11dSJames Kremer 		 * warrant an ereport.
915e4f5a11dSJames Kremer 		 */
916e4f5a11dSJames Kremer 		if (strncmp(ENTRY_PREFIX, pairName, 5) == 0) {
917e4f5a11dSJames Kremer 
918e4f5a11dSJames Kremer 			err = handle_log_entry(slmp, entry, expander,
919e4f5a11dSJames Kremer 			    format_time, fp);
920e4f5a11dSJames Kremer 		}
921e4f5a11dSJames Kremer 	}
922e4f5a11dSJames Kremer 
923e4f5a11dSJames Kremer 	/* Close the log file */
924e4f5a11dSJames Kremer 	if (fp) {
925e4f5a11dSJames Kremer 		(void) fclose(fp);
926e4f5a11dSJames Kremer 		fp = NULL;
927e4f5a11dSJames Kremer 	}
928e4f5a11dSJames Kremer 
929e4f5a11dSJames Kremer 	/* Free the space used for the result and the fmri. */
930e4f5a11dSJames Kremer 	nvlist_free(result);
931e4f5a11dSJames Kremer 
932e4f5a11dSJames Kremer 	return (0);
933e4f5a11dSJames Kremer 
934e4f5a11dSJames Kremer }
935e4f5a11dSJames Kremer 
936e4f5a11dSJames Kremer /*
937e4f5a11dSJames Kremer  * This function performs the log read and processing of the logs for a target
938e4f5a11dSJames Kremer  * as well as writing the data to the filesystem.  Ereports are generated
939e4f5a11dSJames Kremer  * as needed by calling slt_post_ereport.
940e4f5a11dSJames Kremer  *
941e4f5a11dSJames Kremer  * Access the log data for a specific ses.
942e4f5a11dSJames Kremer  * If a log entry should generate an ereport, call slt_post_ereport
943e4f5a11dSJames Kremer  * Format and store the data at the appropriate location.
944e4f5a11dSJames Kremer  */
945e4f5a11dSJames Kremer static int
slt_process_ses_log(topo_hdl_t * thp,tnode_t * node,void * arg)946e4f5a11dSJames Kremer slt_process_ses_log(topo_hdl_t *thp, tnode_t *node, void *arg)
947e4f5a11dSJames Kremer {
948e4f5a11dSJames Kremer 	ses_log_monitor_t *slmp = arg;
949e4f5a11dSJames Kremer 	nvlist_t *fmri;
950e4f5a11dSJames Kremer 	expander_t *expander;
951e4f5a11dSJames Kremer 	struct ses_log_call_struct lib_param;
952e4f5a11dSJames Kremer 
9537a087849SStephen Brooks 	int err = 0;
954e4f5a11dSJames Kremer 	char *label = NULL;
955e4f5a11dSJames Kremer 	char *target_path = NULL;
956e4f5a11dSJames Kremer 	char *product_id = NULL;
957e4f5a11dSJames Kremer 	char *sas_address = NULL;
958e4f5a11dSJames Kremer 
959e4f5a11dSJames Kremer 	if (strcmp(SASEXPANDER, topo_node_name(node)) != 0) {
960e4f5a11dSJames Kremer 		/* Not the type of node we are looking for */
961e4f5a11dSJames Kremer 		return (TOPO_WALK_NEXT);
962e4f5a11dSJames Kremer 	}
963e4f5a11dSJames Kremer 
9647a087849SStephen Brooks 	if (topo_prop_get_string(node, "authority", "product-id",
9657a087849SStephen Brooks 	    &product_id, &err) != 0) {
9667a087849SStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
9677a087849SStephen Brooks 		    "Error collecting product_id %d", err);
9687a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
9697a087849SStephen Brooks 	}
9707a087849SStephen Brooks 
971744e50acSStephen Brooks 	/* If the current system type is unsupported stop processing the node */
972744e50acSStephen Brooks 	if (platform_supported(product_id) == 0) {
973*7656b922SStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl, "Unsupported platform %d",
974*7656b922SStephen Brooks 		    product_id);
9757a087849SStephen Brooks 		topo_hdl_strfree(thp, product_id);
9767a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
9777a087849SStephen Brooks 	}
9787a087849SStephen Brooks 
979e4f5a11dSJames Kremer 	/* Allocate space for the holder structure */
980e4f5a11dSJames Kremer 	expander = (expander_t *)fmd_hdl_zalloc(slmp->slt_hdl,
981e4f5a11dSJames Kremer 	    sizeof (expander_t), FMD_SLEEP);
982e4f5a11dSJames Kremer 
9837a087849SStephen Brooks 	(void) snprintf(expander->slt_pid, MAXNAMELEN, "%s", product_id);
9847a087849SStephen Brooks 	topo_hdl_strfree(thp, product_id);
985e4f5a11dSJames Kremer 
9867a087849SStephen Brooks 	if (topo_prop_get_string(node, "protocol", "label", &label, &err)
9877a087849SStephen Brooks 	    != 0) {
9887a087849SStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl, "Error collecting label %d", err);
9897a087849SStephen Brooks 		free_expander(slmp, expander);
9907a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
991e4f5a11dSJames Kremer 	}
9927a087849SStephen Brooks 	(void) snprintf(expander->slt_label, MAXNAMELEN, "%s", label);
993e4f5a11dSJames Kremer 	topo_hdl_strfree(thp, label);
994e4f5a11dSJames Kremer 
9957a087849SStephen Brooks 	if (topo_prop_get_string(node, TOPO_PGROUP_SES,
9967a087849SStephen Brooks 	    TOPO_PROP_SES_DEV_PATH, &target_path, &err) != 0) {
9977a087849SStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
998744e50acSStephen Brooks 		    "Error collecting ses-devfs-path for %s: %d",
999744e50acSStephen Brooks 		    expander->slt_label, err);
10007a087849SStephen Brooks 		free_expander(slmp, expander);
10017a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
1002e4f5a11dSJames Kremer 	}
10037a087849SStephen Brooks 	(void) snprintf(expander->slt_path, MAXPATHLEN, "%s", target_path);
1004e4f5a11dSJames Kremer 	topo_hdl_strfree(thp, target_path);
1005e4f5a11dSJames Kremer 
10067a087849SStephen Brooks 	if (topo_prop_get_string(node, TOPO_PGROUP_STORAGE,
10077a087849SStephen Brooks 	    TOPO_PROP_SAS_ADDR, &sas_address, &err) != 0) {
10087a087849SStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
1009744e50acSStephen Brooks 		    "Error collecting sas_address for %s: %d",
1010744e50acSStephen Brooks 		    expander->slt_label, err);
10117a087849SStephen Brooks 		free_expander(slmp, expander);
10127a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
1013e4f5a11dSJames Kremer 	}
10147a087849SStephen Brooks 	if (strlen(sas_address) != 16) {
1015744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
10167a087849SStephen Brooks 		    "sas-address length is not 16: (%s)", sas_address);
10177a087849SStephen Brooks 		free_expander(slmp, expander);
10187a087849SStephen Brooks 		topo_hdl_strfree(thp, sas_address);
10197a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
1020e4f5a11dSJames Kremer 	}
10217a087849SStephen Brooks 	(void) snprintf(expander->slt_key, MAXNAMELEN, "%s", sas_address);
1022e4f5a11dSJames Kremer 	topo_hdl_strfree(thp, sas_address);
1023e4f5a11dSJames Kremer 
1024e4f5a11dSJames Kremer 	/* Obtain the fmri for this node and save a reference to it. */
1025e4f5a11dSJames Kremer 	if (topo_node_resource(node, &fmri, &err) != 0) {
1026744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl, "failed to get fmri for %s: %s",
1027744e50acSStephen Brooks 		    expander->slt_label, topo_strerror(err));
1028e4f5a11dSJames Kremer 
1029e4f5a11dSJames Kremer 		free_expander(slmp, expander);
1030e4f5a11dSJames Kremer 		return (TOPO_WALK_NEXT);
1031e4f5a11dSJames Kremer 	} else {
1032e4f5a11dSJames Kremer 		expander->fmri = fmri;
1033e4f5a11dSJames Kremer 	}
1034e4f5a11dSJames Kremer 
10357a087849SStephen Brooks 	if ((err = get_log(slmp, expander, &lib_param)) != 0) {
1036744e50acSStephen Brooks 		/*
1037744e50acSStephen Brooks 		 * NULL_LOG_DATA means that no data was returned from the
1038744e50acSStephen Brooks 		 * library.  (i.e. There were no log entries.) Just free memory
1039744e50acSStephen Brooks 		 * and return.
1040744e50acSStephen Brooks 		 */
1041744e50acSStephen Brooks 		if (err != NULL_LOG_DATA) {
1042744e50acSStephen Brooks 			fmd_hdl_debug(slmp->slt_hdl,
1043744e50acSStephen Brooks 			    "Error retrieving logs from %s: %d",
1044744e50acSStephen Brooks 			    expander->slt_label, err);
1045744e50acSStephen Brooks 		}
10467a087849SStephen Brooks 		free_expander(slmp, expander);
10477a087849SStephen Brooks 		return (TOPO_WALK_NEXT);
10487a087849SStephen Brooks 	}
1049e4f5a11dSJames Kremer 
10507a087849SStephen Brooks 	if ((err = process_log(slmp, expander, &lib_param)) != 0) {
1051744e50acSStephen Brooks 		fmd_hdl_debug(slmp->slt_hdl,
1052744e50acSStephen Brooks 		    "Error processing logs from %s: %d",
1053744e50acSStephen Brooks 		    expander->slt_label, err);
1054e4f5a11dSJames Kremer 	}
1055e4f5a11dSJames Kremer 
10567a087849SStephen Brooks 	/* Free the expander structure before exiting. */
1057e4f5a11dSJames Kremer 	free_expander(slmp, expander);
1058e4f5a11dSJames Kremer 
1059e4f5a11dSJames Kremer 	return (TOPO_WALK_NEXT);
1060e4f5a11dSJames Kremer }
1061e4f5a11dSJames Kremer 
1062e4f5a11dSJames Kremer /*
1063e4f5a11dSJames Kremer  * Called by the FMD after the specified timeout has expired.
1064e4f5a11dSJames Kremer  * This initiates the processing of the SES device logs.
1065e4f5a11dSJames Kremer  * slt_process_ses_log() performs the actual log retrieval and analysis.
1066e4f5a11dSJames Kremer  *
1067e4f5a11dSJames Kremer  * The last action is to reset the timer so that this method is called again.
1068e4f5a11dSJames Kremer  */
1069e4f5a11dSJames Kremer /*ARGSUSED*/
1070e4f5a11dSJames Kremer static void
slt_timeout(fmd_hdl_t * hdl,id_t id,void * data)1071e4f5a11dSJames Kremer slt_timeout(fmd_hdl_t *hdl, id_t id, void *data)
1072e4f5a11dSJames Kremer {
1073e4f5a11dSJames Kremer 	topo_hdl_t *thp;
1074e4f5a11dSJames Kremer 	topo_walk_t *twp;
1075e4f5a11dSJames Kremer 	int err;
1076e4f5a11dSJames Kremer 
1077e4f5a11dSJames Kremer 	/* Retrieve the SES log monitor structure. */
1078e4f5a11dSJames Kremer 	ses_log_monitor_t *slmp = fmd_hdl_getspecific(hdl);
1079e4f5a11dSJames Kremer 
1080e4f5a11dSJames Kremer 	if (slmp == NULL) {
1081e4f5a11dSJames Kremer 		fmd_hdl_abort(hdl, "Unable to retrieve log monitor structure.");
1082e4f5a11dSJames Kremer 		return;
1083e4f5a11dSJames Kremer 	}
1084e4f5a11dSJames Kremer 	slmp->slt_hdl = hdl;
1085e4f5a11dSJames Kremer 
1086e4f5a11dSJames Kremer 	thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION);
1087e4f5a11dSJames Kremer 
1088e4f5a11dSJames Kremer 	/*
1089e4f5a11dSJames Kremer 	 * This initializes a topology walk structure for stepping through
1090e4f5a11dSJames Kremer 	 * the snapshot associated with thp.  Note that a callback function
1091e4f5a11dSJames Kremer 	 * is supplied (slt_process_ses_log in this case).
1092e4f5a11dSJames Kremer 	 */
1093e4f5a11dSJames Kremer 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, slt_process_ses_log,
1094e4f5a11dSJames Kremer 	    slmp, &err)) == NULL) {
1095e4f5a11dSJames Kremer 
1096e4f5a11dSJames Kremer 		fmd_hdl_topo_rele(hdl, thp);
1097e4f5a11dSJames Kremer 		fmd_hdl_abort(hdl, "failed to get topology: %s\n",
1098e4f5a11dSJames Kremer 		    topo_strerror(err));
1099e4f5a11dSJames Kremer 		return;
1100e4f5a11dSJames Kremer 	}
1101e4f5a11dSJames Kremer 
1102e4f5a11dSJames Kremer 	/*
1103e4f5a11dSJames Kremer 	 * This function walks through the snapshot and invokes the callback
1104e4f5a11dSJames Kremer 	 * function supplied when it was set up above.
1105e4f5a11dSJames Kremer 	 */
1106e4f5a11dSJames Kremer 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
1107e4f5a11dSJames Kremer 		topo_walk_fini(twp);
1108e4f5a11dSJames Kremer 		fmd_hdl_topo_rele(hdl, thp);
1109e4f5a11dSJames Kremer 		fmd_hdl_abort(hdl, "failed to walk topology\n");
1110e4f5a11dSJames Kremer 		return;
1111e4f5a11dSJames Kremer 	}
1112e4f5a11dSJames Kremer 
1113e4f5a11dSJames Kremer 	/* This releases the walk structure. */
1114e4f5a11dSJames Kremer 	topo_walk_fini(twp);
1115e4f5a11dSJames Kremer 	fmd_hdl_topo_rele(hdl, thp);
1116e4f5a11dSJames Kremer 
1117e4f5a11dSJames Kremer 	/* Reset the timer for the next iteration. */
1118e4f5a11dSJames Kremer 	slmp->slt_timer = fmd_timer_install(hdl, NULL, NULL,
1119e4f5a11dSJames Kremer 	    slmp->slt_interval);
1120e4f5a11dSJames Kremer 
1121e4f5a11dSJames Kremer }
1122e4f5a11dSJames Kremer 
1123e4f5a11dSJames Kremer /*
1124e4f5a11dSJames Kremer  * Entry points for the FMD to access this transport.
1125e4f5a11dSJames Kremer  */
1126e4f5a11dSJames Kremer static const fmd_hdl_ops_t fmd_ops = {
1127e4f5a11dSJames Kremer 	NULL, /* fmdo_recv */
1128e4f5a11dSJames Kremer 	slt_timeout, /* fmdo_timeout */
1129e4f5a11dSJames Kremer 	NULL, /* fmdo_close */
1130e4f5a11dSJames Kremer 	NULL, /* fmdo_stats */
1131e4f5a11dSJames Kremer 	NULL, /* fmdo_gc */
1132e4f5a11dSJames Kremer 	NULL, /* fmdo_send */
1133e4f5a11dSJames Kremer 	NULL, /* fmdo_topo_change */
1134e4f5a11dSJames Kremer };
1135e4f5a11dSJames Kremer 
1136e4f5a11dSJames Kremer static const fmd_hdl_info_t fmd_info = {
1137e4f5a11dSJames Kremer 	"SES Log Transport Agent", "1.0", &fmd_ops, fmd_props
1138e4f5a11dSJames Kremer };
1139e4f5a11dSJames Kremer 
1140e4f5a11dSJames Kremer /*
1141e4f5a11dSJames Kremer  * Initialize the transport.
1142e4f5a11dSJames Kremer  */
1143e4f5a11dSJames Kremer void
_fmd_init(fmd_hdl_t * hdl)1144e4f5a11dSJames Kremer _fmd_init(fmd_hdl_t *hdl)
1145e4f5a11dSJames Kremer {
1146e4f5a11dSJames Kremer 	ses_log_monitor_t *slmp;
1147e4f5a11dSJames Kremer 	int error;
1148e4f5a11dSJames Kremer 	nvlist_t *expanderList;
1149e4f5a11dSJames Kremer 
1150e4f5a11dSJames Kremer 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
1151e4f5a11dSJames Kremer 		return;
1152e4f5a11dSJames Kremer 
1153e4f5a11dSJames Kremer 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
1154e4f5a11dSJames Kremer 	    sizeof (slt_stats) / sizeof (fmd_stat_t),
1155e4f5a11dSJames Kremer 	    (fmd_stat_t *)&slt_stats);
1156e4f5a11dSJames Kremer 
1157e4f5a11dSJames Kremer 	slmp = fmd_hdl_zalloc(hdl, sizeof (ses_log_monitor_t), FMD_SLEEP);
1158e4f5a11dSJames Kremer 	fmd_hdl_setspecific(hdl, slmp);
1159e4f5a11dSJames Kremer 
1160e4f5a11dSJames Kremer 	slmp->slt_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
1161e4f5a11dSJames Kremer 	if (slmp->slt_xprt == NULL) {
1162e4f5a11dSJames Kremer 		fmd_hdl_error(hdl,
1163e4f5a11dSJames Kremer 		    "Unable to obtain a reference to the transport");
1164e4f5a11dSJames Kremer 		fmd_hdl_free(hdl, slmp, sizeof (*slmp));
1165e4f5a11dSJames Kremer 		fmd_hdl_unregister(hdl);
1166e4f5a11dSJames Kremer 		return;
1167e4f5a11dSJames Kremer 	}
1168e4f5a11dSJames Kremer 
1169e4f5a11dSJames Kremer 	/*
1170e4f5a11dSJames Kremer 	 * interval is validity checked by the framework since it is of type
1171e4f5a11dSJames Kremer 	 * FMD_TYPE_TIME.
1172e4f5a11dSJames Kremer 	 */
1173e4f5a11dSJames Kremer 	slmp->slt_interval = fmd_prop_get_int64(hdl, "interval");
1174e4f5a11dSJames Kremer 
1175e4f5a11dSJames Kremer 	/*
1176e4f5a11dSJames Kremer 	 * Use default the severity if it is out of range.
1177e4f5a11dSJames Kremer 	 * Setting the severity too high is allowed as this has the effect
1178e4f5a11dSJames Kremer 	 * of preventing any ereports from being generated.
1179e4f5a11dSJames Kremer 	 */
1180e4f5a11dSJames Kremer 	slmp->slt_severity = fmd_prop_get_int32(hdl, "severity");
1181e4f5a11dSJames Kremer 	if (slmp->slt_severity < SES_LOG_LEVEL_NOTICE) {
1182e4f5a11dSJames Kremer 
1183e4f5a11dSJames Kremer 		slmp->slt_severity = SES_LOG_LEVEL_ERROR;
1184e4f5a11dSJames Kremer 	}
1185e4f5a11dSJames Kremer 
1186e4f5a11dSJames Kremer 	slmp->slt_log_count = fmd_prop_get_int32(hdl, "logcount");
1187e4f5a11dSJames Kremer 	if (slmp->slt_log_count < MIN_LOG_COUNT) {
1188e4f5a11dSJames Kremer 		slmp->slt_log_count = MIN_LOG_COUNT;
1189e4f5a11dSJames Kremer 	}
1190e4f5a11dSJames Kremer 
1191e4f5a11dSJames Kremer 	slmp->slt_max_log_size = fmd_prop_get_int32(hdl, "maxlogsize");
1192e4f5a11dSJames Kremer 		if (slmp->slt_max_log_size < MIN_LOG_SIZE) {
1193e4f5a11dSJames Kremer 		slmp->slt_max_log_size = MIN_LOG_SIZE;
1194e4f5a11dSJames Kremer 	}
1195e4f5a11dSJames Kremer 
1196e4f5a11dSJames Kremer 	/* Invalid paths will be handled by logging and skipping log creation */
1197e4f5a11dSJames Kremer 	slmp->slt_path = fmd_prop_get_string(hdl, "path");
1198e4f5a11dSJames Kremer 
1199e4f5a11dSJames Kremer 	/* Allocate space for the expander id holder */
1200e4f5a11dSJames Kremer 	if ((error = nvlist_alloc(&expanderList, NV_UNIQUE_NAME, 0)) != 0) {
1201e4f5a11dSJames Kremer 		fmd_xprt_close(hdl, slmp->slt_xprt);
1202e4f5a11dSJames Kremer 		fmd_hdl_strfree(hdl, slmp->slt_path);
1203e4f5a11dSJames Kremer 		fmd_hdl_free(hdl, slmp, sizeof (*slmp));
1204e4f5a11dSJames Kremer 
1205e4f5a11dSJames Kremer 		fmd_hdl_error(hdl,
1206e4f5a11dSJames Kremer 		    "Error allocating space for the expander list: %d", error);
1207e4f5a11dSJames Kremer 		fmd_hdl_unregister(hdl);
1208e4f5a11dSJames Kremer 		return;
1209e4f5a11dSJames Kremer 	}
1210e4f5a11dSJames Kremer 
1211e4f5a11dSJames Kremer 	slmp->slt_expanders = expanderList;
1212e4f5a11dSJames Kremer 
1213e4f5a11dSJames Kremer 	/*
1214e4f5a11dSJames Kremer 	 * Call our initial timer routine, starting the periodic timeout.
1215e4f5a11dSJames Kremer 	 */
1216e4f5a11dSJames Kremer 	slmp->slt_timer = fmd_timer_install(hdl, NULL, NULL, 0);
1217e4f5a11dSJames Kremer }
1218e4f5a11dSJames Kremer 
1219e4f5a11dSJames Kremer /*
1220e4f5a11dSJames Kremer  * Shut down the transport.  The primary responsibility is to release any
1221e4f5a11dSJames Kremer  * allocated memory.
1222e4f5a11dSJames Kremer  */
1223e4f5a11dSJames Kremer void
_fmd_fini(fmd_hdl_t * hdl)1224e4f5a11dSJames Kremer _fmd_fini(fmd_hdl_t *hdl)
1225e4f5a11dSJames Kremer {
1226e4f5a11dSJames Kremer 	ses_log_monitor_t *slmp;
1227e4f5a11dSJames Kremer 
1228e4f5a11dSJames Kremer 	slmp = fmd_hdl_getspecific(hdl);
1229e4f5a11dSJames Kremer 	if (slmp) {
1230e4f5a11dSJames Kremer 		fmd_timer_remove(hdl, slmp->slt_timer);
1231e4f5a11dSJames Kremer 		fmd_xprt_close(hdl, slmp->slt_xprt);
1232e4f5a11dSJames Kremer 		fmd_prop_free_string(hdl, slmp->slt_path);
1233e4f5a11dSJames Kremer 		nvlist_free(slmp->slt_expanders);
1234e4f5a11dSJames Kremer 		fmd_hdl_free(hdl, slmp, sizeof (*slmp));
1235e4f5a11dSJames Kremer 	}
1236e4f5a11dSJames Kremer }
1237