xref: /titanic_52/usr/src/lib/fm/libdiskstatus/common/libdiskstatus.c (revision 24db46411fd54f70c35b94bb952eb7ba040e43b4)
1*24db4641Seschrock /*
2*24db4641Seschrock  * CDDL HEADER START
3*24db4641Seschrock  *
4*24db4641Seschrock  * The contents of this file are subject to the terms of the
5*24db4641Seschrock  * Common Development and Distribution License (the "License").
6*24db4641Seschrock  * You may not use this file except in compliance with the License.
7*24db4641Seschrock  *
8*24db4641Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*24db4641Seschrock  * or http://www.opensolaris.org/os/licensing.
10*24db4641Seschrock  * See the License for the specific language governing permissions
11*24db4641Seschrock  * and limitations under the License.
12*24db4641Seschrock  *
13*24db4641Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
14*24db4641Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*24db4641Seschrock  * If applicable, add the following below this CDDL HEADER, with the
16*24db4641Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
17*24db4641Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
18*24db4641Seschrock  *
19*24db4641Seschrock  * CDDL HEADER END
20*24db4641Seschrock  */
21*24db4641Seschrock /*
22*24db4641Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*24db4641Seschrock  * Use is subject to license terms.
24*24db4641Seschrock  */
25*24db4641Seschrock 
26*24db4641Seschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*24db4641Seschrock 
28*24db4641Seschrock /*
29*24db4641Seschrock  * Disk status library
30*24db4641Seschrock  *
31*24db4641Seschrock  * This library is responsible for querying health and other status information
32*24db4641Seschrock  * from disk drives.  It is intended to be a generic interface, however only
33*24db4641Seschrock  * SCSI (and therefore SATA) disks are currently supported.  The library is
34*24db4641Seschrock  * capable of detecting the following status conditions:
35*24db4641Seschrock  *
36*24db4641Seschrock  * 	- Predictive failure
37*24db4641Seschrock  * 	- Overtemp
38*24db4641Seschrock  * 	- Self-test failure
39*24db4641Seschrock  */
40*24db4641Seschrock 
41*24db4641Seschrock #include <assert.h>
42*24db4641Seschrock #include <errno.h>
43*24db4641Seschrock #include <fcntl.h>
44*24db4641Seschrock #include <libdevinfo.h>
45*24db4641Seschrock #include <libdiskstatus.h>
46*24db4641Seschrock #include <stdlib.h>
47*24db4641Seschrock #include <string.h>
48*24db4641Seschrock #include <sys/fm/io/scsi.h>
49*24db4641Seschrock #include <sys/stat.h>
50*24db4641Seschrock #include <unistd.h>
51*24db4641Seschrock 
52*24db4641Seschrock #include "ds_impl.h"
53*24db4641Seschrock #include "ds_scsi.h"
54*24db4641Seschrock 
55*24db4641Seschrock static ds_transport_t *ds_transports[] = {
56*24db4641Seschrock 	&ds_scsi_sim_transport,
57*24db4641Seschrock 	&ds_scsi_uscsi_transport
58*24db4641Seschrock };
59*24db4641Seschrock 
60*24db4641Seschrock #define	NTRANSPORTS	(sizeof (ds_transports) / sizeof (ds_transports[0]))
61*24db4641Seschrock 
62*24db4641Seschrock /*
63*24db4641Seschrock  * Open a handle to a disk.  This will fail if the device cannot be opened, or
64*24db4641Seschrock  * if no suitable transport exists for communicating with the device.
65*24db4641Seschrock  */
66*24db4641Seschrock disk_status_t *
67*24db4641Seschrock disk_status_open(const char *path, int *error)
68*24db4641Seschrock {
69*24db4641Seschrock 	disk_status_t *dsp;
70*24db4641Seschrock 	ds_transport_t *t;
71*24db4641Seschrock 	int i;
72*24db4641Seschrock 
73*24db4641Seschrock 	if ((dsp = calloc(sizeof (disk_status_t), 1)) == NULL) {
74*24db4641Seschrock 		*error = EDS_NOMEM;
75*24db4641Seschrock 		return (NULL);
76*24db4641Seschrock 	}
77*24db4641Seschrock 
78*24db4641Seschrock 	if ((dsp->ds_fd = open(path, O_RDWR)) < 0) {
79*24db4641Seschrock 		*error = EDS_CANT_OPEN;
80*24db4641Seschrock 		free(dsp);
81*24db4641Seschrock 		return (NULL);
82*24db4641Seschrock 	}
83*24db4641Seschrock 
84*24db4641Seschrock 	if ((dsp->ds_path = strdup(path)) == NULL) {
85*24db4641Seschrock 		*error = EDS_NOMEM;
86*24db4641Seschrock 		disk_status_close(dsp);
87*24db4641Seschrock 		return (NULL);
88*24db4641Seschrock 	}
89*24db4641Seschrock 
90*24db4641Seschrock 	for (i = 0; i < NTRANSPORTS; i++) {
91*24db4641Seschrock 		t = ds_transports[i];
92*24db4641Seschrock 
93*24db4641Seschrock 		dsp->ds_transport = t;
94*24db4641Seschrock 
95*24db4641Seschrock 		nvlist_free(dsp->ds_state);
96*24db4641Seschrock 		dsp->ds_state = NULL;
97*24db4641Seschrock 		if (nvlist_alloc(&dsp->ds_state, NV_UNIQUE_NAME, 0) != 0) {
98*24db4641Seschrock 			*error = EDS_NOMEM;
99*24db4641Seschrock 			disk_status_close(dsp);
100*24db4641Seschrock 			return (NULL);
101*24db4641Seschrock 		}
102*24db4641Seschrock 
103*24db4641Seschrock 		if ((dsp->ds_data = t->dt_open(dsp)) == NULL) {
104*24db4641Seschrock 			if (dsp->ds_error != EDS_NO_TRANSPORT) {
105*24db4641Seschrock 				*error = dsp->ds_error;
106*24db4641Seschrock 				disk_status_close(dsp);
107*24db4641Seschrock 				return (NULL);
108*24db4641Seschrock 			}
109*24db4641Seschrock 		} else {
110*24db4641Seschrock 			dsp->ds_error = 0;
111*24db4641Seschrock 			break;
112*24db4641Seschrock 		}
113*24db4641Seschrock 	}
114*24db4641Seschrock 
115*24db4641Seschrock 	if (dsp->ds_error == EDS_NO_TRANSPORT) {
116*24db4641Seschrock 		*error = dsp->ds_error;
117*24db4641Seschrock 		disk_status_close(dsp);
118*24db4641Seschrock 		return (NULL);
119*24db4641Seschrock 	}
120*24db4641Seschrock 
121*24db4641Seschrock 	return (dsp);
122*24db4641Seschrock }
123*24db4641Seschrock 
124*24db4641Seschrock /*
125*24db4641Seschrock  * Close a handle to a disk.
126*24db4641Seschrock  */
127*24db4641Seschrock void
128*24db4641Seschrock disk_status_close(disk_status_t *dsp)
129*24db4641Seschrock {
130*24db4641Seschrock 	nvlist_free(dsp->ds_state);
131*24db4641Seschrock 	nvlist_free(dsp->ds_predfail);
132*24db4641Seschrock 	nvlist_free(dsp->ds_overtemp);
133*24db4641Seschrock 	nvlist_free(dsp->ds_testfail);
134*24db4641Seschrock 	if (dsp->ds_data)
135*24db4641Seschrock 		dsp->ds_transport->dt_close(dsp->ds_data);
136*24db4641Seschrock 	(void) close(dsp->ds_fd);
137*24db4641Seschrock 	free(dsp->ds_path);
138*24db4641Seschrock 	free(dsp);
139*24db4641Seschrock }
140*24db4641Seschrock 
141*24db4641Seschrock void
142*24db4641Seschrock disk_status_set_debug(boolean_t value)
143*24db4641Seschrock {
144*24db4641Seschrock 	ds_debug = value;
145*24db4641Seschrock }
146*24db4641Seschrock 
147*24db4641Seschrock /*
148*24db4641Seschrock  * Query basic information
149*24db4641Seschrock  */
150*24db4641Seschrock const char *
151*24db4641Seschrock disk_status_path(disk_status_t *dsp)
152*24db4641Seschrock {
153*24db4641Seschrock 	return (dsp->ds_path);
154*24db4641Seschrock }
155*24db4641Seschrock 
156*24db4641Seschrock int
157*24db4641Seschrock disk_status_errno(disk_status_t *dsp)
158*24db4641Seschrock {
159*24db4641Seschrock 	return (dsp->ds_error);
160*24db4641Seschrock }
161*24db4641Seschrock 
162*24db4641Seschrock nvlist_t *
163*24db4641Seschrock disk_status_get(disk_status_t *dsp)
164*24db4641Seschrock {
165*24db4641Seschrock 	nvlist_t *nvl = NULL;
166*24db4641Seschrock 	nvlist_t *faults = NULL;
167*24db4641Seschrock 	int err;
168*24db4641Seschrock 
169*24db4641Seschrock 	/*
170*24db4641Seschrock 	 * Scan (or rescan) the current device.
171*24db4641Seschrock 	 */
172*24db4641Seschrock 	nvlist_free(dsp->ds_testfail);
173*24db4641Seschrock 	nvlist_free(dsp->ds_predfail);
174*24db4641Seschrock 	nvlist_free(dsp->ds_overtemp);
175*24db4641Seschrock 	dsp->ds_testfail = dsp->ds_overtemp = dsp->ds_predfail = NULL;
176*24db4641Seschrock 	dsp->ds_faults = 0;
177*24db4641Seschrock 
178*24db4641Seschrock 	/*
179*24db4641Seschrock 	 * Even if there is an I/O failure when trying to scan the device, we
180*24db4641Seschrock 	 * can still return the current state.
181*24db4641Seschrock 	 */
182*24db4641Seschrock 	if (dsp->ds_transport->dt_scan(dsp->ds_data) != 0 &&
183*24db4641Seschrock 	    dsp->ds_error != EDS_IO)
184*24db4641Seschrock 		return (NULL);
185*24db4641Seschrock 
186*24db4641Seschrock 	if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
187*24db4641Seschrock 		goto nverror;
188*24db4641Seschrock 
189*24db4641Seschrock 	if ((err = nvlist_add_string(nvl, "protocol", "scsi")) != 0 ||
190*24db4641Seschrock 	    (err = nvlist_add_nvlist(nvl, "status", dsp->ds_state)) != 0)
191*24db4641Seschrock 		goto nverror;
192*24db4641Seschrock 
193*24db4641Seschrock 	/*
194*24db4641Seschrock 	 * Construct the list of faults.
195*24db4641Seschrock 	 */
196*24db4641Seschrock 	if ((err = nvlist_alloc(&faults, NV_UNIQUE_NAME, 0)) != 0)
197*24db4641Seschrock 		goto nverror;
198*24db4641Seschrock 
199*24db4641Seschrock 	if (dsp->ds_predfail != NULL) {
200*24db4641Seschrock 		if ((err = nvlist_add_boolean_value(faults,
201*24db4641Seschrock 		    FM_EREPORT_SCSI_PREDFAIL,
202*24db4641Seschrock 		    (dsp->ds_faults & DS_FAULT_PREDFAIL) != 0)) != 0 ||
203*24db4641Seschrock 		    (err = nvlist_add_nvlist(nvl, FM_EREPORT_SCSI_PREDFAIL,
204*24db4641Seschrock 		    dsp->ds_predfail)) != 0)
205*24db4641Seschrock 			goto nverror;
206*24db4641Seschrock 	}
207*24db4641Seschrock 
208*24db4641Seschrock 	if (dsp->ds_testfail != NULL) {
209*24db4641Seschrock 		if ((err = nvlist_add_boolean_value(faults,
210*24db4641Seschrock 		    FM_EREPORT_SCSI_TESTFAIL,
211*24db4641Seschrock 		    (dsp->ds_faults & DS_FAULT_TESTFAIL) != 0)) != 0 ||
212*24db4641Seschrock 		    (err = nvlist_add_nvlist(nvl, FM_EREPORT_SCSI_TESTFAIL,
213*24db4641Seschrock 		    dsp->ds_testfail)) != 0)
214*24db4641Seschrock 			goto nverror;
215*24db4641Seschrock 	}
216*24db4641Seschrock 
217*24db4641Seschrock 	if (dsp->ds_overtemp != NULL) {
218*24db4641Seschrock 		if ((err = nvlist_add_boolean_value(faults,
219*24db4641Seschrock 		    FM_EREPORT_SCSI_OVERTEMP,
220*24db4641Seschrock 		    (dsp->ds_faults & DS_FAULT_OVERTEMP) != 0)) != 0 ||
221*24db4641Seschrock 		    (err = nvlist_add_nvlist(nvl, FM_EREPORT_SCSI_OVERTEMP,
222*24db4641Seschrock 		    dsp->ds_overtemp)) != 0)
223*24db4641Seschrock 			goto nverror;
224*24db4641Seschrock 	}
225*24db4641Seschrock 
226*24db4641Seschrock 	if ((err = nvlist_add_nvlist(nvl, "faults", faults)) != 0)
227*24db4641Seschrock 		goto nverror;
228*24db4641Seschrock 
229*24db4641Seschrock 	nvlist_free(faults);
230*24db4641Seschrock 	return (nvl);
231*24db4641Seschrock 
232*24db4641Seschrock nverror:
233*24db4641Seschrock 	assert(err == ENOMEM);
234*24db4641Seschrock 	nvlist_free(nvl);
235*24db4641Seschrock 	nvlist_free(faults);
236*24db4641Seschrock 	(void) ds_set_errno(dsp, EDS_NOMEM);
237*24db4641Seschrock 	return (NULL);
238*24db4641Seschrock }
239