275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * CDDL HEADER START
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * The contents of this file are subject to the terms of the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Common Development and Distribution License (the "License").
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * You may not use this file except in compliance with the License.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * or http://www.opensolaris.org/os/licensing.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * See the License for the specific language governing permissions
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * and limitations under the License.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * When distributing Covered Code, include this CDDL HEADER in each
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * If applicable, add the following below this CDDL HEADER, with the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * fields enclosed by brackets "[]" replaced with your own identifying
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * information: Portions Copyright [yyyy] [name of copyright owner]
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * CDDL HEADER END
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <scsi/libses.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "ses_impl.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_page_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_find_page(ses_snap_t *sp, ses2_diag_page_t page, boolean_t ctl)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_num == page && pp->ssp_control == ctl &&
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (pp->ssp_len > 0 || pp->ssp_control))
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockgrow_snap_page(ses_snap_page_t *pp, size_t min)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint8_t *newbuf;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (min == 0 || min < pp->ssp_alloc)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock min = pp->ssp_alloc * 2;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((newbuf = ses_realloc(pp->ssp_page, min)) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_page = newbuf;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_alloc = min;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bzero(newbuf + pp->ssp_len, pp->ssp_alloc - pp->ssp_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic ses_snap_page_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockalloc_snap_page(void)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((pp = ses_zalloc(sizeof (ses_snap_page_t))) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((pp->ssp_page = ses_zalloc(SES2_MIN_DIAGPAGE_ALLOC)) == NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_free(pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_num = -1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_alloc = SES2_MIN_DIAGPAGE_ALLOC;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockfree_snap_page(ses_snap_page_t *pp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_mmap_base)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) munmap(pp->ssp_mmap_base, pp->ssp_mmap_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_free(pp->ssp_page);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_free(pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockfree_all_snap_pages(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp, *np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = np) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock np = pp->ssp_next;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_snap_page(pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_pages = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Grow (if needed) the control page buffer, fill in the page code, page
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * length, and generation count, and return a pointer to the page. The
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * caller is responsible for filling in the rest of the page data. If 'unique'
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * is specified, then a new page instance is created instead of sharing the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * current one.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_page_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_ctl_page(ses_snap_t *sp, ses2_diag_page_t page, size_t dlen,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock boolean_t unique)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_target_t *tp = sp->ss_target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock spc3_diag_page_impl_t *pip;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp, *up, **loc;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_pagedesc_t *dp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t len;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp = ses_snap_find_page(sp, page, B_TRUE);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp == NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_set_errno(ESES_NOTSUP);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_initialized && !unique)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (unique) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * The user has requested a unique instance of the page. Create
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * a new ses_snap_page_t instance and chain it off the
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * 'ssp_instances' list of the master page. These must be
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * appended to the end of the chain, as the order of operations
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * may be important (i.e. microcode download).
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((up = alloc_snap_page()) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock up->ssp_num = pp->ssp_num;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock up->ssp_control = B_TRUE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (loc = &pp->ssp_unique; *loc != NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock loc = &(*loc)->ssp_next)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *loc = up;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp = up;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock dp = ses_get_pagedesc(tp, page, SES_PAGE_CTL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ASSERT(dp != NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock len = dp->spd_ctl_len(sp->ss_n_elem, page, dlen);
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim if (pp->ssp_alloc < len && grow_snap_page(pp, len) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_len = len;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bzero(pp->ssp_page, len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_initialized = B_TRUE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pip = (spc3_diag_page_impl_t *)pp->ssp_page;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pip->sdpi_page_code = (uint8_t)page;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SCSI_WRITE16(&pip->sdpi_page_length,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock len - offsetof(spc3_diag_page_impl_t, sdpi_data[0]));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (dp->spd_gcoff != -1)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SCSI_WRITE32((uint8_t *)pip + dp->spd_gcoff, sp->ss_generation);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockread_status_page(ses_snap_t *sp, ses2_diag_page_t page)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_t *ap;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_target_t *tp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock spc3_diag_page_impl_t *pip;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock spc3_receive_diagnostic_results_cdb_t *cp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint_t flags;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint8_t *buf;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t alloc;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint_t retries = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses2_diag_page_t retpage;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_num == page && !pp->ssp_control)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * No matching page. Since the page number is not under consumer or
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * device control, this must be a bug.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ASSERT(pp != NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock tp = sp->ss_target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock flags = LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE |
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock LIBSCSI_AF_RQSENSE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockagain:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ap = libscsi_action_alloc(tp->st_scsi_hdl,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SPC3_CMD_RECEIVE_DIAGNOSTIC_RESULTS, flags, pp->ssp_page,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_alloc);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ap == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ses_libscsi_error(tp->st_scsi_hdl, "failed to "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "allocate SCSI action"));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cp = (spc3_receive_diagnostic_results_cdb_t *)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_get_cdb(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cp->rdrc_page_code = pp->ssp_num;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cp->rdrc_pcv = 1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SCSI_WRITE16(&cp->rdrc_allocation_length,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock MIN(pp->ssp_alloc, UINT16_MAX));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (libscsi_exec(ap, tp->st_target) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_free(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ses_libscsi_error(tp->st_scsi_hdl,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "receive diagnostic results failed"));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (libscsi_action_get_status(ap) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_scsi_error(ap,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "receive diagnostic results failed");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_free(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) libscsi_action_get_buffer(ap, &buf, &alloc, &pp->ssp_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_free(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ASSERT(buf == pp->ssp_page);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ASSERT(alloc == pp->ssp_alloc);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim if (pp->ssp_alloc - pp->ssp_len < 0x80 && pp->ssp_alloc < UINT16_MAX) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bzero(pp->ssp_page, pp->ssp_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_len = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (grow_snap_page(pp, 0) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock goto again;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim if (pp->ssp_len < offsetof(spc3_diag_page_impl_t, sdpi_data)) {
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim bzero(pp->ssp_page, pp->ssp_len);
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim pp->ssp_len = 0;
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim return (ses_error(ESES_BAD_RESPONSE, "target returned "
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim "truncated page 0x%x (length %d)", page, pp->ssp_len));
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim }
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pip = (spc3_diag_page_impl_t *)buf;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pip->sdpi_page_code == page)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock retpage = pip->sdpi_page_code;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bzero(pp->ssp_page, pp->ssp_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_len = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (retpage == SES2_DIAGPAGE_ENCLOSURE_BUSY) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (++retries > LIBSES_MAX_BUSY_RETRIES)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ses_error(ESES_BUSY, "too many "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "enclosure busy responses for page 0x%x", page));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock goto again;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ses_error(ESES_BAD_RESPONSE, "target returned page 0x%x "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "instead of the requested page 0x%x", retpage, page));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocksend_control_page(ses_snap_t *sp, ses_snap_page_t *pp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_target_t *tp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_t *ap;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock spc3_send_diagnostic_cdb_t *cp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint_t flags;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock tp = sp->ss_target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock flags = LIBSCSI_AF_WRITE | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE |
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock LIBSCSI_AF_RQSENSE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ap = libscsi_action_alloc(tp->st_scsi_hdl, SPC3_CMD_SEND_DIAGNOSTIC,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock flags, pp->ssp_page, pp->ssp_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ap == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ses_libscsi_error(tp->st_scsi_hdl, "failed to "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "allocate SCSI action"));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cp = (spc3_send_diagnostic_cdb_t *)libscsi_action_get_cdb(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock cp->sdc_pf = 1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SCSI_WRITE16(&cp->sdc_parameter_list_length, pp->ssp_len);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (libscsi_exec(ap, tp->st_target) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_free(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ses_libscsi_error(tp->st_scsi_hdl,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "SEND DIAGNOSTIC command failed for page 0x%x",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_num));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (libscsi_action_get_status(ap) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_scsi_error(ap, "SEND DIAGNOSTIC command "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "failed for page 0x%x", pp->ssp_num);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_free(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock libscsi_action_free(ap);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockpages_skel_create(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp, *np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_target_t *tp = sp->ss_target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses2_supported_ses_diag_page_impl_t *pip;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses2_diag_page_t page;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t npages;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t pagelen;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock off_t i;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ASSERT(sp->ss_pages == NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((pp = alloc_snap_page()) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_num = SES2_DIAGPAGE_SUPPORTED_PAGES;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_control = B_FALSE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_pages = pp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (read_status_page(sp, SES2_DIAGPAGE_SUPPORTED_PAGES) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_snap_page(pp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_pages = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pip = pp->ssp_page;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagelen = pp->ssp_len;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock npages = SCSI_READ16(&pip->sssdpi_page_length);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (i = 0; i < npages; i++) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!SES_WITHIN_PAGE(pip->sssdpi_pages + i, 1, pip,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagelen))
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock page = (ses2_diag_page_t)pip->sssdpi_pages[i];
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Skip the page we already added during the bootstrap.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (page == SES2_DIAGPAGE_SUPPORTED_PAGES)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * The end of the page list may be padded with zeros; ignore
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * them all.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (page == 0 && i > 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock break;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((np = alloc_snap_page()) == NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_all_snap_pages(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock np->ssp_num = page;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_next = np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp = np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Allocate a control page as well, if we can use it.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ses_get_pagedesc(tp, page, SES_PAGE_CTL) != NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((np = alloc_snap_page()) == NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_all_snap_pages(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (-1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock np->ssp_num = page;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock np->ssp_control = B_TRUE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_next = np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp = np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_free(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_all_snap_pages(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_node_teardown(sp->ss_root);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_free(sp->ss_nodes);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_free(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_rele_unlocked(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_target_t *tp = sp->ss_target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (--sp->ss_refcnt != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_next != NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_next->ss_prev = sp->ss_prev;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_prev != NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_prev->ss_next = sp->ss_next;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock tp->st_snapshots = sp->ss_next;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_free(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_hold(ses_target_t *tp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_t *sp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) pthread_mutex_lock(&tp->st_lock);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp = tp->st_snapshots;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_refcnt++;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) pthread_mutex_unlock(&tp->st_lock);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockvoid
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_rele(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_target_t *tp = sp->ss_target;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) pthread_mutex_lock(&tp->st_lock);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_rele_unlocked(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) pthread_mutex_unlock(&tp->st_lock);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_new(ses_target_t *tp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_t *sp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint32_t gc;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint_t retries = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_pagedesc_t *dp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t pages, pagesize, pagelen;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *scratch;
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim boolean_t simple;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((sp = ses_zalloc(sizeof (ses_snap_t))) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_target = tp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockagain:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_all_snap_pages(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pages_skel_create(sp) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_generation = (uint32_t)-1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_time = gethrtime();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim /*
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim * First check for the short enclosure status diagnostic page and
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim * determine if this is a simple subenclosure or not.
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim */
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim simple = B_FALSE;
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim if (pp->ssp_num == SES2_DIAGPAGE_SHORT_STATUS)
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim simple = B_TRUE;
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim }
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * We skip all of:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * - Control pages
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * - Pages we've already filled in
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * - Pages we don't understand (those with no descriptor)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_len > 0 || pp->ssp_control)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((dp = ses_get_pagedesc(tp, pp->ssp_num,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SES_PAGE_DIAG)) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim if (read_status_page(sp, pp->ssp_num) != 0) {
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim /*
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim * If this page is required, and this is not a simple
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim * subenclosure, then fail the entire snapshot.
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim */
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim if (dp->spd_req == SES_REQ_MANDATORY_ALL ||
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim (dp->spd_req == SES_REQ_MANDATORY_STANDARD &&
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim !simple)) {
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim ses_snap_free(sp);
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim return (NULL);
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim }
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
ac88567a7a5bb7f01cf22cf366bc9d6203e24d7aHyon Kim }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * If the generation code has changed, we don't have a valid
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * snapshot. Start over.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (dp->spd_gcoff != -1 &&
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock dp->spd_gcoff + 4 <= pp->ssp_len) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock gc = SCSI_READ32((uint8_t *)pp->ssp_page +
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock dp->spd_gcoff);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_generation == (uint32_t)-1) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_generation = gc;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock } else if (sp->ss_generation != gc) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (++retries > LIBSES_MAX_GC_RETRIES) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_error(ESES_TOOMUCHCHANGE,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "too many generation count "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "mismatches: page 0x%x gc %u "
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "previous page %u", dp->spd_gcoff,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock gc, sp->ss_generation);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_free((ses_snap_t *)sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock goto again;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * The LIBSES_TRUNCATE environment variable is a debugging tool which,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * if set, randomly truncates all pages (except
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * SES2_DIAGPAGE_SUPPORTED_PAGES). In order to be truly evil, we
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * mmap() each page with enough space after it so we can move the data
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * up to the end of a page and unmap the following page so that any
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * attempt to read past the end of the page results in a segfault.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_target->st_truncate) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagesize = PAGESIZE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Count the maximum number of pages we will need and allocate
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * the necessary space.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pages = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_control || pp->ssp_len == 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pages += (P2ROUNDUP(pp->ssp_len, pagesize) /
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagesize) + 1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((scratch = mmap(NULL, pages * pagesize,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock -1, 0)) == MAP_FAILED) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_error(ESES_NOMEM,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "failed to mmap() pages for truncation");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_free(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_control || pp->ssp_len == 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pages = P2ROUNDUP(pp->ssp_len, pagesize) / pagesize;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_mmap_base = scratch;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_mmap_len = pages * pagesize;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagelen = lrand48() % pp->ssp_len;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) memcpy(pp->ssp_mmap_base + pp->ssp_mmap_len -
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagelen, pp->ssp_page, pagelen);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_free(pp->ssp_page);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_page = pp->ssp_mmap_base + pp->ssp_mmap_len -
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagelen;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_len = pagelen;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) munmap(pp->ssp_mmap_base + pages * pagesize,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pagesize);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock scratch += (pages + 1) * pagesize;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ses_fill_snap(sp) != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_free(sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) pthread_mutex_lock(&tp->st_lock);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (tp->st_snapshots != NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_rele_unlocked(tp->st_snapshots);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_next = tp->st_snapshots;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (tp->st_snapshots != NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock tp->st_snapshots->ss_prev = sp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock tp->st_snapshots = sp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_refcnt = 2;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) pthread_mutex_unlock(&tp->st_lock);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (sp);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockint
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_do_ctl(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_snap_page_t *pp, *up;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int ret = -1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!pp->ssp_control)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pp->ssp_initialized && send_control_page(sp, pp) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock goto error;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (up = pp->ssp_unique; up != NULL; up = up->ssp_next) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (send_control_page(sp, up) != 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock goto error;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ret = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockerror:
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!pp->ssp_control)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_initialized = B_FALSE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock while ((up = pp->ssp_unique) != NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pp->ssp_unique = up->ssp_next;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free_snap_page(up);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (ret);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockuint32_t
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_snap_generation(ses_snap_t *sp)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (sp->ss_generation);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic ses_walk_action_t
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_walk_node(ses_node_t *np, ses_walk_f func, void *arg)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_walk_action_t action;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (; np != NULL; np = ses_node_sibling(np)) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock action = func(np, arg);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (action == SES_WALK_ACTION_TERMINATE)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (SES_WALK_ACTION_TERMINATE);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (action == SES_WALK_ACTION_PRUNE ||
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ses_node_child(np) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ses_walk_node(ses_node_child(np), func, arg) ==
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SES_WALK_ACTION_TERMINATE)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (SES_WALK_ACTION_TERMINATE);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (SES_WALK_ACTION_CONTINUE);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockint
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_walk(ses_snap_t *sp, ses_walk_f func, void *arg)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_walk_node(ses_root_node(sp), func, arg);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (0);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*ARGSUSED*/
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic ses_walk_action_t
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_fill_nodes(ses_node_t *np, void *unused)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock np->sn_snapshot->ss_nodes[np->sn_id] = np;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (SES_WALK_ACTION_CONTINUE);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * Given an ID returned by ses_node_id(), lookup and return the corresponding
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * node in the snapshot. If the snapshot generation count has changed, then
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * return failure.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_node_t *
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockses_node_lookup(ses_snap_t *sp, uint64_t id)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock{
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint32_t gen = (id >> 32);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint32_t idx = (id & 0xFFFFFFFF);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_generation != gen) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_set_errno(ESES_CHANGED);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (idx >= sp->ss_n_nodes) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_error(ESES_BAD_NODE,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "no such node in snapshot");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /*
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * If this is our first lookup attempt, construct the array for fast
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * lookups.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_nodes == NULL) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if ((sp->ss_nodes = ses_zalloc(
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sp->ss_n_nodes * sizeof (void *))) == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_walk(sp, ses_fill_nodes, NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (sp->ss_nodes[idx] == NULL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (void) ses_error(ESES_BAD_NODE,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "no such node in snapshot");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return (sp->ss_nodes[idx]);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}