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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <scsi/libses.h> 28 #include "ses_impl.h" 29 30 int 31 enc_parse_td(ses2_td_hdr_impl_t *tip, const char *tp, nvlist_t *nvl) 32 { 33 int nverr; 34 35 if (tp != NULL) 36 SES_NV_ADD(fixed_string, nverr, nvl, SES_PROP_CLASS_DESCRIPTION, 37 tp, tip->sthi_text_len); 38 39 return (0); 40 } 41 42 static int 43 enc_eid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) 44 { 45 int nverr; 46 47 SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_subenclosure_id); 48 49 return (0); 50 } 51 52 static int 53 enc_espid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) 54 { 55 int nverr; 56 57 SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_rel_esp_id); 58 59 return (0); 60 } 61 62 static int 63 enc_nesp(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) 64 { 65 int nverr; 66 67 SES_NV_ADD(uint64, nverr, nvl, name, tp->st_hdr.sehi_n_esps); 68 69 return (0); 70 } 71 72 static int 73 enc_lid(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) 74 { 75 nvlist_t *lid; 76 int nverr; 77 78 if ((nverr = nvlist_alloc(&lid, NV_UNIQUE_NAME, 0)) != 0) 79 return (ses_set_nverrno(nverr, NULL)); 80 81 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_INT, 82 SCSI_READ64(&tp->st_logical_id)); 83 84 switch (tp->st_logical_id.sni8i_naa) { 85 case NAA_IEEE_EXT: 86 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE, 87 NAA_IEEE_EXT); 88 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID, 89 NAA_IEEE_EXT_COMPANY_ID(&tp->st_logical_id.sni8i_ext_id)); 90 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A, 91 NAA_IEEE_EXT_VENDOR_A(&tp->st_logical_id.sni8i_ext_id)); 92 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_B, 93 NAA_IEEE_EXT_VENDOR_B(&tp->st_logical_id.sni8i_ext_id)); 94 break; 95 case NAA_IEEE_REG: 96 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_ID_TYPE, 97 NAA_IEEE_REG); 98 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_COMPANY_ID, 99 NAA_IEEE_REG_COMPANY_ID(&tp->st_logical_id.sni8i_reg_id)); 100 SES_NV_ADD_OR_FREE(uint64, nverr, lid, SPC3_NAA_VS_A, 101 NAA_IEEE_REG_VENDOR_ID(&tp->st_logical_id.sni8i_reg_id)); 102 break; 103 default: 104 break; 105 } 106 107 if ((nverr = nvlist_add_nvlist(nvl, name, lid)) != 0) { 108 nvlist_free(lid); 109 return (ses_set_nverrno(nverr, name)); 110 } 111 112 nvlist_free(lid); 113 114 return (0); 115 } 116 117 static int 118 enc_vid(const ses2_ed_impl_t *tp, nvlist_t *nvl, 119 const char *name) 120 { 121 int nverr; 122 123 SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_vendor_id); 124 125 return (0); 126 } 127 128 static int 129 enc_pid(const ses2_ed_impl_t *tp, nvlist_t *nvl, 130 const char *name) 131 { 132 int nverr; 133 134 SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_id); 135 136 return (0); 137 } 138 139 static int 140 enc_rev(const ses2_ed_impl_t *tp, nvlist_t *nvl, 141 const char *name) 142 { 143 int nverr; 144 145 SES_NV_ADD_FS_TRUNC(nverr, nvl, name, tp->st_product_revision); 146 147 return (0); 148 } 149 150 static int 151 enc_vs(const ses2_ed_impl_t *tp, nvlist_t *nvl, const char *name) 152 { 153 int nverr; 154 155 SES_NV_ADD(byte_array, nverr, nvl, name, (uchar_t *)tp->st_priv, 156 tp->st_hdr.sehi_ed_len - offsetof(ses2_ed_impl_t, st_priv[0]) + 157 offsetof(ses2_ed_impl_t, st_hdr.sehi_ed_len) + 1); 158 159 return (0); 160 } 161 162 /* LINTED - unused */ 163 static const ses2_ed_impl_t __ed = { 0 }; 164 165 #define ED_REQ_LEN(member) \ 166 (offsetof(ses2_ed_impl_t, member) - sizeof (ses2_ed_hdr_impl_t) + \ 167 sizeof (__ed.member)) 168 169 static const struct config_member { 170 const char *name; 171 size_t minsz; 172 int (*func)(const ses2_ed_impl_t *, nvlist_t *, const char *); 173 } config_members[] = { 174 { SES_EN_PROP_EID, 0, enc_eid }, 175 { SES_EN_PROP_ESPID, 0, enc_espid }, 176 { SES_EN_PROP_NESP, 0, enc_nesp }, 177 { SES_EN_PROP_LID, ED_REQ_LEN(st_logical_id), enc_lid }, 178 { SES_EN_PROP_VID, ED_REQ_LEN(st_vendor_id), enc_vid }, 179 { SES_EN_PROP_PID, ED_REQ_LEN(st_product_id), enc_pid }, 180 { SES_EN_PROP_REV, ED_REQ_LEN(st_product_revision), enc_rev }, 181 { SES_EN_PROP_VS, ED_REQ_LEN(st_priv), enc_vs }, 182 { NULL, 0, NULL } 183 }; 184 185 int 186 enc_parse_ed(ses2_ed_impl_t *tp, nvlist_t *nvl) 187 { 188 const struct config_member *mp; 189 int err; 190 191 if (tp == NULL) 192 return (0); 193 194 for (mp = &config_members[0]; mp->name != NULL; mp++) { 195 if (mp->func != NULL && tp->st_hdr.sehi_ed_len >= mp->minsz) { 196 err = mp->func(tp, nvl, mp->name); 197 if (err != 0) 198 return (err); 199 } 200 } 201 202 return (0); 203 } 204 205 ses_target_t * 206 ses_open_scsi(uint_t version, libscsi_target_t *stp) 207 { 208 ses_target_t *tp; 209 ses_snap_t *sp; 210 211 if (version != LIBSES_VERSION) { 212 (void) ses_set_errno(ESES_VERSION); 213 return (NULL); 214 } 215 216 if ((tp = ses_zalloc(sizeof (ses_target_t))) == NULL) 217 return (NULL); 218 219 tp->st_target = stp; 220 tp->st_scsi_hdl = libscsi_get_handle(stp); 221 tp->st_truncate = (getenv("LIBSES_TRUNCATE") != NULL); 222 if (tp->st_truncate) 223 srand48(gethrtime()); 224 225 (void) pthread_mutex_init(&tp->st_lock, NULL); 226 227 if (ses_plugin_load(tp) != 0) { 228 ses_close(tp); 229 return (NULL); 230 } 231 232 if ((sp = ses_snap_new(tp)) == NULL) { 233 ses_close(tp); 234 return (NULL); 235 } 236 237 ses_snap_rele(sp); 238 239 return (tp); 240 } 241 242 ses_target_t * 243 ses_open(uint_t version, const char *target) 244 { 245 ses_target_t *tp; 246 libscsi_errno_t serr; 247 libscsi_target_t *stp; 248 libscsi_hdl_t *hp; 249 250 if ((hp = libscsi_init(LIBSCSI_VERSION, &serr)) == NULL) { 251 (void) ses_error(ESES_LIBSCSI, "failed to initialize " 252 "libscsi: %s", libscsi_strerror(serr)); 253 return (NULL); 254 } 255 256 if ((stp = libscsi_open(hp, NULL, target)) == NULL) { 257 (void) ses_libscsi_error(hp, "failed to open SES target"); 258 libscsi_fini(hp); 259 return (NULL); 260 } 261 262 if ((tp = ses_open_scsi(version, stp)) == NULL) { 263 libscsi_close(hp, stp); 264 libscsi_fini(hp); 265 return (NULL); 266 } 267 268 tp->st_closescsi = B_TRUE; 269 270 return (tp); 271 } 272 273 libscsi_target_t * 274 ses_scsi_target(ses_target_t *tp) 275 { 276 return (tp->st_target); 277 } 278 279 void 280 ses_close(ses_target_t *tp) 281 { 282 if (tp->st_snapshots != NULL) 283 ses_snap_rele(tp->st_snapshots); 284 if (tp->st_snapshots != NULL) 285 ses_panic("attempt to close SES target with active snapshots"); 286 ses_plugin_unload(tp); 287 if (tp->st_closescsi) { 288 libscsi_close(tp->st_scsi_hdl, tp->st_target); 289 libscsi_fini(tp->st_scsi_hdl); 290 } 291 ses_free(tp); 292 } 293