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