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