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 
32 int
33 enc_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 
44 static int
45 enc_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 
54 static int
55 enc_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 
64 static int
65 enc_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 
74 static int
75 enc_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 
119 static int
120 enc_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 
130 static int
131 enc_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 
141 static int
142 enc_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 
152 static int
153 enc_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 */
164 static 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 
170 static 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 
186 int
187 enc_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 
206 ses_target_t *
207 ses_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 
243 ses_target_t *
244 ses_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 
274 libscsi_target_t *
275 ses_scsi_target(ses_target_t *tp)
276 {
277 	return (tp->st_target);
278 }
279 
280 void
281 ses_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