Print this page
NEX-7303 USN may contain garbage
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-3705 Need to update libses with LID/USN code from sesctld (lint fix)
NEX-3705 Need to update libses with LID/USN code from sesctld
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/scsi/libscsi/common/scsi_subr.c
+++ new/usr/src/lib/scsi/libscsi/common/scsi_subr.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 #include <sys/types.h>
27 28 #include <sys/scsi/generic/commands.h>
28 29 #include <sys/scsi/impl/spc3_types.h>
29 30
30 31 #include <stddef.h>
31 32 #include <stdlib.h>
32 33 #include <string.h>
33 34 #include <strings.h>
34 35 #include <alloca.h>
35 36 #include <stdio.h>
36 37 #include <unistd.h>
37 38 #include <dlfcn.h>
38 39
39 40 #include <scsi/libscsi.h>
41 +#include <sys/byteorder.h>
40 42 #include "libscsi_impl.h"
41 43
42 44 int
43 45 libscsi_assert(const char *expr, const char *file, int line)
44 46 {
45 47 char *msg;
46 48 size_t len;
47 49
48 50 len = snprintf(NULL, 0,
49 51 "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
50 52
51 53 msg = alloca(len + 1);
52 54
53 55 (void) snprintf(msg, len + 1,
54 56 "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
55 57
56 58 (void) write(STDERR_FILENO, msg, strlen(msg));
57 59
58 60 abort();
59 61 _exit(1);
60 62
61 63 /*NOTREACHED*/
62 64 return (0);
63 65 }
64 66
65 67 int
66 68 libscsi_set_errno(libscsi_hdl_t *hp, libscsi_errno_t err)
67 69 {
68 70 hp->lsh_errno = err;
69 71 hp->lsh_errmsg[0] = '\0';
70 72
71 73 return (-1);
72 74 }
73 75
74 76 /*
75 77 * Internal routine for setting both _ue_errno and _ue_errmsg. We save
76 78 * and restore the UNIX errno across this routing so the caller can use either
77 79 * libscsi_set_errno(), libscsi_error(), or libscsi_verror() without this value
78 80 * changing.
79 81 */
80 82 int
81 83 libscsi_verror(libscsi_hdl_t *hp, libscsi_errno_t err, const char *fmt,
82 84 va_list ap)
83 85 {
84 86 size_t n;
85 87 char *errmsg;
86 88
87 89 /*
88 90 * To allow the existing error message to itself be used in an error
89 91 * message, we put the new error message into a buffer on the stack,
90 92 * and then copy it into lsh_errmsg. We also need to set the errno,
91 93 * but because the call to libscsi_set_errno() is destructive to
92 94 * lsh_errmsg, we do this after we print into our temporary buffer
93 95 * (in case _libscsi_errmsg is part of the error message) and before we
94 96 * copy the temporary buffer on to _libscsi_errmsg (to prevent our new
95 97 * message from being nuked by the call to libscsi_set_errno()).
96 98 */
97 99 errmsg = alloca(sizeof (hp->lsh_errmsg));
98 100 (void) vsnprintf(errmsg, sizeof (hp->lsh_errmsg), fmt, ap);
99 101 (void) libscsi_set_errno(hp, err);
100 102
101 103 n = strlen(errmsg);
102 104
103 105 if (n != 0 && errmsg[n - 1] == '\n')
104 106 errmsg[n - 1] = '\0';
105 107
106 108 bcopy(errmsg, hp->lsh_errmsg, n + 1);
107 109
108 110 return (-1);
109 111 }
110 112
111 113 /*PRINTFLIKE3*/
112 114 int
113 115 libscsi_error(libscsi_hdl_t *hp, libscsi_errno_t err, const char *fmt, ...)
114 116 {
115 117 va_list ap;
116 118
117 119 if (fmt == NULL)
118 120 return (libscsi_set_errno(hp, err));
119 121
120 122 va_start(ap, fmt);
121 123 err = libscsi_verror(hp, err, fmt, ap);
122 124 va_end(ap);
123 125
124 126 return (err);
125 127 }
126 128
127 129 libscsi_errno_t
128 130 libscsi_errno(libscsi_hdl_t *hp)
129 131 {
130 132 return (hp->lsh_errno);
131 133 }
132 134
133 135 const char *
134 136 libscsi_errmsg(libscsi_hdl_t *hp)
135 137 {
136 138 if (hp->lsh_errmsg[0] == '\0')
137 139 (void) strlcpy(hp->lsh_errmsg, libscsi_strerror(hp->lsh_errno),
138 140 sizeof (hp->lsh_errmsg));
139 141
140 142 return (hp->lsh_errmsg);
141 143 }
142 144
143 145 void *
144 146 libscsi_alloc(libscsi_hdl_t *hp, size_t size)
145 147 {
146 148 void *mem;
147 149
148 150 if (size == 0) {
149 151 (void) libscsi_set_errno(hp, ESCSI_ZERO_LENGTH);
150 152 return (NULL);
151 153 }
152 154
153 155 if ((mem = malloc(size)) == NULL)
154 156 (void) libscsi_set_errno(hp, ESCSI_NOMEM);
155 157
156 158 return (mem);
157 159 }
158 160
159 161 void *
160 162 libscsi_zalloc(libscsi_hdl_t *hp, size_t size)
161 163 {
162 164 void *mem;
163 165
164 166 if ((mem = libscsi_alloc(hp, size)) == NULL)
165 167 return (NULL);
166 168
167 169 bzero(mem, size);
168 170
169 171 return (mem);
170 172 }
171 173
172 174 char *
173 175 libscsi_strdup(libscsi_hdl_t *hp, const char *str)
174 176 {
175 177 size_t len = strlen(str);
176 178 char *dup = libscsi_alloc(hp, len + 1);
177 179
178 180 if (dup == NULL)
179 181 return (NULL);
180 182
181 183 return (strcpy(dup, str));
182 184 }
183 185
184 186 /*ARGSUSED*/
185 187 void
186 188 libscsi_free(libscsi_hdl_t *hp, void *ptr)
187 189 {
188 190 free(ptr);
189 191 }
190 192
191 193 libscsi_hdl_t *
192 194 libscsi_init(uint_t version, libscsi_errno_t *errp)
193 195 {
194 196 libscsi_hdl_t *hp;
195 197
196 198 if ((hp = malloc(sizeof (libscsi_hdl_t))) == NULL) {
197 199 if (errp != NULL)
198 200 *errp = ESCSI_NOMEM;
199 201 return (NULL);
200 202 }
201 203
202 204 bzero(hp, sizeof (libscsi_hdl_t));
203 205 hp->lsh_version = version;
204 206
205 207 return (hp);
206 208 }
207 209
208 210 void
209 211 libscsi_fini(libscsi_hdl_t *hp)
210 212 {
211 213 libscsi_engine_impl_t *eip, *neip;
212 214
213 215 if (hp == NULL)
214 216 return;
215 217
216 218 ASSERT(hp->lsh_targets == 0);
217 219
218 220 for (eip = hp->lsh_engines; eip != NULL; eip = neip) {
219 221 neip = eip->lsei_next;
220 222 (void) dlclose(eip->lsei_dl_hdl);
221 223 libscsi_free(hp, eip);
222 224 }
223 225
224 226 free(hp);
225 227 }
226 228
227 229 size_t
228 230 libscsi_cmd_cdblen(libscsi_hdl_t *hp, uint8_t cmd)
229 231 {
230 232 size_t sz;
231 233
232 234 switch (CDB_GROUPID(cmd)) {
233 235 case CDB_GROUPID_0:
234 236 sz = CDB_GROUP0;
235 237 break;
236 238 case CDB_GROUPID_1:
237 239 sz = CDB_GROUP1;
238 240 break;
239 241 case CDB_GROUPID_2:
240 242 sz = CDB_GROUP2;
241 243 break;
242 244 case CDB_GROUPID_3:
243 245 sz = CDB_GROUP3;
244 246 break;
245 247 case CDB_GROUPID_4:
246 248 sz = CDB_GROUP4;
247 249 break;
248 250 case CDB_GROUPID_5:
249 251 sz = CDB_GROUP5;
250 252 break;
251 253 case CDB_GROUPID_6:
252 254 sz = CDB_GROUP6;
253 255 break;
254 256 case CDB_GROUPID_7:
255 257 sz = CDB_GROUP7;
256 258 break;
257 259 default:
258 260 sz = 0;
259 261 }
260 262
261 263 if (sz == 0)
262 264 (void) libscsi_error(hp, ESCSI_BADCMD,
263 265 "unknown or unsupported command %u", cmd);
264 266
265 267 return (sz);
266 268 }
267 269
268 270 static char *
269 271 libscsi_process_inquiry_string(libscsi_hdl_t *hp, const char *raw, size_t len)
270 272 {
271 273 char *buf;
272 274
273 275 buf = alloca(len + 1);
274 276 bcopy(raw, buf, len);
275 277
276 278 for (; len > 0; len--) {
277 279 if (buf[len - 1] != ' ')
278 280 break;
279 281 }
280 282
281 283 buf[len] = '\0';
282 284
283 285 return (libscsi_strdup(hp, buf));
284 286 }
285 287
286 288 /*
287 289 * As part of basic initialization, we always retrieve the INQUIRY information
288 290 * to have the vendor/product/revision information available for all consumers.
289 291 */
290 292 int
|
↓ open down ↓ |
241 lines elided |
↑ open up ↑ |
291 293 libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp)
292 294 {
293 295 libscsi_action_t *ap;
294 296 spc3_inquiry_cdb_t *cp;
295 297 spc3_inquiry_data_t data;
296 298 size_t len;
297 299
298 300 if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
299 301 LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
300 302 offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
301 - return (-1);
303 + return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
302 304
303 305 cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
304 306
305 307 SCSI_WRITE16(&cp->ic_allocation_length,
306 308 offsetof(spc3_inquiry_data_t, id_vs_36[0]));
307 309
308 310 if (libscsi_exec(ap, tp) != 0 ||
309 311 libscsi_action_get_status(ap) != 0) {
310 312 libscsi_action_free(ap);
311 313 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
312 314 }
313 315
314 316 (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
315 317 libscsi_action_free(ap);
316 318
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
317 319 if (len < offsetof(spc3_inquiry_data_t, id_vs_36))
318 320 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
319 321
320 322 if ((tp->lst_vendor = libscsi_process_inquiry_string(hp,
321 323 data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL ||
322 324 (tp->lst_product = libscsi_process_inquiry_string(hp,
323 325 data.id_product_id, sizeof (data.id_product_id))) == NULL ||
324 326 (tp->lst_revision = libscsi_process_inquiry_string(hp,
325 327 data.id_product_revision,
326 328 sizeof (data.id_product_revision))) == NULL) {
327 - return (-1);
329 + return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
328 330 }
329 331
330 332 return (0);
331 333 }
332 334
335 +/*
336 + * A designation descriptor consists of the header followed by data.
337 + * When given a pointer to the header to get to next descriptor we need to add
338 + * to hdr pointer the number of data bytes plus size of the header itself.
339 + */
340 +#define NEXT_DESC(hdr, data_len, hdr_type) ((hdr_type *)((((uint8_t *)hdr) + \
341 + data_len + sizeof (hdr_type))))
342 +
343 +int
344 +libscsi_get_inquiry_dev_id(libscsi_hdl_t *hp, libscsi_target_t *tp)
345 +{
346 + libscsi_action_t *ap;
347 + spc3_inquiry_cdb_t *cp;
348 + spc3_dev_id_vpd_page_impl_t data;
349 + size_t len;
350 + int des_bytes_left;
351 + struct vpd_desc *cur_desc;
352 + char lid[17];
353 +
354 + if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
355 + LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
356 + sizeof (spc3_dev_id_vpd_page_impl_t))) == NULL)
357 + return (libscsi_set_errno(hp, ESCSI_NOMEM));
358 +
359 + cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
360 + cp->ic_evpd = 1; /* return vital product data for bellow page code */
361 + cp->ic_page_code = DEV_ID_VPD_PAGE_CODE;
362 + SCSI_WRITE16(&cp->ic_allocation_length,
363 + sizeof (spc3_dev_id_vpd_page_impl_t));
364 +
365 + if (libscsi_exec(ap, tp) != 0 ||
366 + libscsi_action_get_status(ap) != 0) {
367 + libscsi_action_free(ap);
368 + return (libscsi_set_errno(hp, ESCSI_IO));
369 + }
370 +
371 + (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
372 + libscsi_action_free(ap);
373 +
374 + /* make sure we at least got the header */
375 + if (len < offsetof(spc3_dev_id_vpd_page_impl_t, divpi_descrs[0]))
376 + return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
377 +
378 + /* make sure we got the page we asked for */
379 + if (data.divpi_hdr.page_code != DEV_ID_VPD_PAGE_CODE)
380 + return (libscsi_set_errno(hp, ESCSI_IO));
381 +
382 + /* check for page truncation */
383 + len = ((data.divpi_hdr.page_len)[0] << 8 |
384 + (data.divpi_hdr.page_len)[1]);
385 + if (len > sizeof (data.divpi_descrs))
386 + return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
387 +
388 + /* get the first descriptor */
389 + cur_desc = (struct vpd_desc *)(data.divpi_descrs);
390 + /* iterate over descriptors looking for the one we need */
391 + des_bytes_left = len;
392 + for (; des_bytes_left > sizeof (struct vpd_desc);
393 + des_bytes_left -= (sizeof (struct vpd_desc) + cur_desc->len),
394 + cur_desc = NEXT_DESC(cur_desc, cur_desc->len, struct vpd_desc)) {
395 +
396 + /*
397 + * Len for the NAA IEEE designators is 12 (aka 0x08).
398 + * Designator type (id_type) 3 means a NAA formatted
399 + * designator.
400 + * Code set for the NAA IEEE designators is 1 (binary format).
401 + * Association 0 means this designator is for a Logical Unit.
402 + * Association 2 means this designator is for a SCSI device
403 + * that contains the Logical Unit.
404 + * With the ASSOCIATION field set to 0 or 2, device shall
405 + * return the same descriptor when it is accessed through any
406 + * other I_T nexus. See SPC4 7.8.6.1
407 + */
408 + if (cur_desc->len == 0x08 && cur_desc->id_type == 0x3 &&
409 + cur_desc->code_set == 0x1 &&
410 + (cur_desc->association == 0x0 ||
411 + cur_desc->association == 0x2)) {
412 + /* get to the data - skip the descriptor header */
413 + cur_desc = (struct vpd_desc *)(((uint8_t *)cur_desc) +
414 + sizeof (struct vpd_desc));
415 +
416 + /*
417 + * Bits 7-4 of the NAA formatted designator hold
418 + * the designator type. We're only interested
419 + * in designator type 0x5 - a 64bit value
420 + * (including this type filed) that represents a
421 + * NAA IEEE Registered designator that we use as
422 + * the LID.
423 + * See SPC4 "NAA designator format" section.
424 + */
425 + if (((*((uint8_t *)cur_desc)) & 0x50) != 0x50) {
426 + /*
427 + * This is not an IEEE Registered NAA
428 + * designator, point cur_desc back to the
429 + * header and skip this designator.
430 + */
431 + cur_desc = (struct vpd_desc * )
432 + (((uint8_t *)cur_desc) -
433 + sizeof (struct vpd_desc));
434 + continue;
435 + }
436 +
437 + /* byte swap to have LID match what libses displays */
438 + if (snprintf(lid, sizeof (lid), "%llx",
439 + BE_IN64(cur_desc)) < 0)
440 + return (libscsi_set_errno(hp, ESCSI_UNKNOWN));
441 +
442 + if ((tp->lst_lid = libscsi_process_inquiry_string(hp,
443 + lid, sizeof (lid))) == NULL)
444 + return (libscsi_set_errno(hp, ESCSI_NOMEM));
445 +
446 + return (0);
447 + }
448 + }
449 +
450 + return (libscsi_set_errno(hp, ESCSI_NOTSUP));
451 +}
452 +
453 +/*
454 + * Execute inquiry for VPD page 0x80 (unit serial #) and extract the USN
455 + */
456 +int
457 +libscsi_get_inquiry_usn(libscsi_hdl_t *hp, libscsi_target_t *tp)
458 +{
459 + libscsi_action_t *ap;
460 + spc3_inquiry_cdb_t *cp;
461 + spc3_usn_vpd_page_impl_t data;
462 + size_t len;
463 +
464 + if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
465 + LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
466 + sizeof (spc3_usn_vpd_page_impl_t))) == NULL)
467 + return (libscsi_set_errno(hp, ESCSI_NOMEM));
468 +
469 + cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
470 + cp->ic_evpd = 1; /* return vital product data for bellow page code */
471 + cp->ic_page_code = USN_VPD_PAGE_CODE;
472 + SCSI_WRITE16(&cp->ic_allocation_length,
473 + sizeof (spc3_usn_vpd_page_impl_t));
474 +
475 + if (libscsi_exec(ap, tp) != 0 ||
476 + libscsi_action_get_status(ap) != 0) {
477 + libscsi_action_free(ap);
478 + return (libscsi_set_errno(hp, ESCSI_IO));
479 + }
480 +
481 + (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
482 + libscsi_action_free(ap);
483 +
484 + /* make sure we at least got the header */
485 + if (len < offsetof(spc3_usn_vpd_page_impl_t, uvpi_usn[0]))
486 + return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
487 +
488 + /* make sure we got the page we asked for */
489 + if (data.uvpi_hdr.page_code != USN_VPD_PAGE_CODE)
490 + return (libscsi_set_errno(hp, ESCSI_IO));
491 +
492 + /* check for USN truncation */
493 + len = ((data.uvpi_hdr.page_len)[0] << 8 | (data.uvpi_hdr.page_len)[1]);
494 + if (len == 0 || len > sizeof (data.uvpi_usn))
495 + return (libscsi_set_errno(hp, ESCSI_BADLENGTH));
496 +
497 + /* USN is ASCII encoded */
498 + if ((tp->lst_usn = libscsi_process_inquiry_string(hp,
499 + (char *)data.uvpi_usn, len)) == NULL)
500 + return (libscsi_set_errno(hp, ESCSI_NOMEM));
501 +
502 + return (0);
503 +}
504 +
333 505 const char *
334 506 libscsi_vendor(libscsi_target_t *tp)
335 507 {
336 508 return (tp->lst_vendor);
337 509 }
338 510
339 511 const char *
340 512 libscsi_product(libscsi_target_t *tp)
341 513 {
342 514 return (tp->lst_product);
343 515 }
344 516
345 517 const char *
346 518 libscsi_revision(libscsi_target_t *tp)
347 519 {
348 520 return (tp->lst_revision);
521 +}
522 +
523 +const char *
524 +libscsi_lid(libscsi_target_t *tp)
525 +{
526 + return (tp->lst_lid);
527 +}
528 +
529 +const char *
530 +libscsi_usn(libscsi_target_t *tp)
531 +{
532 + return (tp->lst_usn);
349 533 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX