~ubuntu-branches/ubuntu/vivid/sg3-utils/vivid-proposed

« back to all changes in this revision

Viewing changes to src/sg_inq.c

  • Committer: Package Import Robot
  • Author(s): Ritesh Raj Sarraf
  • Date: 2013-06-23 16:08:01 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20130623160801-7rt7zb2dwk0ba7ut
Tags: 1.36-1
* [69e9dac] Imported Upstream version 1.36
* [cb75936] Add debian compat, level 7
* [68fed25] update README.source
* [3c724fc] Add build-dep autotools-dev
* [e4b9fdd] add destdir to install path
* [7cfff11] Simplify build with debhelper
* [f9a7540] Update symbols for 1.36 release
* [7b0b48d] Enable hardening build

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* A utility program originally written for the Linux OS SCSI subsystem.
2
 
*  Copyright (C) 2000-2011 D. Gilbert
 
2
*  Copyright (C) 2000-2013 D. Gilbert
3
3
*  This program is free software; you can redistribute it and/or modify
4
4
*  it under the terms of the GNU General Public License as published by
5
5
*  the Free Software Foundation; either version 2, or (at your option)
38
38
 
39
39
#include "sg_lib.h"
40
40
#include "sg_cmds_basic.h"
 
41
#include "sg_pt.h"
41
42
 
42
43
/* INQUIRY notes:
43
44
 * It is recommended that the initial allocation length given to a
66
67
 * information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes.
67
68
 */
68
69
 
69
 
static char * version_str = "1.03 20111113";    /* SPC-4 rev 33 */
70
 
 
71
 
 
 
70
static const char * version_str = "1.13 20130507";    /* SPC-4 rev 36 */
 
71
 
 
72
 
 
73
/* Following VPD pages are in ascending page number order */
72
74
#define VPD_SUPPORTED_VPDS 0x0
73
75
#define VPD_UNIT_SERIAL_NUM 0x80
74
76
#define VPD_DEVICE_ID  0x83
82
84
#define VPD_DEVICE_CONSTITUENTS 0x8b
83
85
#define VPD_CFA_PROFILE_INFO  0x8c
84
86
#define VPD_POWER_CONSUMPTION  0x8d
 
87
#define VPD_3PARTY_COPY  0x8f
85
88
#define VPD_PROTO_LU 0x90
86
89
#define VPD_PROTO_PORT 0x91
87
90
#define VPD_BLOCK_LIMITS 0xb0
88
91
#define VPD_BLOCK_DEV_CHARS 0xb1
89
 
#define VPD_MAN_ASS_SN 0xb1 
 
92
#define VPD_MAN_ASS_SN 0xb1
90
93
#define VPD_LB_PROVISIONING 0xb2
91
94
#define VPD_REFERRALS 0xb3
92
95
#define VPD_UPR_EMC 0xc0
105
108
#define MX_ALLOC_LEN (0xc000 + 0x80)
106
109
#define VPD_ATA_INFO_LEN  572
107
110
 
 
111
#define SENSE_BUFF_LEN  64       /* Arbitrary, could be larger */
 
112
#define INQUIRY_CMD     0x12
 
113
#define INQUIRY_CMDLEN  6
 
114
#define DEF_PT_TIMEOUT  60       /* 60 seconds */
 
115
 
108
116
 
109
117
static unsigned char rsp_buff[MX_ALLOC_LEN + 1];
110
118
static char xtra_buff[MX_ALLOC_LEN + 1];
115
123
static void decode_transport_id(const char * leadin, unsigned char * ucp,
116
124
                                int len);
117
125
 
118
 
#ifdef SG_LIB_LINUX
 
126
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
119
127
static int try_ata_identify(int ata_fd, int do_hex, int do_raw,
120
128
                            int do_verbose);
121
129
#endif
137
145
    {VPD_BLOCK_DEV_CHARS, 0, 0, 0, "bdc",
138
146
     "Block device characteristics (SBC)"},
139
147
    {VPD_BLOCK_LIMITS, 0, 0, 0, "bl", "Block limits (SBC)"},
140
 
    {VPD_REFERRALS, 0, 0, 0, "ref", "Referrals (SBC)"},
141
148
    {VPD_DEVICE_ID, 0, -1, 0, "di", "Device identification"},
142
149
#if 0
143
150
    {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, 0, "di_asis", "Like 'di' "
150
157
     "identification, target device only"},
151
158
#endif
152
159
    {VPD_EXT_INQ, 0, -1, 0, "ei", "Extended inquiry data"},
 
160
    {VPD_LB_PROVISIONING, 0, 0, 0, "lbpv", "Logical block provisioning "
 
161
     "(SBC)"},
153
162
    {VPD_MAN_NET_ADDR, 0, -1, 0, "mna", "Management network addresses"},
154
163
    {VPD_MODE_PG_POLICY, 0, -1, 0, "mpp", "Mode page policy"},
155
 
    {VPD_LB_PROVISIONING, 0, 0, 0, "lbpv", "Logical block provisioning "
156
 
     "(SBC)"},
157
164
    {VPD_POWER_CONDITION, 0, -1, 0, "po", "Power condition"},
158
165
    {VPD_POWER_CONSUMPTION, 0, -1, 0, "psm", "Power consumption"},
159
166
    {VPD_PROTO_LU, 0, 0x0, 0, "pslu", "Protocol-specific logical unit "
160
167
     "information"},
161
168
    {VPD_PROTO_PORT, 0, 0x0, 0, "pspo", "Protocol-specific port information"},
 
169
    {VPD_REFERRALS, 0, 0, 0, "ref", "Referrals (SBC)"},
162
170
    {VPD_SOFTW_INF_ID, 0, -1, 0, "sii", "Software interface identification"},
163
171
    {VPD_UNIT_SERIAL_NUM, 0, -1, 0, "sn", "Unit serial number"},
164
172
    {VPD_SCSI_PORTS, 0, -1, 0, "sp", "SCSI ports"},
165
173
    {VPD_SUPPORTED_VPDS, 0, -1, 0, "sv", "Supported VPD pages"},
166
 
    {VPD_RDAC_VAC, 0, -1, 1, "rdac_vac", "RDAC volume access control (IBM)"},
167
 
    {VPD_RDAC_VERS, 0, -1, 1, "rdac_vers", "RDAC software version (IBM)"},
 
174
    {VPD_3PARTY_COPY, 0, -1, 0, "tpc", "Third party copy"},
 
175
    /* Following are vendor specific */
 
176
    {VPD_RDAC_VAC, 0, -1, 1, "rdac_vac", "RDAC volume access control (RDAC)"},
 
177
    {VPD_RDAC_VERS, 0, -1, 1, "rdac_vers", "RDAC software version (RDAC)"},
168
178
    {VPD_UPR_EMC, 0, -1, 1, "upr", "Unit path report (EMC)"},
169
179
    {0, 0, 0, 0, NULL, NULL},
170
180
};
171
181
 
172
182
static struct option long_options[] = {
173
 
#ifdef SG_LIB_LINUX
 
183
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
174
184
        {"ata", 0, 0, 'a'},
175
185
#endif
176
186
        {"cmddt", 0, 0, 'c'},
177
187
        {"descriptors", 0, 0, 'd'},
 
188
        {"export", 0, 0, 'u'},
178
189
        {"extended", 0, 0, 'x'},
179
190
        {"help", 0, 0, 'h'},
180
191
        {"hex", 0, 0, 'H'},
181
192
        {"id", 0, 0, 'i'},
182
193
        {"len", 1, 0, 'l'},
183
194
        {"maxlen", 1, 0, 'm'},
 
195
#ifdef SG_SCSI_STRINGS
184
196
        {"new", 0, 0, 'N'},
185
197
        {"old", 0, 0, 'O'},
 
198
#endif
186
199
        {"page", 1, 0, 'p'},
187
200
        {"raw", 0, 0, 'r'},
 
201
        {"vendor", 0, 0, 's'},
188
202
        {"verbose", 0, 0, 'v'},
189
203
        {"version", 0, 0, 'V'},
190
204
        {"vpd", 0, 0, 'e'},
195
209
    int do_ata;
196
210
    int do_cmddt;
197
211
    int do_descriptors;
 
212
    int do_export;
198
213
    int do_help;
199
214
    int do_hex;
200
215
    int do_raw;
 
216
    int do_vendor;
201
217
    int do_verbose;
202
218
    int do_version;
203
219
    int do_decode;
209
225
    int p_given;
210
226
    const char * page_arg;
211
227
    const char * device_name;
 
228
#ifdef SG_SCSI_STRINGS
212
229
    int opt_new;
 
230
#endif
213
231
};
214
232
 
215
233
static void
216
234
usage()
217
235
{
218
 
#ifdef SG_LIB_LINUX
 
236
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
219
237
    fprintf(stderr,
220
 
            "Usage: sg_inq [--ata] [--cmddt] [--descriptors] [--extended] "
221
 
            "[--help] [--hex]\n"
222
 
            "              [--id] [--len=LEN] [--maxlen=LEN] [--page=PG] "
223
 
            "[--raw]\n"
224
 
            "              [--verbose] [--version] [--vpd] DEVICE\n"
 
238
            "Usage: sg_inq [--ata] [--cmddt] [--descriptors] [--export] "
 
239
            "[--extended]\n"
 
240
            "              [--help] [--hex] [--id] [--len=LEN] "
 
241
            "[--maxlen=LEN]\n"
 
242
            "              [--page=PG] [--raw] [--vendor] [--verbose] "
 
243
            "[--version]\n"
 
244
            "              [--vpd] DEVICE\n"
225
245
            "  where:\n"
226
246
            "    --ata|-a        treat DEVICE as (directly attached) ATA "
227
247
            "device\n");
228
248
#else
229
249
    fprintf(stderr,
230
 
            "Usage: sg_inq [--cmddt] [--descriptors] [--extended] [--help] "
231
 
            "[--hex] [--id]\n"
232
 
            "              [--len=LEN] [--maxlen=LEN] [--page=PG] [--raw] "
233
 
            "[--verbose]\n"
234
 
            "              [--version] [--vpd] DEVICE\n"
 
250
            "Usage: sg_inq [--cmddt] [--descriptors] [--export] [--extended] "
 
251
            "[--help]\n"
 
252
            "              [--hex] [--id] [--len=LEN] [--maxlen=LEN] "
 
253
            "[--page=PG]\n"
 
254
            "              [--raw] [--verbose] [--version] [--vpd] DEVICE\n"
235
255
            "  where:\n");
236
256
#endif
237
257
    fprintf(stderr,
240
260
            "                    use twice for list of supported "
241
261
            "commands; obsolete\n"
242
262
            "    --descriptors|-d    fetch and decode version descriptors\n"
 
263
            "    --export|-u     SCSI_IDENT_<assoc>_<type>=<ident> output "
 
264
            "format.\n"
 
265
            "                    Defaults to device id page (0x83) if --page "
 
266
            "not given,\n"
 
267
            "                    only supported for VPD pages 0x80 and 0x83\n"
243
268
            "    --extended|-E|-x    decode extended INQUIRY data VPD page "
244
269
            "(0x86)\n"
245
270
            "    --help|-h       print usage message then exit\n"
256
281
            "                        abbreviation (opcode number if "
257
282
            "'--cmddt' given)\n"
258
283
            "    --raw|-r        output response in binary (to stdout)\n"
 
284
            "    --vendor|-s     show vendor specific fields in std "
 
285
            "inquiry\n"
259
286
            "    --verbose|-v    increase verbosity\n"
260
287
            "    --version|-V    print version string then exit\n"
261
288
            "    --vpd|-e        vital product data (set page with "
266
293
            "utility has a more up to date list of VPD pages.\n");
267
294
}
268
295
 
 
296
#ifdef SG_SCSI_STRINGS
269
297
static void
270
298
usage_old()
271
299
{
291
319
            "  where:\n"
292
320
            "    -a    decode ATA information VPD page (0x89)\n");
293
321
 
294
 
#endif
 
322
#endif  /* SG_LIB_LINUX */
295
323
    fprintf(stderr,
296
324
            "    -b    decode Block limits VPD page (0xb0) (SBC)\n"
297
325
            "    -c    set CmdDt mode (use -o for opcode) [obsolete]\n"
330
358
        usage_old();
331
359
}
332
360
 
 
361
#else  /* SG_SCSI_STRINGS */
 
362
 
 
363
static void
 
364
usage_for(const struct opts_t * optsp)
 
365
{
 
366
    optsp = optsp;
 
367
    usage();
 
368
}
 
369
 
 
370
#endif /* SG_SCSI_STRINGS */
 
371
 
333
372
/* Processes command line options according to new option format. Returns
334
373
 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
335
374
static int
341
380
        int option_index = 0;
342
381
 
343
382
#ifdef SG_LIB_LINUX
344
 
        c = getopt_long(argc, argv, "acdeEhHil:m:NOp:rvVx", long_options,
345
 
                        &option_index);
346
 
#else
347
 
        c = getopt_long(argc, argv, "cdeEhHil:m:NOp:rvVx", long_options,
348
 
                        &option_index);
349
 
#endif
 
383
#ifdef SG_SCSI_STRINGS
 
384
        c = getopt_long(argc, argv, "acdeEhHil:m:NOp:rsuvVx", long_options,
 
385
                        &option_index);
 
386
#else
 
387
        c = getopt_long(argc, argv, "cdeEhHil:m:p:rsuvVx", long_options,
 
388
                        &option_index);
 
389
#endif /* SG_SCSI_STRINGS */
 
390
#else  /* SG_LIB_LINUX */
 
391
#ifdef SG_SCSI_STRINGS
 
392
        c = getopt_long(argc, argv, "cdeEhHil:m:NOp:rsuvVx", long_options,
 
393
                        &option_index);
 
394
#else
 
395
        c = getopt_long(argc, argv, "cdeEhHil:m:p:rsuvVx", long_options,
 
396
                        &option_index);
 
397
#endif /* SG_SCSI_STRINGS */
 
398
#endif /* SG_LIB_LINUX */
350
399
        if (c == -1)
351
400
            break;
352
401
 
353
402
        switch (c) {
354
 
#ifdef SG_LIB_LINUX
 
403
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
355
404
        case 'a':
356
405
            ++optsp->do_ata;
357
406
            break;
395
444
                return SG_LIB_SYNTAX_ERROR;
396
445
            }
397
446
            optsp->resp_len = n;
 
447
#ifdef SG_SCSI_STRINGS
398
448
        case 'N':
399
449
            break;      /* ignore */
400
450
        case 'O':
401
451
            optsp->opt_new = 0;
402
452
            return 0;
 
453
#endif
403
454
        case 'p':
404
455
            optsp->page_arg = optarg;
405
456
            ++optsp->p_given;
407
458
        case 'r':
408
459
            ++optsp->do_raw;
409
460
            break;
 
461
        case 's':
 
462
            ++optsp->do_vendor;
 
463
            break;
 
464
        case 'u':
 
465
            ++optsp->do_export;
 
466
            break;
410
467
        case 'v':
411
468
            ++optsp->do_verbose;
412
469
            break;
437
494
    return 0;
438
495
}
439
496
 
 
497
#ifdef SG_SCSI_STRINGS
440
498
/* Processes command line options according to old option format. Returns
441
499
 * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */
442
500
static int
528
586
                    ++optsp->do_vpd;
529
587
                    ++optsp->num_pages;
530
588
                    break;
 
589
                case 'u':
 
590
                    ++optsp->do_export;
 
591
                    break;
531
592
                case 'v':
532
593
                    ++optsp->do_verbose;
533
594
                    break;
617
678
    return res;
618
679
}
619
680
 
 
681
#else  /* SG_SCSI_STRINGS */
 
682
 
 
683
static int
 
684
process_cl(struct opts_t * optsp, int argc, char * argv[])
 
685
{
 
686
    return process_cl_new(optsp, argc, argv);
 
687
}
 
688
 
 
689
#endif  /* SG_SCSI_STRINGS */
 
690
 
 
691
 
 
692
/* Local version of sg_ll_inquiry() [found in libsgutils] that additionally
 
693
 * passes back resid. Same return values as sg_ll_inquiry() (0 is good). */
 
694
static int
 
695
ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op, void * resp,
 
696
           int mx_resp_len, int * residp, int noisy, int verbose)
 
697
{
 
698
    int res, ret, k, sense_cat;
 
699
    unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
 
700
    unsigned char sense_b[SENSE_BUFF_LEN];
 
701
    unsigned char * up;
 
702
    struct sg_pt_base * ptvp;
 
703
 
 
704
    if (cmddt)
 
705
        inqCmdBlk[1] |= 2;
 
706
    if (evpd)
 
707
        inqCmdBlk[1] |= 1;
 
708
    inqCmdBlk[2] = (unsigned char)pg_op;
 
709
    /* 16 bit allocation length (was 8) is a recent SPC-3 addition */
 
710
    inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
 
711
    inqCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
 
712
    if (verbose) {
 
713
        fprintf(stderr, "    inquiry cdb: ");
 
714
        for (k = 0; k < INQUIRY_CMDLEN; ++k)
 
715
            fprintf(stderr, "%02x ", inqCmdBlk[k]);
 
716
        fprintf(stderr, "\n");
 
717
    }
 
718
    if (resp && (mx_resp_len > 0)) {
 
719
        up = (unsigned char *)resp;
 
720
        up[0] = 0x7f;   /* defensive prefill */
 
721
        if (mx_resp_len > 4)
 
722
            up[4] = 0;
 
723
    }
 
724
    ptvp = construct_scsi_pt_obj();
 
725
    if (NULL == ptvp) {
 
726
        fprintf(stderr, "inquiry: out of memory\n");
 
727
        return -1;
 
728
    }
 
729
    set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk));
 
730
    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
 
731
    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
 
732
    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
 
733
    ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b,
 
734
                               noisy, verbose, &sense_cat);
 
735
    if (residp)
 
736
        *residp = get_scsi_pt_resid(ptvp);
 
737
    destruct_scsi_pt_obj(ptvp);
 
738
    if (-1 == ret)
 
739
        ;
 
740
    else if (-2 == ret) {
 
741
        switch (sense_cat) {
 
742
        case SG_LIB_CAT_INVALID_OP:
 
743
        case SG_LIB_CAT_ILLEGAL_REQ:
 
744
        case SG_LIB_CAT_ABORTED_COMMAND:
 
745
            ret = sense_cat;
 
746
            break;
 
747
        case SG_LIB_CAT_RECOVERED:
 
748
        case SG_LIB_CAT_NO_SENSE:
 
749
            ret = 0;
 
750
            break;
 
751
        default:
 
752
            ret = -1;
 
753
            break;
 
754
        }
 
755
    } else if (ret < 4) {
 
756
        if (verbose)
 
757
            fprintf(stderr, "inquiry: got too few bytes (%d)\n", ret);
 
758
        ret = SG_LIB_CAT_MALFORMED;
 
759
    } else
 
760
        ret = 0;
 
761
 
 
762
    return ret;
 
763
}
 
764
 
620
765
static const struct svpd_values_name_t *
621
766
sdp_find_vpd_by_acron(const char * ap)
622
767
{
650
795
        printf("%c", str[k]);
651
796
}
652
797
 
 
798
/* Strip initial and trailing whitespaces; convert one or repeated
 
799
 * whitespaces to a single "_"; convert non-printable characters to "."
 
800
 * and if there are no valid (i.e. printable) characters return 0.
 
801
 * Process 'str' in place (i.e. it's input and output) and return the
 
802
 * length of the output, excluding the trailing '\0'.
 
803
 */
 
804
static int
 
805
encode_whitespaces(unsigned char *str, int inlen)
 
806
{
 
807
    int k, res;
 
808
    int j = 0;
 
809
    int valid = 0;
 
810
    int outlen = inlen;
 
811
 
 
812
    /* Skip initial whitespaces */
 
813
    while (isblank(str[j]))
 
814
        j++;
 
815
    k = j;
 
816
    /* Strip trailing whitespaces */
 
817
    while ((outlen > k) &&
 
818
           (isblank(str[outlen - 1]) || ('\0' == str[outlen - 1]))) {
 
819
        str[outlen - 1] = '\0';
 
820
        outlen--;
 
821
    }
 
822
    for (res = 0; k < outlen; ++k) {
 
823
        if (isblank(str[k])) {
 
824
            if ((res > 0) && ('_' != str[res - 1])) {
 
825
                str[res++] = '_';
 
826
                valid++;
 
827
            }
 
828
        } else if (! isprint(str[k]))
 
829
            str[res++] = '.';
 
830
        else {
 
831
            str[res++] = str[k];
 
832
            valid++;
 
833
        }
 
834
    }
 
835
    if (! valid)
 
836
        res = 0;
 
837
    str[res] = '\0';
 
838
    return res;
 
839
}
 
840
 
 
841
static int
 
842
encode_string(char *out, const unsigned char *in, int inlen)
 
843
{
 
844
    int i, j = 0;
 
845
 
 
846
    for (i = 0; (i < inlen); ++i) {
 
847
        if (isblank(in[i]) || !isprint(in[i])) {
 
848
            sprintf(&out[j], "\\x%02x", in[i]);
 
849
            j += 4;
 
850
        } else {
 
851
            out[j] = in[i];
 
852
            j++;
 
853
        }
 
854
    }
 
855
    out[j] = '\0';
 
856
    return j;
 
857
}
 
858
 
653
859
struct vpd_name {
654
860
    int number;
655
861
    int peri_type;
656
 
    char * name;
 
862
    const char * name;
657
863
};
658
864
 
659
865
/* In numerical order */
673
879
    {VPD_DEVICE_CONSTITUENTS, 0, "Device constituents"},
674
880
    {VPD_CFA_PROFILE_INFO, 0, "CFA profile information"},       /* 0x8c */
675
881
    {VPD_POWER_CONSUMPTION, 0, "Power consumption"},            /* 0x8d */
 
882
    {VPD_3PARTY_COPY, 0, "Third party copy"},                   /* 0x8f */
676
883
    /* 0xb0 to 0xbf are per peripheral device type */
677
884
    {VPD_BLOCK_LIMITS, 0, "Block limits (sbc2)"},               /* 0xb0 */
678
885
    {VPD_BLOCK_DEV_CHARS, 0, "Block device characteristics (sbc3)"},
756
963
    "logging",
757
964
    "code download",
758
965
    "administrative configuration service",
759
 
    "reserved[0x7]", "reserved[0x8]", "reserved[0x9]",
760
 
    "reserved[0xa]", "reserved[0xb]", "reserved[0xc]", "reserved[0xd]",
761
 
    "reserved[0xe]", "reserved[0xf]", "reserved[0x10]", "reserved[0x11]",
762
 
    "reserved[0x12]", "reserved[0x13]", "reserved[0x14]", "reserved[0x15]",
763
 
    "reserved[0x16]", "reserved[0x17]", "reserved[0x18]", "reserved[0x19]",
764
 
    "reserved[0x1a]", "reserved[0x1b]", "reserved[0x1c]", "reserved[0x1d]",
765
 
    "reserved[0x1e]", "reserved[0x1f]",
 
966
    "[0x7]", "[0x8]", "[0x9]", "[0xa]", "[0xb]", "[0xc]", "[0xd]",
 
967
    "[0xe]", "[0xf]", "[0x10]", "[0x11]", "[0x12]", "[0x13]", "[0x14]",
 
968
    "[0x15]", "[0x16]", "[0x17]", "[0x18]", "[0x19]", "[0x1a]",
 
969
    "[0x1b]", "[0x1c]", "[0x1d]", "[0x1e]", "[0x1f]",
766
970
};
767
971
 
768
972
/* VPD_MAN_NET_ADDR */
897
1101
    "Binary",
898
1102
    "ASCII",
899
1103
    "UTF-8",
900
 
    "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]",
901
 
    "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]",
902
 
    "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
 
1104
    "[0x4]", "[0x5]", "[0x6]", "[0x7]", "[0x8]", "[0x9]", "[0xa]", "[0xb]",
 
1105
    "[0xc]", "[0xd]", "[0xe]", "[0xf]",
903
1106
};
904
1107
 
905
1108
static const char * desig_type_arr[] =
906
1109
{
907
 
    "vendor specific [0x0]",
908
 
    "T10 vendor identification",
909
 
    "EUI-64 based",
910
 
    "NAA",
911
 
    "Relative target port",
912
 
    "Target port group",        /* spc4r09: _primary_ target port group */
913
 
    "Logical unit group",
914
 
    "MD5 logical unit identifier",
915
 
    "SCSI name string",
916
 
    "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]",
917
 
    "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]",
 
1110
    "vendor specific [0x0]", /* SCSI_IDENT_DEVICE_VENDOR */
 
1111
    "T10 vendor identification", /* SCSI_IDENT_DEVICE_T10 */
 
1112
    "EUI-64 based", /* SCSI_IDENT_DEVICE_EUI64 */
 
1113
    "NAA", /* SCSI_IDENT_DEVICE_NAA */
 
1114
    "Relative target port", /* SCSI_IDENT_PORT_RELATIVE */
 
1115
    "Target port group", /* SCSI_IDENT_PORT_TP_GROUP */
 
1116
    "Logical unit group", /* SCSI_IDENT_PORT_LU_GROUP */
 
1117
    "MD5 logical unit identifier", /* SCSI_IDENT_DEVICE_MD5 */
 
1118
    "SCSI name string", /* SCSI_IDENT_DEVICE_SCSINAME */
 
1119
    "Protocol specific port identifier",        /* spc4r36 */
 
1120
    "[0xa]", "[0xb]", "[0xc]", "[0xd]", "[0xe]", "[0xf]",
918
1121
};
919
1122
 
920
1123
/* These are target port, device server (i.e. target) and LU identifiers */
929
1132
    const unsigned char * ip;
930
1133
    char b[64];
931
1134
 
 
1135
    if (buff[2] != 0) {
 
1136
        /*
 
1137
         * Reference the 3rd byte of the first Identification descriptor
 
1138
         * of a page 83 reply to determine whether the reply is compliant
 
1139
         * with SCSI-2 or SPC-2/3 specifications.  A zero value in the
 
1140
         * 3rd byte indicates an SPC-2/3 conformant reply ( the field is
 
1141
         * reserved ).  This byte will be non-zero for a SCSI-2
 
1142
         * conformant page 83 reply from these EMC Symmetrix models since
 
1143
         * the 7th byte of the reply corresponds to the 4th and 5th
 
1144
         * nibbles of the 6-byte OUI for EMC, that is, 0x006048.
 
1145
         */
 
1146
        i_len = len;
 
1147
        ip = ucp = buff;
 
1148
        c_set = 1;
 
1149
        assoc = 0;
 
1150
        piv = 0;
 
1151
        p_id = 0xf;
 
1152
        desig_type = 3;
 
1153
        j = 1;
 
1154
        off = 16;
 
1155
        printf("  Pre-SPC descriptor, descriptor length: %d\n", i_len);
 
1156
        goto decode;
 
1157
    }
 
1158
 
932
1159
    for (j = 1, off = -1;
933
1160
         (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0;
934
1161
         ++j) {
944
1171
            return;
945
1172
        }
946
1173
        ip = ucp + 4;
947
 
        p_id = ((ucp[0] >> 4) & 0xf);
948
 
        c_set = (ucp[0] & 0xf);
949
 
        piv = ((ucp[1] & 0x80) ? 1 : 0);
 
1174
        p_id = ((ucp[0] >> 4) & 0xf);   /* protocol identifier */
 
1175
        c_set = (ucp[0] & 0xf);         /* code set */
 
1176
        piv = ((ucp[1] & 0x80) ? 1 : 0); /* protocol identifier valid */
950
1177
        assoc = ((ucp[1] >> 4) & 0x3);
951
1178
        desig_type = (ucp[1] & 0xf);
 
1179
  decode:
952
1180
        if (piv && ((1 == assoc) || (2 == assoc)))
953
1181
            printf("    transport: %s\n",
954
1182
                   sg_get_trans_proto_str(p_id, sizeof(b), b));
974
1202
            if (k)
975
1203
                printf("      vendor specific: %.*s\n", i_len, ip);
976
1204
            else
977
 
                dStrHex((const char *)ip, i_len, 0);
 
1205
                dStrHex((const char *)ip, i_len, -1);
978
1206
            break;
979
1207
        case 1: /* T10 vendor identification */
980
1208
            printf("      vendor id: %.8s\n", ip);
985
1213
            printf("      EUI-64 based %d byte identifier\n", i_len);
986
1214
            if (1 != c_set) {
987
1215
                fprintf(stderr, "      << expected binary code_set (1)>>\n");
988
 
                dStrHex((const char *)ip, i_len, 0);
 
1216
                dStrHex((const char *)ip, i_len, -1);
989
1217
                break;
990
1218
            }
991
1219
            ci_off = 0;
1001
1229
            } else if ((8 != i_len) && (12 != i_len)) {
1002
1230
                fprintf(stderr, "      << can only decode 8, 12 and 16 "
1003
1231
                        "byte ids>>\n");
1004
 
                dStrHex((const char *)ip, i_len, 0);
 
1232
                dStrHex((const char *)ip, i_len, -1);
1005
1233
                break;
1006
1234
            }
1007
1235
            c_id = ((ip[ci_off] << 16) | (ip[ci_off + 1] << 8) |
1028
1256
        case 3: /* NAA */
1029
1257
            if (1 != c_set) {
1030
1258
                fprintf(stderr, "      << expected binary code_set (1)>>\n");
1031
 
                dStrHex((const char *)ip, i_len, 0);
 
1259
                dStrHex((const char *)ip, i_len, -1);
1032
1260
                break;
1033
1261
            }
1034
1262
            naa = (ip[0] >> 4) & 0xff;
1035
1263
            if ((naa < 2) || (naa > 6) || (4 == naa)) {
1036
1264
                fprintf(stderr, "      << unexpected naa [0x%x]>>\n", naa);
1037
 
                dStrHex((const char *)ip, i_len, 0);
 
1265
                dStrHex((const char *)ip, i_len, -1);
1038
1266
                break;
1039
1267
            }
1040
1268
            if (2 == naa) {             /* NAA IEEE Extended */
1041
1269
                if (8 != i_len) {
1042
1270
                    fprintf(stderr, "      << unexpected NAA 2 identifier "
1043
1271
                            "length: 0x%x>>\n", i_len);
1044
 
                    dStrHex((const char *)ip, i_len, 0);
 
1272
                    dStrHex((const char *)ip, i_len, -1);
1045
1273
                    break;
1046
1274
                }
1047
1275
                d_id = (((ip[0] & 0xf) << 8) | ip[1]);
1059
1287
                if (8 != i_len) {
1060
1288
                    fprintf(stderr, "      << unexpected NAA 3 identifier "
1061
1289
                            "length: 0x%x>>\n", i_len);
1062
 
                    dStrHex((const char *)ip, i_len, 0);
 
1290
                    dStrHex((const char *)ip, i_len, -1);
1063
1291
                    break;
1064
1292
                }
1065
1293
                printf("      NAA 3, Locally assigned:\n");
1071
1299
                if (8 != i_len) {
1072
1300
                    fprintf(stderr, "      << unexpected NAA 5 identifier "
1073
1301
                            "length: 0x%x>>\n", i_len);
1074
 
                    dStrHex((const char *)ip, i_len, 0);
 
1302
                    dStrHex((const char *)ip, i_len, -1);
1075
1303
                    break;
1076
1304
                }
1077
1305
                c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) |
1123
1351
            if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1124
1352
                fprintf(stderr, "      << expected binary code_set, target "
1125
1353
                        "port association, length 4>>\n");
1126
 
                dStrHex((const char *)ip, i_len, 0);
 
1354
                dStrHex((const char *)ip, i_len, -1);
1127
1355
                break;
1128
1356
            }
1129
1357
            d_id = ((ip[2] << 8) | ip[3]);
1133
1361
            if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
1134
1362
                fprintf(stderr, "      << expected binary code_set, target "
1135
1363
                        "port association, length 4>>\n");
1136
 
                dStrHex((const char *)ip, i_len, 0);
 
1364
                dStrHex((const char *)ip, i_len, -1);
1137
1365
                break;
1138
1366
            }
1139
1367
            d_id = ((ip[2] << 8) | ip[3]);
1143
1371
            if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
1144
1372
                fprintf(stderr, "      << expected binary code_set, logical "
1145
1373
                        "unit association, length 4>>\n");
1146
 
                dStrHex((const char *)ip, i_len, 0);
 
1374
                dStrHex((const char *)ip, i_len, -1);
1147
1375
                break;
1148
1376
            }
1149
1377
            d_id = ((ip[2] << 8) | ip[3]);
1153
1381
            if ((1 != c_set) || (0 != assoc)) {
1154
1382
                fprintf(stderr, "      << expected binary code_set, logical "
1155
1383
                        "unit association>>\n");
1156
 
                dStrHex((const char *)ip, i_len, 0);
 
1384
                dStrHex((const char *)ip, i_len, -1);
1157
1385
                break;
1158
1386
            }
1159
1387
            printf("      MD5 logical unit identifier:\n");
1160
 
            dStrHex((const char *)ip, i_len, 0);
 
1388
            dStrHex((const char *)ip, i_len, -1);
1161
1389
            break;
1162
1390
        case 8: /* SCSI name string */
1163
1391
            if (3 != c_set) {
1164
1392
                fprintf(stderr, "      << expected UTF-8 code_set>>\n");
1165
 
                dStrHex((const char *)ip, i_len, 0);
 
1393
                dStrHex((const char *)ip, i_len, -1);
1166
1394
                break;
1167
1395
            }
1168
1396
            printf("      SCSI name string:\n");
1172
1400
             */
1173
1401
            printf("      %s\n", (const char *)ip);
1174
1402
            break;
 
1403
        case 9: /* Protocol specific port identifier */
 
1404
            /* added in spc4r36, PIV must be set, proto_id indicates */
 
1405
            /* whether UAS (USB) or SOP (PCIe) or ... */
 
1406
            if (! piv)
 
1407
                printf("      >>>> Protocol specific port identifier "
 
1408
                       "expects protocol\n"
 
1409
                       "           identifier to be valid and it is not\n");
 
1410
            if (TPROTO_UAS == p_id) {
 
1411
                printf("      USB device address: 0x%x\n", 0x7f & ip[0]);
 
1412
                printf("      USB interface number: 0x%x\n", ip[2]);
 
1413
            } else if (TPROTO_SOP == p_id) {
 
1414
                printf("      PCIe routing ID, bus number: 0x%x\n", ip[0]);
 
1415
                printf("          function number: 0x%x\n", ip[1]);
 
1416
                printf("          [or device number: 0x%x, function number: "
 
1417
                       "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]);
 
1418
            } else
 
1419
                printf("      >>>> unexpected protocol indentifier: %s\n"
 
1420
                       "           with Protocol specific port "
 
1421
                       "identifier\n",
 
1422
                       sg_get_trans_proto_str(p_id, sizeof(b), b));
 
1423
            break;
1175
1424
        default: /* reserved */
1176
 
            dStrHex((const char *)ip, i_len, 0);
 
1425
            dStrHex((const char *)ip, i_len, -1);
1177
1426
            break;
1178
1427
        }
1179
1428
    }
1181
1430
        fprintf(stderr, "%s VPD page error: around offset=%d\n", leadin, off);
1182
1431
}
1183
1432
 
 
1433
static void
 
1434
export_dev_ids(unsigned char * buff, int len)
 
1435
{
 
1436
    int u, j, m, id_len, c_set, assoc, desig_type, i_len;
 
1437
    int off, d_id, naa, k;
 
1438
    unsigned char * ucp;
 
1439
    unsigned char * ip;
 
1440
    const char * assoc_str;
 
1441
 
 
1442
    if (buff[2] != 0) {
 
1443
        /*
 
1444
         * Cf decode_dev_ids() for details
 
1445
         */
 
1446
        i_len = len;
 
1447
        ip = buff;
 
1448
        c_set = 1;
 
1449
        assoc = 0;
 
1450
        desig_type = 3;
 
1451
        j = 1;
 
1452
        off = 16;
 
1453
        goto decode;
 
1454
    }
 
1455
 
 
1456
    for (j = 1, off = -1;
 
1457
         (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0;
 
1458
         ++j) {
 
1459
        ucp = buff + off;
 
1460
        i_len = ucp[3];
 
1461
        id_len = i_len + 4;
 
1462
        if ((off + id_len) > len) {
 
1463
            fprintf(stderr, "Device Identification VPD page error: designator "
 
1464
                    "length longer than\n     remaining response length=%d\n",
 
1465
                    (len - off));
 
1466
            return;
 
1467
        }
 
1468
        ip = ucp + 4;
 
1469
        c_set = (ucp[0] & 0xf);
 
1470
        assoc = ((ucp[1] >> 4) & 0x3);
 
1471
        desig_type = (ucp[1] & 0xf);
 
1472
  decode:
 
1473
        switch (assoc) {
 
1474
            case 0:
 
1475
                assoc_str = "LUN";
 
1476
                break;
 
1477
            case 1:
 
1478
                assoc_str = "PORT";
 
1479
                break;
 
1480
            case 2:
 
1481
                assoc_str = "TARGET";
 
1482
                break;
 
1483
            default:
 
1484
                fprintf(stderr, "    Invalid association %d\n", assoc);
 
1485
                return;
 
1486
        }
 
1487
        switch (desig_type) {
 
1488
        case 0: /* vendor specific */
 
1489
            k = 0;
 
1490
            if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */
 
1491
                k = encode_whitespaces(ip, i_len);
 
1492
                if (k >= i_len)
 
1493
                    k = 1;
 
1494
            }
 
1495
            if (k)
 
1496
                printf("SCSI_IDENT_%s_VENDOR=%.*s\n", assoc_str, k, ip);
 
1497
            break;
 
1498
        case 1: /* T10 vendor identification */
 
1499
            k = encode_whitespaces(ip, i_len);
 
1500
            printf("SCSI_IDENT_%s_T10=%.*s\n", assoc_str, k, ip);
 
1501
            break;
 
1502
        case 2: /* EUI-64 based */
 
1503
            if (1 != c_set) {
 
1504
                fprintf(stderr, "      << expected binary code_set (1)>>\n");
 
1505
                dStrHex((const char *)ip, i_len, 0);
 
1506
                break;
 
1507
            }
 
1508
            printf("SCSI_IDENT_%s_EUI64=", assoc_str);
 
1509
            for (m = 0; m < i_len; ++m)
 
1510
                printf("%02x", (unsigned int)ip[m]);
 
1511
            printf("\n");
 
1512
            break;
 
1513
        case 3: /* NAA */
 
1514
            if (1 != c_set) {
 
1515
                fprintf(stderr, "      << expected binary code_set (1)>>\n");
 
1516
                dStrHex((const char *)ip, i_len, 0);
 
1517
                break;
 
1518
            }
 
1519
            naa = (ip[0] >> 4) & 0xff;
 
1520
            if ((naa < 2) || (naa > 6) || (4 == naa)) {
 
1521
                fprintf(stderr, "      << unexpected naa [0x%x]>>\n", naa);
 
1522
                dStrHex((const char *)ip, i_len, 0);
 
1523
                break;
 
1524
            }
 
1525
            if (6 != naa) {
 
1526
                if (8 != i_len) {
 
1527
                    fprintf(stderr, "      << unexpected NAA 2 identifier "
 
1528
                            "length: 0x%x>>\n", i_len);
 
1529
                    dStrHex((const char *)ip, i_len, 0);
 
1530
                    break;
 
1531
                }
 
1532
                printf("SCSI_IDENT_%s_NAA=", assoc_str);
 
1533
                for (m = 0; m < 8; ++m)
 
1534
                    printf("%02x", (unsigned int)ip[m]);
 
1535
                printf("\n");
 
1536
            } else {      /* NAA IEEE Registered extended */
 
1537
                if (16 != i_len) {
 
1538
                    fprintf(stderr, "      << unexpected NAA 6 identifier "
 
1539
                            "length: 0x%x>>\n", i_len);
 
1540
                    dStrHex((const char *)ip, i_len, 0);
 
1541
                    break;
 
1542
                }
 
1543
                printf("SCSI_IDENT_%s_NAA=", assoc_str);
 
1544
                for (m = 0; m < 16; ++m)
 
1545
                    printf("%02x", (unsigned int)ip[m]);
 
1546
                printf("\n");
 
1547
            }
 
1548
            break;
 
1549
        case 4: /* Relative target port */
 
1550
            if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
 
1551
                fprintf(stderr, "      << expected binary code_set, target "
 
1552
                        "port association, length 4>>\n");
 
1553
                dStrHex((const char *)ip, i_len, 0);
 
1554
                break;
 
1555
            }
 
1556
            d_id = ((ip[2] << 8) | ip[3]);
 
1557
            printf("SCSI_IDENT_%s_RELATIVE=%d\n", assoc_str, d_id);
 
1558
            break;
 
1559
        case 5: /* (primary) Target port group */
 
1560
            if ((1 != c_set) || (1 != assoc) || (4 != i_len)) {
 
1561
                fprintf(stderr, "      << expected binary code_set, target "
 
1562
                        "port association, length 4>>\n");
 
1563
                dStrHex((const char *)ip, i_len, 0);
 
1564
                break;
 
1565
            }
 
1566
            d_id = ((ip[2] << 8) | ip[3]);
 
1567
            printf("SCSI_IDENT_%s_TARGET_PORT_GROUP=0x%x\n", assoc_str, d_id);
 
1568
            break;
 
1569
        case 6: /* Logical unit group */
 
1570
            if ((1 != c_set) || (0 != assoc) || (4 != i_len)) {
 
1571
                fprintf(stderr, "      << expected binary code_set, logical "
 
1572
                        "unit association, length 4>>\n");
 
1573
                dStrHex((const char *)ip, i_len, 0);
 
1574
                break;
 
1575
            }
 
1576
            d_id = ((ip[2] << 8) | ip[3]);
 
1577
            printf("SCSI_IDENT_%s_LOGICAL_UNIT_GROUP=0x%x\n", assoc_str, d_id);
 
1578
            break;
 
1579
        case 7: /* MD5 logical unit identifier */
 
1580
            if ((1 != c_set) || (0 != assoc)) {
 
1581
                fprintf(stderr, "      << expected binary code_set, logical "
 
1582
                        "unit association>>\n");
 
1583
                dStrHex((const char *)ip, i_len, 0);
 
1584
                break;
 
1585
            }
 
1586
            printf("SCSI_IDENT_%s_MD5=", assoc_str);
 
1587
            dStrHex((const char *)ip, i_len, -1);
 
1588
            break;
 
1589
        case 8: /* SCSI name string */
 
1590
            if (3 != c_set) {
 
1591
                fprintf(stderr, "      << expected UTF-8 code_set>>\n");
 
1592
                dStrHex((const char *)ip, i_len, -1);
 
1593
                break;
 
1594
            }
 
1595
            printf("SCSI_IDENT_%s_NAME=%.*s\n", assoc_str, i_len,
 
1596
                   (const char *)ip);
 
1597
            break;
 
1598
        case 9: /* PCIe Routing ID */
 
1599
            /* new in spc4r34, looks under-specified, drop through now */
 
1600
        default: /* reserved */
 
1601
            dStrHex((const char *)ip, i_len, -1);
 
1602
            break;
 
1603
        }
 
1604
    }
 
1605
    if (-2 == u)
 
1606
        fprintf(stderr, "Device identification VPD page error: "
 
1607
                "around offset=%d\n", off);
 
1608
}
 
1609
 
1184
1610
/* Transport IDs are initiator port identifiers, typically other than the
1185
 
   initiator port issuing a SCSI command. Code borrowed from sg_persist.c */
 
1611
   initiator port issuing a SCSI command. */
1186
1612
static void
1187
1613
decode_transport_id(const char * leadin, unsigned char * ucp, int len)
1188
1614
{
1204
1630
            if (0 != format_code)
1205
1631
                printf("%s  [Unexpected format code: %d]\n", leadin,
1206
1632
                       format_code);
1207
 
            dStrHex((const char *)&ucp[8], 8, 0);
 
1633
            dStrHex((const char *)&ucp[8], 8, -1);
1208
1634
            bump = 24;
1209
1635
            break;
1210
1636
        case TPROTO_SPI:
1220
1646
        case TPROTO_SSA: /* SSA */
1221
1647
            printf("%s  SSA (transport id not defined):\n", leadin);
1222
1648
            printf("%s  format code: %d\n", leadin, format_code);
1223
 
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
 
1649
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1);
1224
1650
            bump = 24;
1225
1651
            break;
1226
1652
        case TPROTO_1394:
1228
1654
            if (0 != format_code)
1229
1655
                printf("%s  [Unexpected format code: %d]\n", leadin,
1230
1656
                       format_code);
1231
 
            dStrHex((const char *)&ucp[8], 8, 0);
 
1657
            dStrHex((const char *)&ucp[8], 8, -1);
1232
1658
            bump = 24;
1233
1659
            break;
1234
1660
        case TPROTO_SRP:
1236
1662
            if (0 != format_code)
1237
1663
                printf("%s  [Unexpected format code: %d]\n", leadin,
1238
1664
                       format_code);
1239
 
            dStrHex((const char *)&ucp[8], 16, 0);
 
1665
            dStrHex((const char *)&ucp[8], 16, -1);
1240
1666
            bump = 24;
1241
1667
            break;
1242
1668
        case TPROTO_ISCSI:
1248
1674
                printf("world wide unique port id: %.*s\n", num, &ucp[4]);
1249
1675
            else {
1250
1676
                printf("  [Unexpected format code: %d]\n", format_code);
1251
 
                dStrHex((const char *)ucp, num + 4, 0);
 
1677
                dStrHex((const char *)ucp, num + 4, -1);
1252
1678
            }
1253
1679
            bump = (((num + 4) < 24) ? 24 : num + 4);
1254
1680
            break;
1268
1694
        case TPROTO_ADT:
1269
1695
            printf("%s  ADT:\n", leadin);
1270
1696
            printf("%s  format code: %d\n", leadin, format_code);
1271
 
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
 
1697
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1);
1272
1698
            bump = 24;
1273
1699
            break;
1274
1700
        case TPROTO_ATA:
1275
1701
            printf("%s  ATAPI:\n", leadin);
1276
1702
            printf("%s  format code: %d\n", leadin, format_code);
1277
 
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0);
 
1703
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1);
 
1704
            bump = 24;
 
1705
            break;
 
1706
        case TPROTO_UAS:
 
1707
            printf("%s  UAS:\n", leadin);
 
1708
            printf("%s  format code: %d\n", leadin, format_code);
 
1709
            dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1);
 
1710
            bump = 24;
 
1711
            break;
 
1712
        case TPROTO_SOP:
 
1713
            printf("%s  SOP ", leadin);
 
1714
            num = ((ucp[2] << 8) | ucp[3]);
 
1715
            if (0 == format_code)
 
1716
                printf("Routing ID: 0x%x\n", num);
 
1717
            else {
 
1718
                printf("  [Unexpected format code: %d]\n", format_code);
 
1719
                dStrHex((const char *)ucp, 24, -1);
 
1720
            }
1278
1721
            bump = 24;
1279
1722
            break;
1280
1723
        case TPROTO_NONE:
 
1724
            fprintf(stderr, "%s  No specified protocol\n", leadin);
 
1725
            /* dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0); */
 
1726
            bump = 24;
 
1727
            break;
1281
1728
        default:
1282
1729
            fprintf(stderr, "%s  unknown protocol id=0x%x  "
1283
1730
                    "format_code=%d\n", leadin, proto_id, format_code);
1319
1766
           (buff[10] << 8) + buff[11]);     /* spc4r27 */
1320
1767
    printf("  POA_SUP=%d HRA_SUP=%d VSA_SUP=%d\n",      /* spc4r32 */
1321
1768
           !!(buff[12] & 0x80), !!(buff[12] & 0x40), !!(buff[12] & 0x20));
 
1769
    printf("  Maximum supported sense data length=%d\n",
 
1770
           buff[13]); /* spc4r34 */
1322
1771
}
1323
1772
 
1324
1773
/* VPD_SOFTW_INF_ID */
1325
1774
static void
1326
1775
decode_softw_inf_id(unsigned char * buff, int len, int do_hex)
1327
1776
{
1328
 
    int k;
1329
 
 
1330
1777
    if (do_hex) {
1331
1778
        dStrHex((const char *)buff, len, 0);
1332
1779
        return;
1333
1780
    }
1334
1781
    len -= 4;
1335
1782
    buff += 4;
1336
 
    for ( ; len > 5; len -= 6, buff += 6) {
1337
 
        printf("    ");
1338
 
        for (k = 0; k < 6; ++k)
1339
 
            printf("%02x", (unsigned int)buff[k]);
1340
 
        printf("\n");
1341
 
    }
 
1783
    for ( ; len > 5; len -= 6, buff += 6)
 
1784
        printf("    IEEE Company_id: 0x%06x, vendor specific extension "
 
1785
               "id: 0x%06x\n", (buff[0] << 16) | (buff[1] << 8) | buff[2],
 
1786
               (buff[3] << 16) | (buff[4] << 8) | buff[5]);
1342
1787
}
1343
1788
 
1344
1789
/* VPD_ATA_INFO */
1460
1905
            if (len > 19) {     /* added in sbc3r09 */
1461
1906
                u = (buff[16] << 24) | (buff[17] << 16) | (buff[18] << 8) |
1462
1907
                    buff[19];
1463
 
                printf("  Maximum prefetch, xdread, xdwrite transfer length: %u "
1464
 
                       "blocks\n", u);
 
1908
                printf("  Maximum prefetch, xdread, xdwrite transfer length: "
 
1909
                       "%u blocks\n", u);
1465
1910
            }
1466
1911
            if (len > 27) {     /* added in sbc3r18 */
1467
1912
                u = ((unsigned int)buff[20] << 24) | (buff[21] << 16) |
1520
1965
                printf("  Reserved [0x%x]\n", u);
1521
1966
            else
1522
1967
                printf("  Nominal rotation rate: %d rpm\n", u);
 
1968
            printf("  Product type=%d\n", buff[6]);
 
1969
            printf("  WABEREQ=%d\n", (buff[7] >> 6) & 0x3);
 
1970
            printf("  WACEREQ=%d\n", (buff[7] >> 4) & 0x3);
 
1971
            u = buff[7] & 0xf;
 
1972
            printf("  Nominal form factor ");
 
1973
            switch(u) {
 
1974
            case 0:
 
1975
                printf("is not reported\n");
 
1976
                break;
 
1977
            case 1:
 
1978
                printf("5.25 inches\n");
 
1979
                break;
 
1980
            case 2:
 
1981
                printf("3.5 inches\n");
 
1982
                break;
 
1983
            case 3:
 
1984
                printf("2.5 inches\n");
 
1985
                break;
 
1986
            case 4:
 
1987
                printf("1.8 inches\n");
 
1988
                break;
 
1989
            case 5:
 
1990
                printf("less then 1.8 inches\n");
 
1991
                break;
 
1992
            default:
 
1993
                printf("reserved [%u]\n", u);
 
1994
                break;
 
1995
            }
 
1996
            printf("  VBULS=%d\n", buff[8] & 0x1);
1523
1997
            break;
1524
1998
        case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC:
1525
1999
            printf("  Manufacturer-assigned serial number: %.*s\n",
1545
2019
    switch (pdt) {
1546
2020
        case PDT_DISK: case PDT_WO: case PDT_OPTICAL:
1547
2021
            if (len < 0xc0) {
1548
 
                fprintf(stderr, "Referrals VPD page length too short=%d\n", len);
 
2022
                fprintf(stderr, "Referrals VPD page length too short=%d\n",
 
2023
                        len);
1549
2024
                return;
1550
2025
            }
1551
2026
            s = (buff[8] << 24) | (buff[9] << 16) | (buff[10] << 8) | buff[11];
1552
 
            m = (buff[12] << 24) | (buff[13] << 16) | (buff[14] << 8) | buff[15];
 
2027
            m = (buff[12] << 24) | (buff[13] << 16) | (buff[14] << 8) |
 
2028
                buff[15];
1553
2029
            if (0 == s)
1554
2030
                printf("  Single user data segment\n");
1555
2031
            else if (0 == m)
1556
 
                printf("  Segment size specified by user data segment descriptor\n");
 
2032
                printf("  Segment size specified by user data segment "
 
2033
                       "descriptor\n");
1557
2034
            else
1558
2035
                printf("  Segment size: %u, segment multiplier: %u\n", s, m);
1559
2036
            break;
1591
2068
    "I/O Operations being rejected, SP reboot or NDU in progress",
1592
2069
};
1593
2070
 
 
2071
static const char * failover_mode_arr[] =
 
2072
{
 
2073
    "Legacy mode 0",
 
2074
    "Unknown mode (1)",
 
2075
    "Unknown mode (2)",
 
2076
    "Unknown mode (3)",
 
2077
    "Active/Passive (PNR) mode 1",
 
2078
    "Unknown mode (5)",
 
2079
    "Active/Active (ALUA) mode 4",
 
2080
    "Unknown mode (7)",
 
2081
    "Legacy mode 2",
 
2082
    "Unknown mode (9)",
 
2083
    "Unknown mode (10)",
 
2084
    "Unknown mode (11)",
 
2085
    "Unknown mode (12)",
 
2086
    "Unknown mode (13)",
 
2087
    "AIX Active/Passive (PAR) mode 3",
 
2088
    "Unknown mode (15)",
 
2089
};
 
2090
 
1594
2091
static void
1595
2092
decode_upr_vpd_c0_emc(unsigned char * buff, int len)
1596
2093
{
1597
 
    int k, ip_mgmt, failover_mode, vpp80, lun_z;
 
2094
    int k, ip_mgmt, vpp80, lun_z;
1598
2095
 
1599
2096
    if (len < 3) {
1600
 
        fprintf(stderr, "Device identification VPD page length too "
1601
 
                "short=%d\n", len);
 
2097
        fprintf(stderr, "EMC upr VPD page [0xc0]: length too short=%d\n",
 
2098
                len);
1602
2099
        return;
1603
2100
    }
1604
2101
    if (buff[9] != 0x00) {
1650
2147
        printf("\n");
1651
2148
    }
1652
2149
 
1653
 
    failover_mode = buff[28] & 0x0f;
1654
2150
    vpp80 = buff[30] & 0x08;
1655
2151
    lun_z = buff[30] & 0x04;
1656
2152
 
1657
2153
    printf("  System Type: %x, Failover mode: %s\n",
1658
 
                   buff[27],
1659
 
                   failover_mode == 4 ? "Set to 1" : "Unknown");
 
2154
           buff[27], failover_mode_arr[buff[28] & 0x0f]);
1660
2155
 
1661
2156
    printf("  Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n",
1662
2157
                   vpp80 ? "array serial#" : "LUN serial#",
1748
2243
}
1749
2244
 
1750
2245
/* Returns 0 if Unit Serial Number VPD page contents found, else see
1751
 
   sg_ll_inquiry() */
 
2246
   sg_ll_inquiry() return values */
1752
2247
static int
1753
2248
fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose)
1754
2249
{
1813
2308
}
1814
2309
 
1815
2310
 
1816
 
/* Returns 0 if successful */
 
2311
/* Process a standard INQUIRY response. Returns 0 if successful */
1817
2312
static int
1818
2313
process_std_inq(int sg_fd, const struct opts_t * optsp)
1819
2314
{
1821
2316
    const char * cp;
1822
2317
    int vdesc_arr[8];
1823
2318
    char buff[48];
1824
 
    int verb;
 
2319
    int verb, resid;
1825
2320
 
1826
2321
    memset(vdesc_arr, 0, sizeof(vdesc_arr));
1827
2322
    rlen = (optsp->resp_len > 0) ? optsp->resp_len : SAFE_STD_INQ_RESP_LEN;
1828
2323
    verb = optsp->do_verbose;
1829
 
    res = sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, rlen, 0, verb);
 
2324
    res = ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, rlen, &resid, 0, verb);
1830
2325
    if (0 == res) {
1831
2326
        pqual = (rsp_buff[0] & 0xe0) >> 5;
1832
 
        if (! optsp->do_raw) {
 
2327
        if (! optsp->do_raw && ! optsp->do_export) {
1833
2328
            if (0 == pqual)
1834
2329
                printf("standard INQUIRY:\n");
1835
2330
            else if (1 == pqual)
1852
2347
            (0 == optsp->resp_len)) {
1853
2348
            rlen = len;
1854
2349
            memset(rsp_buff, 0, rlen);
1855
 
            if (sg_ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, rlen, 1, verb)) {
 
2350
            if (ll_inquiry(sg_fd, 0, 0, 0, rsp_buff, rlen, &resid, 1, verb)) {
1856
2351
                fprintf(stderr, "second INQUIRY (%d byte) failed\n", len);
1857
2352
                return SG_LIB_CAT_OTHER;
1858
2353
            }
1859
2354
            if (len != (rsp_buff[4] + 5)) {
1860
 
                fprintf(stderr, "strange, twin INQUIRYs yield different "
1861
 
                        "'additional lengths'\n");
 
2355
                fprintf(stderr, "strange, consecutive INQUIRYs yield "
 
2356
                        "different 'additional lengths'\n");
1862
2357
                res = SG_LIB_CAT_MALFORMED;
1863
2358
                len = rsp_buff[4] + 5;
1864
2359
            }
1867
2362
            act_len = rlen;
1868
2363
        else
1869
2364
            act_len = (rlen < len) ? rlen : len;
 
2365
        /* don't use more than HBA's resid says was transferred from LU */
 
2366
        if (act_len > (rlen - resid))
 
2367
            act_len = rlen - resid;
1870
2368
        if (optsp->do_raw)
1871
2369
            dStrRaw((const char *)rsp_buff, act_len);
1872
2370
        else if (optsp->do_hex)
1873
2371
            dStrHex((const char *)rsp_buff, act_len, 0);
1874
 
        else {
 
2372
        else if (!optsp->do_export) {
1875
2373
            printf("  PQual=%d  Device_type=%d  RMB=%d  version=0x%02x ",
1876
2374
                   pqual, peri_type, !!(rsp_buff[1] & 0x80),
1877
2375
                   (unsigned int)rsp_buff[2]);
1885
2383
            printf("ACC=%d  TPGS=%d  3PC=%d  Protect=%d ",
1886
2384
                   !!(rsp_buff[5] & 0x40), ((rsp_buff[5] & 0x30) >> 4),
1887
2385
                   !!(rsp_buff[5] & 0x08), !!(rsp_buff[5] & 0x01));
1888
 
            printf(" BQue=%d\n  EncServ=%d  ", !!(rsp_buff[6] & 0x80),
 
2386
            printf(" [BQue=%d]\n  EncServ=%d  ", !!(rsp_buff[6] & 0x80),
1889
2387
                   !!(rsp_buff[6] & 0x40));
1890
2388
            if (rsp_buff[6] & 0x10)
1891
2389
                printf("MultiP=1 (VS=%d)  ", !!(rsp_buff[6] & 0x20));
1912
2410
            cp = sg_get_pdt_str(peri_type, sizeof(buff), buff);
1913
2411
            if (strlen(cp) > 0)
1914
2412
                printf("   Peripheral device type: %s\n", cp);
1915
 
 
1916
 
            if (act_len <= 8)
 
2413
        }
 
2414
        if (act_len <= 8) {
 
2415
            if (! optsp->do_export)
1917
2416
                printf(" Inquiry response length=%d, no vendor, "
1918
2417
                       "product or revision data\n", act_len);
1919
 
            else {
1920
 
                if (act_len < SAFE_STD_INQ_RESP_LEN)
1921
 
                    rsp_buff[act_len] = '\0';
1922
 
                memcpy(xtra_buff, &rsp_buff[8], 8);
1923
 
                xtra_buff[8] = '\0';
 
2418
        } else {
 
2419
            int i;
 
2420
 
 
2421
            if (act_len < SAFE_STD_INQ_RESP_LEN)
 
2422
                rsp_buff[act_len] = '\0';
 
2423
            memcpy(xtra_buff, &rsp_buff[8], 8);
 
2424
            xtra_buff[8] = '\0';
 
2425
            /* Fixup any tab characters */
 
2426
            for (i = 0; i < 8; ++i)
 
2427
                if (xtra_buff[i] == 0x09)
 
2428
                    xtra_buff[i] = ' ';
 
2429
            if (optsp->do_export) {
 
2430
                len = encode_whitespaces((unsigned char *)xtra_buff, 8);
 
2431
                printf("SCSI_VENDOR=%s\n", xtra_buff);
 
2432
                encode_string(xtra_buff, &rsp_buff[8], 8);
 
2433
                printf("SCSI_VENDOR_ENC=%s\n", xtra_buff);
 
2434
            } else
1924
2435
                printf(" Vendor identification: %s\n", xtra_buff);
1925
 
                if (act_len <= 16)
 
2436
            if (act_len <= 16) {
 
2437
                if (! optsp->do_export)
1926
2438
                    printf(" Product identification: <none>\n");
1927
 
                else {
1928
 
                    memcpy(xtra_buff, &rsp_buff[16], 16);
1929
 
                    xtra_buff[16] = '\0';
 
2439
            } else {
 
2440
                memcpy(xtra_buff, &rsp_buff[16], 16);
 
2441
                xtra_buff[16] = '\0';
 
2442
                if (optsp->do_export) {
 
2443
                    len = encode_whitespaces((unsigned char *)xtra_buff, 16);
 
2444
                    printf("SCSI_MODEL=%s\n", xtra_buff);
 
2445
                    encode_string(xtra_buff, &rsp_buff[16], 16);
 
2446
                    printf("SCSI_MODEL_ENC=%s\n", xtra_buff);
 
2447
                } else
1930
2448
                    printf(" Product identification: %s\n", xtra_buff);
1931
 
                }
1932
 
                if (act_len <= 32)
 
2449
            }
 
2450
            if (act_len <= 32) {
 
2451
                if (!optsp->do_export)
1933
2452
                    printf(" Product revision level: <none>\n");
1934
 
                else {
1935
 
                    memcpy(xtra_buff, &rsp_buff[32], 4);
1936
 
                    xtra_buff[4] = '\0';
 
2453
            } else {
 
2454
                memcpy(xtra_buff, &rsp_buff[32], 4);
 
2455
                xtra_buff[4] = '\0';
 
2456
                if (optsp->do_export) {
 
2457
                    len = encode_whitespaces((unsigned char *)xtra_buff, 4);
 
2458
                    printf("SCSI_REVISION=%s\n", xtra_buff);
 
2459
                } else
1937
2460
                    printf(" Product revision level: %s\n", xtra_buff);
1938
 
                }
1939
 
                if (optsp->do_descriptors) {
1940
 
                    for (j = 0, k = 58; ((j < 8) && ((k + 1) < act_len));
1941
 
                         k +=2, ++j)
1942
 
                        vdesc_arr[j] = ((rsp_buff[k] << 8) +
1943
 
                                         rsp_buff[k + 1]);
1944
 
                }
 
2461
            }
 
2462
            if (optsp->do_vendor && (act_len > 36) && ('\0' != rsp_buff[36]) &&
 
2463
                (' ' != rsp_buff[36])) {
 
2464
                memcpy(xtra_buff, &rsp_buff[36], act_len < 56 ? act_len - 36 :
 
2465
                       20);
 
2466
                if (optsp->do_export) {
 
2467
                    len = encode_whitespaces((unsigned char *)xtra_buff, 20);
 
2468
                    printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
 
2469
                } else
 
2470
                    printf(" Vendor specific: %s\n", xtra_buff);
 
2471
            }
 
2472
            if (optsp->do_descriptors) {
 
2473
                for (j = 0, k = 58; ((j < 8) && ((k + 1) < act_len));
 
2474
                     k +=2, ++j)
 
2475
                    vdesc_arr[j] = ((rsp_buff[k] << 8) +
 
2476
                                    rsp_buff[k + 1]);
 
2477
            }
 
2478
            if ((optsp->do_vendor > 1) && (act_len > 96)) {
 
2479
                memcpy(xtra_buff, &rsp_buff[96], act_len - 96);
 
2480
                if (optsp->do_export) {
 
2481
                    len = encode_whitespaces((unsigned char *)xtra_buff,
 
2482
                                             act_len - 96);
 
2483
                    printf("VENDOR_SPECIFIC=%s\n", xtra_buff);
 
2484
                } else
 
2485
                    printf(" Vendor specific: %s\n", xtra_buff);
1945
2486
            }
1946
2487
        }
1947
 
        if (! (optsp->do_raw || optsp->do_hex)) {
 
2488
        if (! (optsp->do_raw || optsp->do_hex || optsp->do_export)) {
1948
2489
            if (0 == optsp->resp_len) {
1949
2490
                if (0 == fetch_unit_serial_num(sg_fd, xtra_buff,
1950
2491
                                   sizeof(xtra_buff), optsp->do_verbose))
1969
2510
            }
1970
2511
        }
1971
2512
    } else if (res < 0) { /* could be an ATA device */
1972
 
#ifdef SG_LIB_LINUX
 
2513
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
1973
2514
        /* Try an ATA Identify Device command */
1974
2515
        res = try_ata_identify(sg_fd, optsp->do_hex, optsp->do_raw,
1975
2516
                               optsp->do_verbose);
1986
2527
    } else {
1987
2528
        fprintf(stderr, "    inquiry: failed requesting %d byte response: ",
1988
2529
                rlen);
 
2530
        if (resid && verb)
 
2531
            snprintf(buff, sizeof(buff), " [resid=%d]", resid);
 
2532
        else
 
2533
            buff[0] = '\0';
1989
2534
        if (SG_LIB_CAT_INVALID_OP == res)
1990
 
            fprintf(stderr, "not supported (?)\n");
 
2535
            fprintf(stderr, "not supported (?)%s\n", buff);
1991
2536
        else if (SG_LIB_CAT_NOT_READY == res)
1992
 
            fprintf(stderr, "device not ready (?)\n");
 
2537
            fprintf(stderr, "device not ready (?)%s\n", buff);
1993
2538
        else if (SG_LIB_CAT_ILLEGAL_REQ == res)
1994
 
            fprintf(stderr, "field in cdb illegal\n");
 
2539
            fprintf(stderr, "field in cdb illegal%s\n", buff);
1995
2540
        else if (SG_LIB_CAT_UNIT_ATTENTION == res)
1996
 
            fprintf(stderr, "unit attention (?)\n");
 
2541
            fprintf(stderr, "unit attention (?)%s\n", buff);
1997
2542
        else if (SG_LIB_CAT_ABORTED_COMMAND == res)
1998
 
            fprintf(stderr, "aborted command\n");
 
2543
            fprintf(stderr, "aborted command%s\n", buff);
1999
2544
        else
2000
 
            fprintf(stderr, "res=%d\n", res);
 
2545
            fprintf(stderr, "res=%d%s\n", res, buff);
2001
2546
        return res;
2002
2547
    }
2003
2548
    return 0;
2004
2549
}
2005
2550
 
 
2551
#ifdef SG_SCSI_STRINGS
2006
2552
/* Returns 0 if successful */
2007
2553
static int
2008
2554
process_cmddt(int sg_fd, const struct opts_t * optsp)
2115
2661
    return res;
2116
2662
}
2117
2663
 
 
2664
#else /* SG_SCSI_STRINGS */
 
2665
 
 
2666
/* Returns 0. */
 
2667
static int
 
2668
process_cmddt(int sg_fd, const struct opts_t * optsp)
 
2669
{
 
2670
    sg_fd = sg_fd;
 
2671
    optsp = optsp;
 
2672
    fprintf(stderr, "'--cmddt' not implemented, use sg_opcodes\n");
 
2673
    return 0;
 
2674
}
 
2675
 
 
2676
#endif /* SG_SCSI_STRINGS */
 
2677
 
 
2678
 
2118
2679
/* Returns 0 if successful */
2119
2680
static int
2120
2681
process_vpd(int sg_fd, const struct opts_t * optsp)
2194
2755
 
2195
2756
    switch (optsp->page_num) {
2196
2757
    case VPD_UNIT_SERIAL_NUM:
2197
 
        if (! optsp->do_raw)
 
2758
        if (! optsp->do_raw && ! optsp->do_export)
2198
2759
            printf("VPD INQUIRY: Unit serial number page\n");
2199
2760
        res = sg_ll_inquiry(sg_fd, 0, 1, VPD_UNIT_SERIAL_NUM, rsp_buff,
2200
2761
                            DEF_ALLOC_LEN, 1, optsp->do_verbose);
2217
2778
                if (len >= (int)sizeof(obuff))
2218
2779
                    len = sizeof(obuff) - 1;
2219
2780
                memcpy(obuff, rsp_buff + 4, len);
2220
 
                printf("  Unit serial number: %s\n", obuff);
 
2781
                if (optsp->do_export) {
 
2782
                    len = encode_whitespaces((unsigned char *)obuff, len);
 
2783
                    printf("SCSI_IDENT_SERIAL=%s\n", obuff);
 
2784
                } else {
 
2785
                    printf("  Unit serial number: %s\n", obuff);
 
2786
                }
2221
2787
            }
2222
2788
        }
2223
2789
        break;
2224
2790
    case VPD_DEVICE_ID:
2225
 
        if (! optsp->do_raw)
 
2791
        if (! optsp->do_raw && ! optsp->do_export)
2226
2792
            printf("VPD INQUIRY: Device Identification page\n");
2227
2793
        res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff,
2228
2794
                            DEF_ALLOC_LEN, 1, optsp->do_verbose);
2244
2810
            }
2245
2811
            if (optsp->do_raw)
2246
2812
                dStrRaw((const char *)rsp_buff, len);
2247
 
            else
 
2813
            else if (optsp->do_export) {
 
2814
                if (len < 4) {
 
2815
                    fprintf(stderr, "Device identification page length too "
 
2816
                            "short=%d\n", len);
 
2817
                } else {
 
2818
                    export_dev_ids(rsp_buff + 4, len - 4);
 
2819
                }
 
2820
            } else
2248
2821
                decode_id_vpd(rsp_buff, len, optsp->do_hex);
2249
2822
        }
2250
2823
        break;
2678
3251
int
2679
3252
main(int argc, char * argv[])
2680
3253
{
2681
 
    int sg_fd, num, res, n;
2682
 
    unsigned int u;
 
3254
    int sg_fd, res, n;
2683
3255
    int ret = 0;
2684
3256
    const struct svpd_values_name_t * vnp;
2685
3257
    struct opts_t opts;
2710
3282
        if (isalpha(*opts.page_arg)) {
2711
3283
            vnp = sdp_find_vpd_by_acron(opts.page_arg);
2712
3284
            if (NULL == vnp) {
 
3285
#ifdef SG_SCSI_STRINGS
2713
3286
                if (opts.opt_new)
2714
3287
                    fprintf(stderr, "abbreviation %s given to '--page=' "
2715
3288
                            "not recognized\n", opts.page_arg);
2716
3289
                else
2717
3290
                    fprintf(stderr, "abbreviation %s given to '-p=' "
2718
3291
                            "not recognized\n", opts.page_arg);
 
3292
#else
 
3293
                fprintf(stderr, "abbreviation %s given to '--page=' "
 
3294
                        "not recognized\n", opts.page_arg);
 
3295
#endif
2719
3296
                fprintf(stderr, ">>> Available abbreviations:\n");
2720
3297
                enumerate_vpds();
2721
3298
                return SG_LIB_SYNTAX_ERROR;
2724
3301
                ++opts.do_decode;
2725
3302
            opts.page_num = vnp->value;
2726
3303
        } else {
 
3304
#ifdef SG_SCSI_STRINGS
2727
3305
            if (opts.opt_new) {
2728
3306
                n = sg_get_num(opts.page_arg);
2729
3307
                if ((n < 0) || (n > 255)) {
2735
3313
                if ((1 != opts.do_hex) && (0 == opts.do_raw))
2736
3314
                    ++opts.do_decode;
2737
3315
            } else {
 
3316
                int num;
 
3317
                unsigned int u;
 
3318
 
2738
3319
                num = sscanf(opts.page_arg, "%x", &u);
2739
3320
                if ((1 != num) || (u > 255)) {
2740
3321
                    fprintf(stderr, "Inappropriate value after '-o=' "
2744
3325
                }
2745
3326
                n = u;
2746
3327
            }
 
3328
#else
 
3329
            n = sg_get_num(opts.page_arg);
 
3330
            if ((n < 0) || (n > 255)) {
 
3331
                fprintf(stderr, "Bad argument to '--page=', "
 
3332
                        "expecting 0 to 255 inclusive\n");
 
3333
                usage_for(&opts);
 
3334
                return SG_LIB_SYNTAX_ERROR;
 
3335
            }
 
3336
            if ((1 != opts.do_hex) && (0 == opts.do_raw))
 
3337
                ++opts.do_decode;
 
3338
#endif /* SG_SCSI_STRINGS */
2747
3339
            opts.page_num = n;
2748
3340
        }
2749
3341
    }
 
3342
    if (opts.do_export) {
 
3343
        if (opts.page_num != -1) {
 
3344
            if (opts.page_num != VPD_DEVICE_ID &&
 
3345
                opts.page_num != VPD_UNIT_SERIAL_NUM) {
 
3346
                fprintf(stderr, "Option '--export' only supported "
 
3347
                        "for VPD pages 0x80 and 0x83\n");
 
3348
                usage_for(&opts);
 
3349
                return SG_LIB_SYNTAX_ERROR;
 
3350
            }
 
3351
            ++opts.do_decode;
 
3352
            ++opts.do_vpd;
 
3353
        }
 
3354
    }
2750
3355
 
2751
3356
    if ((0 == opts.do_cmddt) && (opts.page_num >= 0) && opts.p_given)
2752
3357
        ++opts.do_vpd;
2757
3362
        return SG_LIB_SYNTAX_ERROR;
2758
3363
    }
2759
3364
    if (opts.do_vpd && opts.do_cmddt) {
 
3365
#ifdef SG_SCSI_STRINGS
2760
3366
        if (opts.opt_new)
2761
3367
            fprintf(stderr, "Can't use '--cmddt' with VPD pages\n");
2762
3368
        else
2763
3369
            fprintf(stderr, "Can't have both '-e' and '-c' (or '-cl')\n");
 
3370
#else
 
3371
        fprintf(stderr, "Can't use '--cmddt' with VPD pages\n");
 
3372
#endif
2764
3373
        usage_for(&opts);
2765
3374
        return SG_LIB_SYNTAX_ERROR;
2766
3375
    }
2808
3417
    }
2809
3418
    memset(rsp_buff, 0, sizeof(rsp_buff));
2810
3419
 
2811
 
#ifdef SG_LIB_LINUX
 
3420
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
2812
3421
    if (opts.do_ata) {
2813
3422
        res = try_ata_identify(sg_fd, opts.do_hex, opts.do_raw,
2814
3423
                               opts.do_verbose);
2856
3465
}
2857
3466
 
2858
3467
 
2859
 
#ifdef SG_LIB_LINUX
 
3468
#if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS)
2860
3469
/* Following code permits ATA IDENTIFY commands to be performed on
2861
3470
   ATA non "Packet Interface" devices (e.g. ATA disks).
2862
3471
   GPL-ed code borrowed from smartmontools (smartmontools.sf.net).
2952
3561
        } else if (atapi_flag) {
2953
3562
            *atapi_flag = 1;
2954
3563
            if (verbose > 1)
2955
 
                fprintf(stderr, "HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n");
 
3564
                fprintf(stderr, "HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) "
 
3565
                        "succeeded\n");
2956
3566
        }
2957
3567
    } else {    /* assume non-packet device */
2958
3568
        buff[0] = ATA_IDENTIFY_DEVICE;