xref: /titanic_51/usr/src/lib/scsi/libses/common/ses_node.c (revision ac88567a7a5bb7f01cf22cf366bc9d6203e24d7a)
1275c9da8Seschrock /*
2275c9da8Seschrock  * CDDL HEADER START
3275c9da8Seschrock  *
4275c9da8Seschrock  * The contents of this file are subject to the terms of the
5275c9da8Seschrock  * Common Development and Distribution License (the "License").
6275c9da8Seschrock  * You may not use this file except in compliance with the License.
7275c9da8Seschrock  *
8275c9da8Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9275c9da8Seschrock  * or http://www.opensolaris.org/os/licensing.
10275c9da8Seschrock  * See the License for the specific language governing permissions
11275c9da8Seschrock  * and limitations under the License.
12275c9da8Seschrock  *
13275c9da8Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
14275c9da8Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15275c9da8Seschrock  * If applicable, add the following below this CDDL HEADER, with the
16275c9da8Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
17275c9da8Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
18275c9da8Seschrock  *
19275c9da8Seschrock  * CDDL HEADER END
20275c9da8Seschrock  */
21275c9da8Seschrock 
22275c9da8Seschrock /*
23*ac88567aSHyon Kim  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24275c9da8Seschrock  */
25275c9da8Seschrock 
26275c9da8Seschrock #include <scsi/libses.h>
27275c9da8Seschrock #include "ses_impl.h"
28275c9da8Seschrock 
29275c9da8Seschrock #define	NEXT_ED(eip)	\
30275c9da8Seschrock 	((ses2_ed_impl_t *)((uint8_t *)(eip) + 	\
31275c9da8Seschrock 	    ((eip)->st_hdr.sehi_ed_len + sizeof (ses2_ed_hdr_impl_t))))
32275c9da8Seschrock 
33275c9da8Seschrock static ses_node_t *
34275c9da8Seschrock ses_find_enclosure(ses_snap_t *sp, uint64_t number)
35275c9da8Seschrock {
36275c9da8Seschrock 	ses_node_t *np;
37275c9da8Seschrock 
38275c9da8Seschrock 	for (np = sp->ss_root->sn_first_child; np != NULL;
39275c9da8Seschrock 	    np = np->sn_next_sibling) {
40275c9da8Seschrock 		ASSERT(np->sn_type == SES_NODE_ENCLOSURE);
41275c9da8Seschrock 		if (np->sn_enc_num == number)
42275c9da8Seschrock 			return ((ses_node_t *)np);
43275c9da8Seschrock 	}
44275c9da8Seschrock 
45275c9da8Seschrock 	return (NULL);
46275c9da8Seschrock }
47275c9da8Seschrock 
48c4800545Sjmcp /*
49c4800545Sjmcp  * ses_snap_primary_enclosure() finds the primary enclosure for
50c4800545Sjmcp  * the supplied ses_snap_t.
51c4800545Sjmcp  */
52c4800545Sjmcp ses_node_t *
53c4800545Sjmcp ses_snap_primary_enclosure(ses_snap_t *sp)
54c4800545Sjmcp {
55c4800545Sjmcp 	return (ses_find_enclosure(sp, 0));
56c4800545Sjmcp }
57c4800545Sjmcp 
58275c9da8Seschrock void
59275c9da8Seschrock ses_node_teardown(ses_node_t *np)
60275c9da8Seschrock {
61275c9da8Seschrock 	ses_node_t *rp;
62275c9da8Seschrock 
63275c9da8Seschrock 	if (np == NULL)
64275c9da8Seschrock 		return;
65275c9da8Seschrock 
66275c9da8Seschrock 	for (; np != NULL; np = rp) {
67275c9da8Seschrock 		ses_node_teardown(np->sn_first_child);
68275c9da8Seschrock 		rp = np->sn_next_sibling;
69275c9da8Seschrock 		nvlist_free(np->sn_props);
70275c9da8Seschrock 		ses_free(np);
71275c9da8Seschrock 	}
72275c9da8Seschrock }
73275c9da8Seschrock 
74275c9da8Seschrock static ses_node_t *
75275c9da8Seschrock ses_node_alloc(ses_snap_t *sp, ses_node_t *pnp)
76275c9da8Seschrock {
77275c9da8Seschrock 	ses_node_t *np;
78275c9da8Seschrock 
79275c9da8Seschrock 	np = ses_zalloc(sizeof (ses_node_t));
80275c9da8Seschrock 	if (np == NULL)
81275c9da8Seschrock 		goto fail;
82275c9da8Seschrock 	if (nvlist_alloc(&np->sn_props, NV_UNIQUE_NAME, 0) != 0)
83275c9da8Seschrock 		goto fail;
84275c9da8Seschrock 
85275c9da8Seschrock 	np->sn_snapshot = sp;
86275c9da8Seschrock 	np->sn_id = sp->ss_n_nodes++;
87275c9da8Seschrock 
88275c9da8Seschrock 	if (pnp == NULL) {
89275c9da8Seschrock 		ASSERT(sp->ss_root == NULL);
90275c9da8Seschrock 		sp->ss_root = np;
91275c9da8Seschrock 	} else {
92275c9da8Seschrock 		np->sn_parent = pnp;
93275c9da8Seschrock 		np->sn_prev_sibling = pnp->sn_last_child;
94275c9da8Seschrock 
95275c9da8Seschrock 		if (pnp->sn_first_child == NULL)
96275c9da8Seschrock 			pnp->sn_first_child = np;
97275c9da8Seschrock 		else
98275c9da8Seschrock 			pnp->sn_last_child->sn_next_sibling = np;
99275c9da8Seschrock 
100275c9da8Seschrock 		pnp->sn_last_child = np;
101275c9da8Seschrock 	}
102275c9da8Seschrock 
103275c9da8Seschrock 	return (np);
104275c9da8Seschrock 
105275c9da8Seschrock fail:
106275c9da8Seschrock 	ses_free(np);
107275c9da8Seschrock 	ses_node_teardown(sp->ss_root);
108275c9da8Seschrock 	sp->ss_root = NULL;
109275c9da8Seschrock 	return (NULL);
110275c9da8Seschrock }
111275c9da8Seschrock 
112275c9da8Seschrock /*
113275c9da8Seschrock  * Parse element type descriptor.
114275c9da8Seschrock  */
115275c9da8Seschrock static int
116275c9da8Seschrock elem_parse_td(ses2_td_hdr_impl_t *tip, const char *tp, nvlist_t *nvl)
117275c9da8Seschrock {
118275c9da8Seschrock 	int nverr;
119275c9da8Seschrock 
120275c9da8Seschrock 	if (tp != NULL)
121275c9da8Seschrock 		SES_NV_ADD(fixed_string, nverr, nvl, SES_PROP_CLASS_DESCRIPTION,
122275c9da8Seschrock 		    tp, tip->sthi_text_len);
123275c9da8Seschrock 
124275c9da8Seschrock 	return (0);
125275c9da8Seschrock }
126275c9da8Seschrock 
127275c9da8Seschrock 
128275c9da8Seschrock /*
129275c9da8Seschrock  * Build a skeleton tree of nodes in the given snapshot.  This is the heart of
130275c9da8Seschrock  * libses, and is responsible for parsing the config page into a tree and
131275c9da8Seschrock  * populating nodes with data from the config page.
132275c9da8Seschrock  */
133275c9da8Seschrock static int
134275c9da8Seschrock ses_build_snap_skel(ses_snap_t *sp)
135275c9da8Seschrock {
136275c9da8Seschrock 	ses2_ed_impl_t *eip;
137275c9da8Seschrock 	ses2_td_hdr_impl_t *tip, *ftip;
138275c9da8Seschrock 	ses_node_t *np, *pnp, *cnp, *root;
139275c9da8Seschrock 	ses_snap_page_t *pp;
140275c9da8Seschrock 	ses2_config_page_impl_t *pip;
141275c9da8Seschrock 	int i, j, n_etds = 0;
142275c9da8Seschrock 	off_t toff;
143275c9da8Seschrock 	char *tp, *text;
144275c9da8Seschrock 	int err;
145*ac88567aSHyon Kim 	uint64_t idx, eidx;
146275c9da8Seschrock 
147275c9da8Seschrock 	pp = ses_snap_find_page(sp, SES2_DIAGPAGE_CONFIG, B_FALSE);
148275c9da8Seschrock 	if (pp == NULL)
149275c9da8Seschrock 		return (ses_error(ESES_BAD_RESPONSE, "target does not support "
150275c9da8Seschrock 		    "configuration diagnostic page"));
151275c9da8Seschrock 	pip = (ses2_config_page_impl_t *)pp->ssp_page;
152275c9da8Seschrock 
153275c9da8Seschrock 	if (pp->ssp_len < offsetof(ses2_config_page_impl_t, scpi_data))
154275c9da8Seschrock 		return (ses_error(ESES_BAD_RESPONSE, "no enclosure "
155275c9da8Seschrock 		    "descriptors found"));
156275c9da8Seschrock 
157275c9da8Seschrock 	/*
158275c9da8Seschrock 	 * Start with the root of the tree, which is a target node, containing
159275c9da8Seschrock 	 * just the SCSI inquiry properties.
160275c9da8Seschrock 	 */
161275c9da8Seschrock 	if ((root = ses_node_alloc(sp, sp->ss_root)) == NULL)
162275c9da8Seschrock 		return (-1);
163275c9da8Seschrock 
164275c9da8Seschrock 	root->sn_type = SES_NODE_TARGET;
165275c9da8Seschrock 	SES_NV_ADD(string, err, root->sn_props, SCSI_PROP_VENDOR,
166275c9da8Seschrock 	    libscsi_vendor(sp->ss_target->st_target));
167275c9da8Seschrock 	SES_NV_ADD(string, err, root->sn_props, SCSI_PROP_PRODUCT,
168275c9da8Seschrock 	    libscsi_product(sp->ss_target->st_target));
169275c9da8Seschrock 	SES_NV_ADD(string, err, root->sn_props, SCSI_PROP_REVISION,
170275c9da8Seschrock 	    libscsi_revision(sp->ss_target->st_target));
171275c9da8Seschrock 
172275c9da8Seschrock 	for (eip = (ses2_ed_impl_t *)pip->scpi_data, i = 0;
173275c9da8Seschrock 	    i < pip->scpi_n_subenclosures + 1;
174275c9da8Seschrock 	    i++, eip = NEXT_ED(eip)) {
175275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(eip, pp->ssp_page, pp->ssp_len))
176275c9da8Seschrock 			break;
177275c9da8Seschrock 
178275c9da8Seschrock 		n_etds += eip->st_hdr.sehi_n_etd_hdrs;
179275c9da8Seschrock 	}
180275c9da8Seschrock 	ftip = (ses2_td_hdr_impl_t *)eip;
181275c9da8Seschrock 
182275c9da8Seschrock 	/*
183275c9da8Seschrock 	 * There should really be only one Enclosure element possible for a
184275c9da8Seschrock 	 * give subenclosure ID.  The standard never comes out and says this,
185275c9da8Seschrock 	 * but it does describe this element as "managing the enclosure itself"
186275c9da8Seschrock 	 * which implies rather strongly that the subenclosure ID field is that
187275c9da8Seschrock 	 * of, well, the enclosure itself.  Since an enclosure can't contain
188275c9da8Seschrock 	 * itself, it follows logically that each subenclosure has at most one
189275c9da8Seschrock 	 * Enclosure type descriptor elements matching its ID.  Of course, some
190275c9da8Seschrock 	 * enclosure firmware is buggy, so this may not always work out; in
191275c9da8Seschrock 	 * this case we just ignore all but the first Enclosure-type element
192275c9da8Seschrock 	 * with our subenclosure ID.
193275c9da8Seschrock 	 */
194275c9da8Seschrock 	for (eip = (ses2_ed_impl_t *)pip->scpi_data, i = 0;
195275c9da8Seschrock 	    i < pip->scpi_n_subenclosures + 1;
196275c9da8Seschrock 	    i++, eip = NEXT_ED(eip)) {
197275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(eip, pp->ssp_page, pp->ssp_len))
198275c9da8Seschrock 			break;
199275c9da8Seschrock 
200275c9da8Seschrock 		if ((np = ses_node_alloc(sp, root)) == NULL)
201275c9da8Seschrock 			return (-1);
202275c9da8Seschrock 
203275c9da8Seschrock 		np->sn_type = SES_NODE_ENCLOSURE;
204275c9da8Seschrock 		np->sn_enc_num = eip->st_hdr.sehi_subenclosure_id;
205275c9da8Seschrock 
206275c9da8Seschrock 		if (!SES_WITHIN_PAGE(eip, eip->st_hdr.sehi_ed_len +
207275c9da8Seschrock 		    sizeof (ses2_ed_hdr_impl_t),
208275c9da8Seschrock 		    pp->ssp_page, pp->ssp_len))
209275c9da8Seschrock 			break;
210275c9da8Seschrock 
211275c9da8Seschrock 		if (enc_parse_ed(eip, np->sn_props) != 0)
212275c9da8Seschrock 			return (-1);
213275c9da8Seschrock 	}
214275c9da8Seschrock 
215275c9da8Seschrock 	if (root->sn_first_child == NULL)
216275c9da8Seschrock 		return (ses_error(ESES_BAD_RESPONSE, "no enclosure "
217275c9da8Seschrock 		    "descriptors found"));
218275c9da8Seschrock 
219275c9da8Seschrock 	tp = (char *)(ftip + n_etds);
220275c9da8Seschrock 
221*ac88567aSHyon Kim 	for (i = 0, toff = 0, idx = eidx = 0; i < n_etds; i++) {
222275c9da8Seschrock 		tip = ftip + i;
223275c9da8Seschrock 
224275c9da8Seschrock 		if (!SES_WITHIN_PAGE_STRUCT(tip, pp->ssp_page, pp->ssp_len))
225275c9da8Seschrock 			break;
226275c9da8Seschrock 
227275c9da8Seschrock 		pnp = ses_find_enclosure(sp,
228275c9da8Seschrock 		    tip->sthi_subenclosure_id);
229275c9da8Seschrock 		if (pnp == NULL) {
230275c9da8Seschrock 			idx += tip->sthi_max_elements + 1;
231*ac88567aSHyon Kim 			eidx += tip->sthi_max_elements;
232275c9da8Seschrock 			toff += tip->sthi_text_len;
233275c9da8Seschrock 			continue;
234275c9da8Seschrock 		}
235275c9da8Seschrock 
236275c9da8Seschrock 		if (tip->sthi_element_type == SES_ET_ENCLOSURE) {
237275c9da8Seschrock 			if (tip->sthi_max_elements == 0) {
238275c9da8Seschrock 				SES_NV_ADD(uint64, err, pnp->sn_props,
239275c9da8Seschrock 				    SES_PROP_ELEMENT_INDEX, idx);
240275c9da8Seschrock 				pnp->sn_rootidx = idx;
241275c9da8Seschrock 			} else {
242275c9da8Seschrock 				SES_NV_ADD(uint64, err, pnp->sn_props,
243275c9da8Seschrock 				    SES_PROP_ELEMENT_INDEX, idx + 1);
244*ac88567aSHyon Kim 				SES_NV_ADD(uint64, err, pnp->sn_props,
245*ac88567aSHyon Kim 				    SES_PROP_ELEMENT_ONLY_INDEX, eidx);
246275c9da8Seschrock 				pnp->sn_rootidx = idx + 1;
247275c9da8Seschrock 			}
248275c9da8Seschrock 
249275c9da8Seschrock 			if (tip->sthi_text_len > 0 &&
250275c9da8Seschrock 			    SES_WITHIN_PAGE(tp + toff, tip->sthi_text_len,
251275c9da8Seschrock 			    pp->ssp_page, pp->ssp_len)) {
252275c9da8Seschrock 				text = tp + toff;
253275c9da8Seschrock 				toff += tip->sthi_text_len;
254275c9da8Seschrock 			} else {
255275c9da8Seschrock 				text = NULL;
256275c9da8Seschrock 			}
257275c9da8Seschrock 
258275c9da8Seschrock 			SES_NV_ADD(uint64, err, pnp->sn_props,
259275c9da8Seschrock 			    SES_PROP_ELEMENT_TYPE, SES_ET_ENCLOSURE);
260275c9da8Seschrock 			if (enc_parse_td(tip, text, pnp->sn_props) != 0)
261275c9da8Seschrock 				return (-1);
262275c9da8Seschrock 
263275c9da8Seschrock 			idx += tip->sthi_max_elements + 1;
264*ac88567aSHyon Kim 			eidx += tip->sthi_max_elements;
265275c9da8Seschrock 			continue;
266275c9da8Seschrock 		}
267275c9da8Seschrock 
268275c9da8Seschrock 		if ((np = ses_node_alloc(sp, pnp)) == NULL)
269275c9da8Seschrock 			return (-1);
270275c9da8Seschrock 
271275c9da8Seschrock 		np->sn_type = SES_NODE_AGGREGATE;
272275c9da8Seschrock 		np->sn_enc_num = tip->sthi_subenclosure_id;
273275c9da8Seschrock 		np->sn_parent = pnp;
274275c9da8Seschrock 		np->sn_rootidx = idx;
275275c9da8Seschrock 
276275c9da8Seschrock 		SES_NV_ADD(uint64, err, np->sn_props,
277275c9da8Seschrock 		    SES_PROP_ELEMENT_INDEX, idx);
278275c9da8Seschrock 		SES_NV_ADD(uint64, err, np->sn_props,
279275c9da8Seschrock 		    SES_PROP_ELEMENT_TYPE, tip->sthi_element_type);
280275c9da8Seschrock 
281275c9da8Seschrock 		if (tip->sthi_text_len > 0 &&
282275c9da8Seschrock 		    SES_WITHIN_PAGE(tp + toff, tip->sthi_text_len,
283275c9da8Seschrock 		    pp->ssp_page, pp->ssp_len)) {
284275c9da8Seschrock 			text = tp + toff;
285275c9da8Seschrock 			toff += tip->sthi_text_len;
286275c9da8Seschrock 		} else {
287275c9da8Seschrock 			text = NULL;
288275c9da8Seschrock 		}
289275c9da8Seschrock 
290275c9da8Seschrock 		if (elem_parse_td(tip, text, np->sn_props) != 0)
291275c9da8Seschrock 			return (-1);
292275c9da8Seschrock 
293275c9da8Seschrock 		idx += tip->sthi_max_elements + 1;
294275c9da8Seschrock 
295275c9da8Seschrock 		if (tip->sthi_max_elements == 0)
296275c9da8Seschrock 			continue;
297275c9da8Seschrock 
298275c9da8Seschrock 		for (j = 0; j < tip->sthi_max_elements; j++) {
299275c9da8Seschrock 			cnp = ses_node_alloc(sp, np);
300275c9da8Seschrock 			if (cnp == NULL)
301275c9da8Seschrock 				return (-1);
302275c9da8Seschrock 
303275c9da8Seschrock 			cnp->sn_type = SES_NODE_ELEMENT;
304275c9da8Seschrock 			SES_NV_ADD(uint64, err, cnp->sn_props,
305275c9da8Seschrock 			    SES_PROP_ELEMENT_INDEX, np->sn_rootidx + j + 1);
306275c9da8Seschrock 			SES_NV_ADD(uint64, err, cnp->sn_props,
307*ac88567aSHyon Kim 			    SES_PROP_ELEMENT_ONLY_INDEX, eidx + j);
308*ac88567aSHyon Kim 			SES_NV_ADD(uint64, err, cnp->sn_props,
309275c9da8Seschrock 			    SES_PROP_ELEMENT_CLASS_INDEX, j);
310275c9da8Seschrock 			SES_NV_ADD(uint64, err, cnp->sn_props,
311275c9da8Seschrock 			    SES_PROP_ELEMENT_TYPE, tip->sthi_element_type);
312275c9da8Seschrock 		}
313*ac88567aSHyon Kim 
314*ac88567aSHyon Kim 		eidx += tip->sthi_max_elements;
315275c9da8Seschrock 	}
316275c9da8Seschrock 
317275c9da8Seschrock 	np->sn_snapshot->ss_n_elem = idx;
318275c9da8Seschrock 
319275c9da8Seschrock 	return (0);
320275c9da8Seschrock }
321275c9da8Seschrock 
322275c9da8Seschrock static int
323275c9da8Seschrock ses_fill_tree(ses_node_t *np)
324275c9da8Seschrock {
325275c9da8Seschrock 	if (np == NULL)
326275c9da8Seschrock 		return (0);
327275c9da8Seschrock 
328275c9da8Seschrock 	for (; np != NULL; np = np->sn_next_sibling) {
329275c9da8Seschrock 		if (ses_fill_node(np) != 0)
330275c9da8Seschrock 			return (-1);
331275c9da8Seschrock 		if (ses_fill_tree(np->sn_first_child) != 0)
332275c9da8Seschrock 			return (-1);
333275c9da8Seschrock 	}
334275c9da8Seschrock 
335275c9da8Seschrock 	return (0);
336275c9da8Seschrock }
337275c9da8Seschrock 
338275c9da8Seschrock int
339275c9da8Seschrock ses_fill_snap(ses_snap_t *sp)
340275c9da8Seschrock {
341275c9da8Seschrock 	if (ses_build_snap_skel(sp) != 0)
342275c9da8Seschrock 		return (-1);
343275c9da8Seschrock 
344275c9da8Seschrock 	if (ses_fill_tree(sp->ss_root) != 0)
345275c9da8Seschrock 		return (-1);
346275c9da8Seschrock 
347275c9da8Seschrock 	return (0);
348275c9da8Seschrock }
349275c9da8Seschrock 
350275c9da8Seschrock ses_node_t *
351275c9da8Seschrock ses_root_node(ses_snap_t *sp)
352275c9da8Seschrock {
353275c9da8Seschrock 	return (sp->ss_root);
354275c9da8Seschrock }
355275c9da8Seschrock 
356275c9da8Seschrock ses_node_t *
357275c9da8Seschrock ses_node_sibling(ses_node_t *np)
358275c9da8Seschrock {
359275c9da8Seschrock 	return (np->sn_next_sibling);
360275c9da8Seschrock }
361275c9da8Seschrock 
362275c9da8Seschrock ses_node_t *
363275c9da8Seschrock ses_node_prev_sibling(ses_node_t *np)
364275c9da8Seschrock {
365275c9da8Seschrock 	return (np->sn_prev_sibling);
366275c9da8Seschrock }
367275c9da8Seschrock 
368275c9da8Seschrock ses_node_t *
369275c9da8Seschrock ses_node_parent(ses_node_t *np)
370275c9da8Seschrock {
371275c9da8Seschrock 	return (np->sn_parent);
372275c9da8Seschrock }
373275c9da8Seschrock 
374275c9da8Seschrock ses_node_t *
375275c9da8Seschrock ses_node_child(ses_node_t *np)
376275c9da8Seschrock {
377275c9da8Seschrock 	return (np->sn_first_child);
378275c9da8Seschrock }
379275c9da8Seschrock 
380275c9da8Seschrock ses_node_type_t
381275c9da8Seschrock ses_node_type(ses_node_t *np)
382275c9da8Seschrock {
383275c9da8Seschrock 	return (np->sn_type);
384275c9da8Seschrock }
385275c9da8Seschrock 
386275c9da8Seschrock ses_snap_t *
387275c9da8Seschrock ses_node_snapshot(ses_node_t *np)
388275c9da8Seschrock {
389275c9da8Seschrock 	return ((ses_snap_t *)np->sn_snapshot);
390275c9da8Seschrock }
391275c9da8Seschrock 
392275c9da8Seschrock ses_target_t *
393275c9da8Seschrock ses_node_target(ses_node_t *np)
394275c9da8Seschrock {
395275c9da8Seschrock 	return (np->sn_snapshot->ss_target);
396275c9da8Seschrock }
397275c9da8Seschrock 
398275c9da8Seschrock nvlist_t *
399275c9da8Seschrock ses_node_props(ses_node_t *np)
400275c9da8Seschrock {
401275c9da8Seschrock 	return (np->sn_props);
402275c9da8Seschrock }
403275c9da8Seschrock 
404275c9da8Seschrock /*
405275c9da8Seschrock  * A node identifier is a (generation, index) tuple that can be used to lookup a
406275c9da8Seschrock  * node within this target at a later point.  This will be valid across
407275c9da8Seschrock  * snapshots, though it will return failure if the generation count has changed.
408275c9da8Seschrock  */
409275c9da8Seschrock uint64_t
410275c9da8Seschrock ses_node_id(ses_node_t *np)
411275c9da8Seschrock {
412275c9da8Seschrock 	return (((uint64_t)np->sn_snapshot->ss_generation << 32) |
413275c9da8Seschrock 	    np->sn_id);
414275c9da8Seschrock }
415