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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <sys/scsi/generic/commands.h>
28 #include <sys/scsi/impl/spc3_types.h>
29
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <alloca.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <dlfcn.h>
38
39 #include <scsi/libscsi.h>
40 #include "libscsi_impl.h"
41
42 int
43 libscsi_assert(const char *expr, const char *file, int line)
44 {
45 char *msg;
46 size_t len;
47
48 len = snprintf(NULL, 0,
49 "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
50
51 msg = alloca(len + 1);
52
53 (void) snprintf(msg, len + 1,
54 "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
55
56 (void) write(STDERR_FILENO, msg, strlen(msg));
57
58 abort();
59 _exit(1);
281 buf[len] = '\0';
282
283 return (libscsi_strdup(hp, buf));
284 }
285
286 /*
287 * As part of basic initialization, we always retrieve the INQUIRY information
288 * to have the vendor/product/revision information available for all consumers.
289 */
290 int
291 libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp)
292 {
293 libscsi_action_t *ap;
294 spc3_inquiry_cdb_t *cp;
295 spc3_inquiry_data_t data;
296 size_t len;
297
298 if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
299 LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
300 offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
301 return (-1);
302
303 cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
304
305 SCSI_WRITE16(&cp->ic_allocation_length,
306 offsetof(spc3_inquiry_data_t, id_vs_36[0]));
307
308 if (libscsi_exec(ap, tp) != 0 ||
309 libscsi_action_get_status(ap) != 0) {
310 libscsi_action_free(ap);
311 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
312 }
313
314 (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
315 libscsi_action_free(ap);
316
317 if (len < offsetof(spc3_inquiry_data_t, id_vs_36))
318 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
319
320 if ((tp->lst_vendor = libscsi_process_inquiry_string(hp,
321 data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL ||
322 (tp->lst_product = libscsi_process_inquiry_string(hp,
323 data.id_product_id, sizeof (data.id_product_id))) == NULL ||
324 (tp->lst_revision = libscsi_process_inquiry_string(hp,
325 data.id_product_revision,
326 sizeof (data.id_product_revision))) == NULL) {
327 return (-1);
328 }
329
330 return (0);
331 }
332
333 const char *
334 libscsi_vendor(libscsi_target_t *tp)
335 {
336 return (tp->lst_vendor);
337 }
338
339 const char *
340 libscsi_product(libscsi_target_t *tp)
341 {
342 return (tp->lst_product);
343 }
344
345 const char *
346 libscsi_revision(libscsi_target_t *tp)
347 {
348 return (tp->lst_revision);
349 }
|
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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/types.h>
28 #include <sys/scsi/generic/commands.h>
29 #include <sys/scsi/impl/spc3_types.h>
30
31 #include <stddef.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <alloca.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <dlfcn.h>
39
40 #include <scsi/libscsi.h>
41 #include <sys/byteorder.h>
42 #include "libscsi_impl.h"
43
44 int
45 libscsi_assert(const char *expr, const char *file, int line)
46 {
47 char *msg;
48 size_t len;
49
50 len = snprintf(NULL, 0,
51 "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
52
53 msg = alloca(len + 1);
54
55 (void) snprintf(msg, len + 1,
56 "ABORT: \"%s\", line %d: assertion failed: %s\n", file, line, expr);
57
58 (void) write(STDERR_FILENO, msg, strlen(msg));
59
60 abort();
61 _exit(1);
283 buf[len] = '\0';
284
285 return (libscsi_strdup(hp, buf));
286 }
287
288 /*
289 * As part of basic initialization, we always retrieve the INQUIRY information
290 * to have the vendor/product/revision information available for all consumers.
291 */
292 int
293 libscsi_get_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp)
294 {
295 libscsi_action_t *ap;
296 spc3_inquiry_cdb_t *cp;
297 spc3_inquiry_data_t data;
298 size_t len;
299
300 if ((ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
301 LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE, &data,
302 offsetof(spc3_inquiry_data_t, id_vs_36[0]))) == NULL)
303 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
304
305 cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
306
307 SCSI_WRITE16(&cp->ic_allocation_length,
308 offsetof(spc3_inquiry_data_t, id_vs_36[0]));
309
310 if (libscsi_exec(ap, tp) != 0 ||
311 libscsi_action_get_status(ap) != 0) {
312 libscsi_action_free(ap);
313 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
314 }
315
316 (void) libscsi_action_get_buffer(ap, NULL, NULL, &len);
317 libscsi_action_free(ap);
318
319 if (len < offsetof(spc3_inquiry_data_t, id_vs_36))
320 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
321
322 if ((tp->lst_vendor = libscsi_process_inquiry_string(hp,
323 data.id_vendor_id, sizeof (data.id_vendor_id))) == NULL ||
324 (tp->lst_product = libscsi_process_inquiry_string(hp,
325 data.id_product_id, sizeof (data.id_product_id))) == NULL ||
326 (tp->lst_revision = libscsi_process_inquiry_string(hp,
327 data.id_product_revision,
328 sizeof (data.id_product_revision))) == NULL) {
329 return (libscsi_set_errno(hp, ESCSI_INQUIRY_FAILED));
330 }
331
332 return (0);
333 }
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
505 const char *
506 libscsi_vendor(libscsi_target_t *tp)
507 {
508 return (tp->lst_vendor);
509 }
510
511 const char *
512 libscsi_product(libscsi_target_t *tp)
513 {
514 return (tp->lst_product);
515 }
516
517 const char *
518 libscsi_revision(libscsi_target_t *tp)
519 {
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);
533 }
|