2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <scsi/libses.h>
2N/A#include "ses_impl.h"
2N/A
2N/Aint
2N/Aenc_parse_td(ses2_td_hdr_impl_t *tip, const char *tp, nvlist_t *nvl)
2N/A{
2N/A int nverr;
2N/A
2N/A if (tp != NULL)
2N/A SES_NV_ADD(fixed_string, nverr, nvl, SES_PROP_CLASS_DESCRIPTION,
2N/A tp, tip->sthi_text_len);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_eid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_subenclosure_id);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_espid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_rel_esp_id);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_nesp(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_n_esps);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_lid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
2N/A{
2N/A nvlist_t *lid;
2N/A int nverr;
2N/A
2N/A if ((nverr = nvlist_alloc(&lid, NV_UNIQUE_NAME, 0)) != 0)
2N/A return (ses_set_nverrno(nverr, NULL));
2N/A
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_INT,
2N/A SCSI_READ64(&tp->st_logical_id));
2N/A
2N/A switch (tp->st_logical_id.sni8i_naa) {
2N/A case NAA_IEEE_EXT:
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE,
2N/A NAA_IEEE_EXT);
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID,
2N/A NAA_IEEE_EXT_COMPANY_ID(&tp->st_logical_id.sni8i_ext_id));
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A,
2N/A NAA_IEEE_EXT_VENDOR_A(&tp->st_logical_id.sni8i_ext_id));
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_B,
2N/A NAA_IEEE_EXT_VENDOR_B(&tp->st_logical_id.sni8i_ext_id));
2N/A break;
2N/A case NAA_IEEE_REG:
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE,
2N/A NAA_IEEE_REG);
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID,
2N/A NAA_IEEE_REG_COMPANY_ID(&tp->st_logical_id.sni8i_reg_id));
2N/A SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A,
2N/A NAA_IEEE_REG_VENDOR_ID(&tp->st_logical_id.sni8i_reg_id));
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A
2N/A if ((nverr = nvlist_add_nvlist(nvl, name, lid)) != 0) {
2N/A nvlist_free(lid);
2N/A return (ses_set_nverrno(nverr, name));
2N/A }
2N/A
2N/A nvlist_free(lid);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_vid(const ses2_ed_impl_t *tp, nvlist_t *nvl,
2N/A const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_vendor_id);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_pid(const ses2_ed_impl_t *tp, nvlist_t *nvl,
2N/A const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_id);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_rev(const ses2_ed_impl_t *tp, nvlist_t *nvl,
2N/A const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_revision);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aenc_vs(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name)
2N/A{
2N/A int nverr;
2N/A
2N/A SES_NV_ADD(byte_array, nverr, nvl, name, (uchar_t *)tp->st_priv,
2N/A tp->st_hdr.sehi_ed_len - offsetof(ses2_ed_impl_t, st_priv[0]) +
2N/A offsetof(ses2_ed_impl_t, st_hdr.sehi_ed_len) + 1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* LINTED - unused */
2N/Astatic const ses2_ed_impl_t __ed = { 0 };
2N/A
2N/A#define ED_REQ_LEN(member) \
2N/A (offsetof(ses2_ed_impl_t, member) - sizeof (ses2_ed_hdr_impl_t) + \
2N/A sizeof (__ed.member))
2N/A
2N/Astatic const struct config_member {
2N/A const char *name;
2N/A size_t minsz;
2N/A int (*func)(const ses2_ed_impl_t *, nvlist_t *, const char *);
2N/A} config_members[] = {
2N/A { SES_EN_PROP_EID, 0, enc_eid },
2N/A { SES_EN_PROP_ESPID, 0, enc_espid },
2N/A { SES_EN_PROP_NESP, 0, enc_nesp },
2N/A { SES_EN_PROP_LID, ED_REQ_LEN(st_logical_id), enc_lid },
2N/A { SES_EN_PROP_VID, ED_REQ_LEN(st_vendor_id), enc_vid },
2N/A { SES_EN_PROP_PID, ED_REQ_LEN(st_product_id), enc_pid },
2N/A { SES_EN_PROP_REV, ED_REQ_LEN(st_product_revision), enc_rev },
2N/A { SES_EN_PROP_VS, ED_REQ_LEN(st_priv), enc_vs },
2N/A { NULL, 0, NULL }
2N/A};
2N/A
2N/Aint
2N/Aenc_parse_ed(ses2_ed_impl_t *tp, nvlist_t *nvl)
2N/A{
2N/A const struct config_member *mp;
2N/A int err;
2N/A
2N/A if (tp == NULL)
2N/A return (0);
2N/A
2N/A for (mp = &config_members[0]; mp->name != NULL; mp++) {
2N/A if (mp->func != NULL && tp->st_hdr.sehi_ed_len >= mp->minsz) {
2N/A err = mp->func(tp, nvl, mp->name);
2N/A if (err != 0)
2N/A return (err);
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Ases_target_t *
2N/Ases_open_scsi(uint_t version, libscsi_target_t *stp)
2N/A{
2N/A ses_target_t *tp;
2N/A ses_snap_t *sp;
2N/A
2N/A if (version != LIBSES_VERSION) {
2N/A (void) ses_set_errno(ESES_VERSION);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((tp = ses_zalloc(sizeof (ses_target_t))) == NULL)
2N/A return (NULL);
2N/A
2N/A tp->st_target = stp;
2N/A tp->st_scsi_hdl = libscsi_get_handle(stp);
2N/A tp->st_truncate = (getenv("LIBSES_TRUNCATE") != NULL);
2N/A if (tp->st_truncate)
2N/A srand48(gethrtime());
2N/A
2N/A (void) pthread_mutex_init(&tp->st_lock, NULL);
2N/A
2N/A if (ses_plugin_load(tp) != 0) {
2N/A ses_close(tp);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((sp = ses_snap_new(tp)) == NULL) {
2N/A ses_close(tp);
2N/A return (NULL);
2N/A }
2N/A
2N/A ses_snap_rele(sp);
2N/A
2N/A return (tp);
2N/A}
2N/A
2N/Ases_target_t *
2N/Ases_open(uint_t version, const char *target)
2N/A{
2N/A ses_target_t *tp;
2N/A libscsi_errno_t serr;
2N/A libscsi_target_t *stp;
2N/A libscsi_hdl_t *hp;
2N/A
2N/A if ((hp = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) {
2N/A (void) ses_error(ESES_LIBSCSI, "failed to initialize "
2N/A "libscsi: %s", libscsi_strerror(serr));
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((stp = libscsi_open(hp, NULL, target)) == NULL) {
2N/A (void) ses_libscsi_error(hp, "failed to open SES target");
2N/A libscsi_fini(hp);
2N/A return (NULL);
2N/A }
2N/A
2N/A if ((tp = ses_open_scsi(version, stp)) == NULL) {
2N/A libscsi_close(hp, stp);
2N/A libscsi_fini(hp);
2N/A return (NULL);
2N/A }
2N/A
2N/A tp->st_closescsi = B_TRUE;
2N/A
2N/A return (tp);
2N/A}
2N/A
2N/Alibscsi_target_t *
2N/Ases_scsi_target(ses_target_t *tp)
2N/A{
2N/A return (tp->st_target);
2N/A}
2N/A
2N/Avoid
2N/Ases_close(ses_target_t *tp)
2N/A{
2N/A if (tp->st_snapshots != NULL)
2N/A ses_snap_rele(tp->st_snapshots);
2N/A if (tp->st_snapshots != NULL)
2N/A ses_panic("attempt to close SES target with active snapshots");
2N/A ses_plugin_unload(tp);
2N/A if (tp->st_closescsi) {
2N/A libscsi_close(tp->st_scsi_hdl, tp->st_target);
2N/A libscsi_fini(tp->st_scsi_hdl);
2N/A }
2N/A ses_free(tp);
2N/A}