ses_enclosure.c revision 6316:40d5384cc8b2
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#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <scsi/libses.h>
30#include "ses_impl.h"
31
32int
33enc_parse_td(ses2_td_hdr_impl_t *tip, const char *tp, nvlist_t *nvl)
34{
35	int nverr;
36
37	if (tp != NULL)
38		SES_NV_ADD(fixed_string, nverr, nvl, SES_PROP_CLASS_DESCRIPTION,
39		    tp, tip->sthi_text_len);
40
41	return (0);
42}
43
44static int
45enc_eid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
46{
47	int nverr;
48
49	SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_subenclosure_id);
50
51	return (0);
52}
53
54static int
55enc_espid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
56{
57	int nverr;
58
59	SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_rel_esp_id);
60
61	return (0);
62}
63
64static int
65enc_nesp(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
66{
67	int nverr;
68
69	SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_n_esps);
70
71	return (0);
72}
73
74static int
75enc_lid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
76{
77	nvlist_t *lid;
78	int nverr;
79
80	if ((nverr = nvlist_alloc(&lid, NV_UNIQUE_NAME, 0)) != 0)
81		return (ses_set_nverrno(nverr, NULL));
82
83	SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_INT,
84	    SCSI_READ64(&tp->st_logical_id));
85
86	switch (tp->st_logical_id.sni8i_naa) {
87	case NAA_IEEE_EXT:
88		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE,
89		    NAA_IEEE_EXT);
90		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID,
91		    NAA_IEEE_EXT_COMPANY_ID(&tp->st_logical_id.sni8i_ext_id));
92		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A,
93		    NAA_IEEE_EXT_VENDOR_A(&tp->st_logical_id.sni8i_ext_id));
94		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_B,
95		    NAA_IEEE_EXT_VENDOR_B(&tp->st_logical_id.sni8i_ext_id));
96		break;
97	case NAA_IEEE_REG:
98		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE,
99		    NAA_IEEE_REG);
100		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID,
101		    NAA_IEEE_REG_COMPANY_ID(&tp->st_logical_id.sni8i_reg_id));
102		SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A,
103		    NAA_IEEE_REG_VENDOR_ID(&tp->st_logical_id.sni8i_reg_id));
104		break;
105	default:
106		break;
107	}
108
109	if ((nverr = nvlist_add_nvlist(nvl, name, lid)) != 0) {
110		nvlist_free(lid);
111		return (ses_set_nverrno(nverr, name));
112	}
113
114	nvlist_free(lid);
115
116	return (0);
117}
118
119static int
120enc_vid(const ses2_ed_impl_t *tp, nvlist_t *nvl,
121    const char *name)
122{
123	int nverr;
124
125	SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_vendor_id);
126
127	return (0);
128}
129
130static int
131enc_pid(const ses2_ed_impl_t *tp, nvlist_t *nvl,
132    const char *name)
133{
134	int nverr;
135
136	SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_id);
137
138	return (0);
139}
140
141static int
142enc_rev(const ses2_ed_impl_t *tp, nvlist_t *nvl,
143    const char *name)
144{
145	int nverr;
146
147	SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_revision);
148
149	return (0);
150}
151
152static int
153enc_vs(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
154{
155	int nverr;
156
157	SES_NV_ADD(byte_array, nverr, nvl, name, (uchar_t *)tp->st_priv,
158	    tp->st_hdr.sehi_ed_len - offsetof(ses2_ed_impl_t, st_priv[0]));
159
160	return (0);
161}
162
163/* LINTED - unused */
164static const ses2_ed_impl_t __ed = { 0 };
165
166#define	ED_REQ_LEN(member)	\
167	(offsetof(ses2_ed_impl_t, member) - sizeof (ses2_ed_hdr_impl_t) + \
168	    sizeof (__ed.member))
169
170static const struct config_member {
171	const char *name;
172	size_t minsz;
173	int (*func)(const ses2_ed_impl_t *, nvlist_t *, const char *);
174} config_members[] = {
175	{ SES_EN_PROP_EID, 0, enc_eid },
176	{ SES_EN_PROP_ESPID, 0, enc_espid },
177	{ SES_EN_PROP_NESP, 0, enc_nesp },
178	{ SES_EN_PROP_LID, ED_REQ_LEN(st_logical_id), enc_lid },
179	{ SES_EN_PROP_VID, ED_REQ_LEN(st_vendor_id), enc_vid },
180	{ SES_EN_PROP_PID, ED_REQ_LEN(st_product_id), enc_pid },
181	{ SES_EN_PROP_REV, ED_REQ_LEN(st_product_revision), enc_rev },
182	{ SES_EN_PROP_VS, ED_REQ_LEN(st_priv), enc_vs },
183	{ NULL, 0, NULL }
184};
185
186int
187enc_parse_ed(ses2_ed_impl_t *tp, nvlist_t *nvl)
188{
189	const struct config_member *mp;
190	int err;
191
192	if (tp == NULL)
193		return (0);
194
195	for (mp = &config_members[0]; mp->name != NULL; mp++) {
196		if (mp->func != NULL && tp->st_hdr.sehi_ed_len >= mp->minsz) {
197			err = mp->func(tp, nvl, mp->name);
198			if (err != 0)
199				return (err);
200		}
201	}
202
203	return (0);
204}
205
206ses_target_t *
207ses_open_scsi(uint_t version, libscsi_target_t *stp)
208{
209	ses_target_t *tp;
210	ses_snap_t *sp;
211
212	if (version != LIBSES_VERSION) {
213		(void) ses_set_errno(ESES_VERSION);
214		return (NULL);
215	}
216
217	if ((tp = ses_zalloc(sizeof (ses_target_t))) == NULL)
218		return (NULL);
219
220	tp->st_target = stp;
221	tp->st_scsi_hdl = libscsi_get_handle(stp);
222	tp->st_truncate = (getenv("LIBSES_TRUNCATE") != NULL);
223	if (tp->st_truncate)
224		srand48(gethrtime());
225
226	(void) pthread_mutex_init(&tp->st_lock, NULL);
227
228	if (ses_plugin_load(tp) != 0) {
229		ses_close(tp);
230		return (NULL);
231	}
232
233	if ((sp = ses_snap_new(tp)) == NULL) {
234		ses_close(tp);
235		return (NULL);
236	}
237
238	ses_snap_rele(sp);
239
240	return (tp);
241}
242
243ses_target_t *
244ses_open(uint_t version, const char *target)
245{
246	ses_target_t *tp;
247	libscsi_errno_t serr;
248	libscsi_target_t *stp;
249	libscsi_hdl_t *hp;
250
251	if ((hp = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
252		(void) ses_error(ESES_LIBSCSI, "failed to initialize "
253		    "libscsi: %s", libscsi_strerror(serr));
254		return (NULL);
255	}
256
257	if ((stp = libscsi_open(hp, NULL, target)) == NULL) {
258		(void) ses_libscsi_error(hp, "failed to open SES target");
259		libscsi_fini(hp);
260		return (NULL);
261	}
262
263	if ((tp = ses_open_scsi(version, stp)) == NULL) {
264		libscsi_close(hp, stp);
265		libscsi_fini(hp);
266		return (NULL);
267	}
268
269	tp->st_closescsi = B_TRUE;
270
271	return (tp);
272}
273
274libscsi_target_t *
275ses_scsi_target(ses_target_t *tp)
276{
277	return (tp->st_target);
278}
279
280void
281ses_close(ses_target_t *tp)
282{
283	if (tp->st_snapshots != NULL)
284		ses_snap_rele(tp->st_snapshots);
285	if (tp->st_snapshots != NULL)
286		ses_panic("attempt to close SES target with active snapshots");
287	ses_plugin_unload(tp);
288	if (tp->st_closescsi) {
289		libscsi_close(tp->st_scsi_hdl, tp->st_target);
290		libscsi_fini(tp->st_scsi_hdl);
291	}
292	ses_free(tp);
293}
294