~ubuntu-branches/ubuntu/intrepid/sg3-utils/intrepid

« back to all changes in this revision

Viewing changes to sg_modes.c

  • Committer: Bazaar Package Importer
  • Author(s): Luk Claes
  • Date: 2006-11-05 17:23:29 UTC
  • mfrom: (1.1.4 upstream) (3.1.2 edgy)
  • Revision ID: james.westby@ubuntu.com-20061105172329-l4loha00sk36qz6k
* Non-maintainer upload.
* Fix FTBFS due to old syscall usage (Closes: #395512).

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
#include <stdlib.h>
5
5
#include <string.h>
6
6
#include <ctype.h>
7
 
#include <errno.h>
8
 
#include <sys/ioctl.h>
9
 
#include <sys/types.h>
10
 
#include "sg_include.h"
11
 
#include "sg_err.h"
 
7
 
 
8
#include "sg_lib.h"
 
9
#include "sg_cmds.h"
12
10
 
13
11
/* A utility program for the Linux OS SCSI generic ("sg") device driver.
14
 
*  Copyright (C) 2000-2004 D. Gilbert
 
12
*  Copyright (C) 2000-2006 D. Gilbert
15
13
*  This program is free software; you can redistribute it and/or modify
16
14
*  it under the terms of the GNU General Public License as published by
17
15
*  the Free Software Foundation; either version 2, or (at your option)
23
21
   
24
22
*/
25
23
 
26
 
static char * version_str = "0.27 20040822";
 
24
static char * version_str = "1.16 20060623";
27
25
 
28
26
#define ME "sg_modes: "
29
27
 
30
 
#define SENSE_BUFF_LEN 32       /* Arbitrary, could be larger */
31
 
#define DEF_TIMEOUT 60000       /* 60,000 millisecs == 60 seconds */
32
 
 
33
 
#define MODE_SENSE6_CMD      0x1a
34
 
#define MODE_SENSE6_CMDLEN   6
35
 
#define MODE_SENSE10_CMD     0x5a
36
 
#define MODE_SENSE10_CMDLEN  10
37
 
#define INQUIRY_CMD     0x12
38
 
#define INQUIRY_CMDLEN  6
39
 
#define INQUIRY_RESPLEN  36
40
28
#define MX_ALLOC_LEN (1024 * 4)
41
 
 
42
29
#define PG_CODE_ALL 0x3f
43
30
#define PG_CODE_MASK 0x3f
44
31
#define PG_CODE_MAX 0x3f
45
32
#define SPG_CODE_ALL 0xff
 
33
#define PROTO_SPECIFIC_1 0x18
 
34
#define PROTO_SPECIFIC_2 0x19
46
35
 
47
36
#define EBUFF_SZ 256
48
37
 
49
38
 
50
 
struct simple_inquiry_t {
51
 
    unsigned char peripheral_qualifier;
52
 
    unsigned char peripheral_type;
53
 
    unsigned char rmb;
54
 
    unsigned char version;      /* as per recent drafts: whole of byte 2 */
55
 
    unsigned char byte_3;
56
 
    unsigned char byte_5;
57
 
    unsigned char byte_6;
58
 
    unsigned char byte_7;
59
 
    char vendor[9];
60
 
    char product[17];
61
 
    char revision[5];
62
 
};
63
 
 
64
 
/* Returns 0 when successful, else -1 */
65
 
static int do_simple_inq(int sg_fd, int noisy, 
66
 
                         struct simple_inquiry_t * inq_data, int verbose)
67
 
{
68
 
    int res, k;
69
 
    unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
70
 
    unsigned char sense_b[SENSE_BUFF_LEN];
71
 
    struct sg_io_hdr io_hdr;
72
 
    unsigned char inq_resp[INQUIRY_RESPLEN];
73
 
 
74
 
    if (inq_data) {
75
 
        memset(inq_data, 0, sizeof(* inq_data));
76
 
        inq_data->peripheral_qualifier = 0x3;
77
 
        inq_data->peripheral_type = 0x1f;
78
 
    }
79
 
    inqCmdBlk[4] = (unsigned char)sizeof(inq_resp);
80
 
    if (verbose) {
81
 
        fprintf(stderr, "        inquiry cdb: ");
82
 
        for (k = 0; k < INQUIRY_CMDLEN; ++k)
83
 
            fprintf(stderr, "%02x ", inqCmdBlk[k]);
84
 
        fprintf(stderr, "\n");
85
 
    }
86
 
    memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
87
 
    io_hdr.interface_id = 'S';
88
 
    io_hdr.cmd_len = sizeof(inqCmdBlk);
89
 
    io_hdr.mx_sb_len = sizeof(sense_b);
90
 
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
91
 
    io_hdr.dxfer_len = sizeof(inq_resp);
92
 
    io_hdr.dxferp = inq_resp;
93
 
    io_hdr.cmdp = inqCmdBlk;
94
 
    io_hdr.sbp = sense_b;
95
 
    io_hdr.timeout = DEF_TIMEOUT;
96
 
 
97
 
    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
98
 
        perror("SG_IO (inquiry) error");
99
 
        return -1;
100
 
    }
101
 
    res = sg_err_category3(&io_hdr);
102
 
    switch (res) {
103
 
    case SG_ERR_CAT_CLEAN:
104
 
    case SG_ERR_CAT_RECOVERED:
105
 
        if (inq_data) {
106
 
            inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
107
 
            inq_data->peripheral_type = inq_resp[0] & 0x1f;
108
 
            inq_data->rmb = (inq_resp[1] & 0x80) ? 1 : 0;
109
 
            inq_data->version = inq_resp[2];
110
 
            inq_data->byte_3 = inq_resp[3];
111
 
            inq_data->byte_5 = inq_resp[5];
112
 
            inq_data->byte_6 = inq_resp[6];
113
 
            inq_data->byte_7 = inq_resp[7];
114
 
            memcpy(inq_data->vendor, inq_resp + 8, 8);
115
 
            memcpy(inq_data->product, inq_resp + 16, 16);
116
 
            memcpy(inq_data->revision, inq_resp + 32, 4);
117
 
        }
118
 
        return 0;
119
 
    default:
120
 
        if (noisy) {
121
 
            char ebuff[EBUFF_SZ];
122
 
            snprintf(ebuff, EBUFF_SZ, "Inquiry error ");
123
 
            sg_chk_n_print3(ebuff, &io_hdr);
124
 
        }
125
 
        return -1;
126
 
    }
127
 
}
128
 
 
129
 
static int do_modes(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
130
 
                    void * resp, int mx_resp_len, int noisy, int mode6,
131
 
                    int verbose)
132
 
{
133
 
    int res, k;
134
 
    unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] = 
135
 
        {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
136
 
    unsigned char sense_b[SENSE_BUFF_LEN];
137
 
    struct sg_io_hdr io_hdr;
138
 
    int cmd_len;
139
 
 
140
 
    cmd_len = mode6 ? MODE_SENSE6_CMDLEN : MODE_SENSE10_CMDLEN;
141
 
    modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0);
142
 
    modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | 
143
 
                                     (pg_code & PG_CODE_MASK));
144
 
    modesCmdBlk[3] = (unsigned char)(sub_pg_code & 0xff);
145
 
    if (mx_resp_len > (mode6 ? 0xff : 0xffff)) {
146
 
        printf( ME "mx_resp_len too big\n");
147
 
        return -1;
148
 
    }
149
 
    if (mode6) {
150
 
        modesCmdBlk[0] = MODE_SENSE6_CMD;
151
 
        modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
152
 
    } else {
153
 
        modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
154
 
        modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
155
 
    }
156
 
    if (verbose) {
157
 
        fprintf(stderr, "        mode sense cdb: ");
158
 
        for (k = 0; k < cmd_len; ++k)
159
 
            fprintf(stderr, "%02x ", modesCmdBlk[k]);
160
 
        fprintf(stderr, "\n");
161
 
    }
162
 
 
163
 
    memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
164
 
    memset(sense_b, 0, sizeof(sense_b));
165
 
    io_hdr.interface_id = 'S';
166
 
    io_hdr.cmd_len = cmd_len;
167
 
    io_hdr.mx_sb_len = sizeof(sense_b);
168
 
    io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
169
 
    io_hdr.dxfer_len = mx_resp_len;
170
 
    io_hdr.dxferp = resp;
171
 
    io_hdr.cmdp = modesCmdBlk;
172
 
    io_hdr.sbp = sense_b;
173
 
    io_hdr.timeout = DEF_TIMEOUT;
174
 
 
175
 
    if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
176
 
        perror("SG_IO (mode sense) error");
177
 
        return -1;
178
 
    }
179
 
    res = sg_err_category3(&io_hdr);
180
 
    switch (res) {
181
 
    case SG_ERR_CAT_CLEAN:
182
 
    case SG_ERR_CAT_RECOVERED:
183
 
        return 0;
184
 
    default:
185
 
        {
186
 
            char ebuff[EBUFF_SZ];
187
 
            struct sg_scsi_sense_hdr ssh;
188
 
 
189
 
            if (noisy) {
190
 
                snprintf(ebuff, EBUFF_SZ, "Mode sense error, dbd=%d "
191
 
                        "pc=%d page_code=%x sub_page_code=%x\n     ", dbd,
192
 
                        pc, pg_code, sub_pg_code);
193
 
                sg_chk_n_print3(ebuff, &io_hdr);
194
 
            }
195
 
            if (sg_normalize_sense(&io_hdr, &ssh)) {
196
 
                if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) {
197
 
                    if (mode6)
198
 
                        fprintf(stderr, ">>>>>> try again without the '-6' "
199
 
                                "switch for a 10 byte MODE SENSE command\n");
200
 
                    else
201
 
                        fprintf(stderr, ">>>>>> try again with a '-6' "
202
 
                                "switch for a 6 byte MODE SENSE command\n");
203
 
                }
204
 
            }
205
 
        }
206
 
        return -1;
207
 
    }
208
 
}
209
 
 
210
 
const char * scsi_ptype_strs[] = {
211
 
    "disk",
212
 
    "tape",
213
 
    "printer",
214
 
    "processor",
215
 
    "write once optical disk",
216
 
    "cd/dvd",
217
 
    "scanner",
218
 
    "optical memory device",
219
 
    "medium changer",
220
 
    "communications",
221
 
    "graphics",
222
 
    "graphics",
223
 
    "storage array controller",
224
 
    "enclosure services device",
225
 
    "simplified direct access device",
226
 
    "optical card reader/writer device",
227
 
};
228
 
 
229
 
const char * get_ptype_str(int scsi_ptype)
230
 
{
231
 
    int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
232
 
 
233
 
    return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
234
 
}
 
39
static const char * transport_proto_arr[] =
 
40
{
 
41
    "Fibre Channel (FCP-2)",
 
42
    "Parallel SCSI (SPI-4)",
 
43
    "SSA (SSA-S3P)",
 
44
    "IEEE 1394 (SBP-3)",
 
45
    "Remote Direct Memory Access (SRP)",
 
46
    "Internet SCSI (iSCSI)",
 
47
    "Serial Attached SCSI (SAS)",
 
48
    "Automation/Drive Interface (ADT)",
 
49
    "ATA Packet Interface (ATA/ATAPI-7)",
 
50
    "Ox9", "Oxa", "Oxb", "Oxc", "Oxd", "Oxe",
 
51
    "No specific protocol"
 
52
};
235
53
 
236
54
struct page_code_desc {
237
55
    int page_code;
239
57
    const char * desc;
240
58
};
241
59
 
242
 
static struct page_code_desc pc_desc_all[] = {
243
 
    {0x0, 0x0, "Unit Attention condition [vendor: page format not required]"},
 
60
static struct page_code_desc pc_desc_common[] = {
 
61
    {0x0, 0x0, "Unit Attention condition [vendor specific format]"},
244
62
    {0x2, 0x0, "Disconnect-Reconnect"},
 
63
    {0x9, 0x0, "Peripheral device (obsolete)"},
245
64
    {0xa, 0x0, "Control"},
246
65
    {0xa, 0x1, "Control extension"},
247
66
    {0x15, 0x0, "Extended"},
248
67
    {0x16, 0x0, "Extended device-type specific"},
249
 
    {0x18, 0x0, "Protocol specific LUN"},
 
68
    {0x18, 0x0, "Protocol specific lu"},
250
69
    {0x19, 0x0, "Protocol specific port"},
251
70
    {0x1a, 0x0, "Power condition"},
252
71
    {0x1c, 0x0, "Informational exceptions control"},
253
72
    {PG_CODE_ALL, 0x0, "[yields all supported pages]"},
 
73
    {PG_CODE_ALL, SPG_CODE_ALL, "[yields all supported pages and subpages]"},
254
74
};
255
75
 
256
76
static struct page_code_desc pc_desc_disk[] = {
257
77
    {0x1, 0x0, "Read-Write error recovery"},
258
 
    {0x3, 0x0, "Format"},
259
 
    {0x4, 0x0, "Rigid disk geometry"},
260
 
    {0x5, 0x0, "Flexible geometry"},
 
78
    {0x3, 0x0, "Format (obsolete)"},
 
79
    {0x4, 0x0, "Rigid disk geometry (obsolete)"},
 
80
    {0x5, 0x0, "Flexible geometry (obsolete)"},
261
81
    {0x7, 0x0, "Verify error recovery"},
262
82
    {0x8, 0x0, "Caching"},
263
 
    {0x9, 0x0, "Peripheral device (spc-2 ?)"},
264
 
    {0xb, 0x0, "Medium types supported"},
265
 
    {0xc, 0x0, "Notch and partition"},
266
 
    {0xd, 0x0, "Power condition (obsolete)"},
 
83
    {0xa, 0xf1, "Parallel ATA control (SAT)"},
 
84
    {0xa, 0xf2, "Reserved (SATA control) (SAT)"},
 
85
    {0xb, 0x0, "Medium types supported (obsolete)"},
 
86
    {0xc, 0x0, "Notch and partition (obsolete)"},
 
87
    {0xd, 0x0, "Power condition (obsolete, moved to 0x1a)"},
267
88
    {0x10, 0x0, "XOR control"},
 
89
    {0x1c, 0x1, "Background control"},
268
90
};
269
91
 
270
92
static struct page_code_desc pc_desc_tape[] = {
271
93
    {0xf, 0x0, "Data Compression"},
272
 
    {0x10, 0x0, "Device config"},
 
94
    {0x10, 0x0, "Device configuration"},
 
95
    {0x10, 0x1, "Device configuration extension"},
273
96
    {0x11, 0x0, "Medium Partition [1]"},
274
97
    {0x12, 0x0, "Medium Partition [2]"},
275
98
    {0x13, 0x0, "Medium Partition [3]"},
276
99
    {0x14, 0x0, "Medium Partition [4]"},
277
100
    {0x1c, 0x0, "Informational exceptions control (tape version)"},
 
101
    {0x1d, 0x0, "Medium configuration"},
278
102
};
279
103
 
280
104
static struct page_code_desc pc_desc_cddvd[] = {
285
109
    {0x8, 0x0, "Caching"},
286
110
    {0xd, 0x0, "CD device parameters (obsolete)"},
287
111
    {0xe, 0x0, "CD audio"},
288
 
    {0x1a, 0x0, "Power condition"},
289
 
    {0x1c, 0x0, "Fault/failure reporting control"},
 
112
    {0x1a, 0x0, "Power condition (mmc)"},
 
113
    {0x1c, 0x0, "Fault/failure reporting control (mmc)"},
290
114
    {0x1d, 0x0, "Timeout and protect"},
291
115
    {0x2a, 0x0, "MM capabilities and mechanical status (obsolete)"},
292
116
};
295
119
    {0x1d, 0x0, "Element address assignment"},
296
120
    {0x1e, 0x0, "Transport geometry parameters"},
297
121
    {0x1f, 0x0, "Device capabilities"},
 
122
    {0x1f, 0x1, "Extended device capabilities"},
298
123
};
299
124
 
300
125
static struct page_code_desc pc_desc_scc[] = {
305
130
    {0x14, 0x0, "Enclosure services management"},
306
131
};
307
132
 
308
 
struct page_code_desc * find_mode_page_table(int scsi_ptype, int * size)
 
133
static struct page_code_desc pc_desc_rbc[] = {
 
134
    {0x6, 0x0, "RBC device parameters"},
 
135
};
 
136
 
 
137
static struct page_code_desc pc_desc_adt[] = {
 
138
    {0xe, 0x0, "ADC device configuration"},
 
139
    {0xe, 0x1, "Target device"},
 
140
    {0xe, 0x2, "DT device primary port"},
 
141
    {0xe, 0x3, "Logical unit"},
 
142
    {0xe, 0x4, "Target device serial number"},
 
143
};
 
144
 
 
145
static struct page_code_desc * mode_page_cs_table(int scsi_ptype,
 
146
                                                  int * size)
309
147
{
310
148
    switch (scsi_ptype)
311
149
    {
 
150
        case -1:        /* common list */
 
151
            *size = sizeof(pc_desc_common) / sizeof(pc_desc_common[0]);
 
152
            return &pc_desc_common[0];
312
153
        case 0:         /* disk (direct access) type devices */
313
154
        case 4:
314
155
        case 7:
315
 
        case 0xe:
316
156
            *size = sizeof(pc_desc_disk) / sizeof(pc_desc_disk[0]);
317
157
            return &pc_desc_disk[0];
318
158
        case 1:         /* tape devices */
331
171
        case 0xd:       /* enclosure services devices */
332
172
            *size = sizeof(pc_desc_ses) / sizeof(pc_desc_ses[0]);
333
173
            return &pc_desc_ses[0];
334
 
    }
335
 
    *size = 0;
336
 
    return NULL;
337
 
}
338
 
 
339
 
const char * find_page_code_desc(int page_num, int subpage_num,
340
 
                                 int scsi_ptype)
 
174
        case 0xe:       /* simplified direct access device */
 
175
            *size = sizeof(pc_desc_rbc) / sizeof(pc_desc_rbc[0]);
 
176
            return &pc_desc_rbc[0];
 
177
        case 0x12:       /* automation device/interface */
 
178
            *size = sizeof(pc_desc_adt) / sizeof(pc_desc_adt[0]);
 
179
            return &pc_desc_adt[0];
 
180
    }
 
181
    *size = 0;
 
182
    return NULL;
 
183
}
 
184
 
 
185
static struct page_code_desc pc_desc_t_fcp[] = {
 
186
    {0x18, 0x0, "LU control"},
 
187
    {0x19, 0x0, "Port control"},
 
188
};
 
189
 
 
190
static struct page_code_desc pc_desc_t_spi4[] = {
 
191
    {0x18, 0x0, "LU control"},
 
192
    {0x19, 0x0, "Port control short format"},
 
193
    {0x19, 0x1, "Margin control"},
 
194
    {0x19, 0x2, "Saved training configuration value"},
 
195
    {0x19, 0x3, "Negotiated settings"},
 
196
    {0x19, 0x4, "Report transfer capabilities"},
 
197
};
 
198
 
 
199
static struct page_code_desc pc_desc_t_sas[] = {
 
200
    {0x18, 0x0, "LU SSP, short format"},
 
201
    {0x19, 0x0, "Port SSP, short format"},
 
202
    {0x19, 0x1, "Port SSP, phy control and discover"},
 
203
    {0x19, 0x2, "Port SSP, shared"},
 
204
};
 
205
 
 
206
static struct page_code_desc pc_desc_t_adt[] = {
 
207
    {0xe, 0x1, "Target device"},
 
208
    {0xe, 0x2, "DT device primary port"},
 
209
    {0xe, 0x3, "Logical unit"},
 
210
    {0x18, 0x0, "Protocol specific lu"},
 
211
    {0x19, 0x0, "Protocol specific port"},
 
212
};
 
213
 
 
214
static struct page_code_desc * mode_page_transp_table(int t_proto,
 
215
                                                      int * size)
 
216
{
 
217
    switch (t_proto)
 
218
    {
 
219
        case 0:         /* Fibre channel */
 
220
            *size = sizeof(pc_desc_t_fcp) / sizeof(pc_desc_t_fcp[0]);
 
221
            return &pc_desc_t_fcp[0];
 
222
        case 1:         /* SPI-4 */
 
223
            *size = sizeof(pc_desc_t_spi4) / sizeof(pc_desc_t_spi4[0]);
 
224
            return &pc_desc_t_spi4[0];
 
225
        case 6:         /* SAS-1.1 */
 
226
            *size = sizeof(pc_desc_t_sas) / sizeof(pc_desc_t_sas[0]);
 
227
            return &pc_desc_t_sas[0];
 
228
        case 7:         /* ADT/ADC */
 
229
            *size = sizeof(pc_desc_t_adt) / sizeof(pc_desc_t_adt[0]);
 
230
            return &pc_desc_t_adt[0];
 
231
    }
 
232
    *size = 0;
 
233
    return NULL;
 
234
}
 
235
 
 
236
static const char * find_page_code_desc(int page_num, int subpage_num,
 
237
                                        int scsi_ptype, int inq_byte6,
 
238
                                        int t_proto)
341
239
{
342
240
    int k;
343
241
    int num;
344
242
    const struct page_code_desc * pcdp;
345
243
 
346
 
    pcdp = find_mode_page_table(scsi_ptype, &num);
 
244
    if (t_proto >= 0) {
 
245
        pcdp = mode_page_transp_table(t_proto, &num);
 
246
        if (pcdp) {
 
247
            for (k = 0; k < num; ++k, ++pcdp) {
 
248
                if ((page_num == pcdp->page_code) &&
 
249
                    (subpage_num == pcdp->subpage_code))
 
250
                    return pcdp->desc;
 
251
                else if (page_num < pcdp->page_code)
 
252
                    break;
 
253
            }
 
254
        }
 
255
    }
 
256
    pcdp = mode_page_cs_table(scsi_ptype, &num);
347
257
    if (pcdp) {
348
258
        for (k = 0; k < num; ++k, ++pcdp) {
349
259
            if ((page_num == pcdp->page_code) &&
353
263
                break;
354
264
        }
355
265
    }
356
 
    pcdp = &pc_desc_all[0];
357
 
    num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]);
 
266
    if ((0xd != scsi_ptype) && (inq_byte6 & 0x40)) {
 
267
        /* check for attached enclosure services processor */
 
268
        pcdp = mode_page_cs_table(0xd, &num);
 
269
        if (pcdp) {
 
270
            for (k = 0; k < num; ++k, ++pcdp) {
 
271
                if ((page_num == pcdp->page_code) &&
 
272
                    (subpage_num == pcdp->subpage_code))
 
273
                    return pcdp->desc;
 
274
                else if (page_num < pcdp->page_code)
 
275
                    break;
 
276
            }
 
277
        }
 
278
    }
 
279
    if ((0x8 != scsi_ptype) && (inq_byte6 & 0x8)) {
 
280
        /* check for attached medium changer device */
 
281
        pcdp = mode_page_cs_table(0x8, &num);
 
282
        if (pcdp) {
 
283
            for (k = 0; k < num; ++k, ++pcdp) {
 
284
                if ((page_num == pcdp->page_code) &&
 
285
                    (subpage_num == pcdp->subpage_code))
 
286
                    return pcdp->desc;
 
287
                else if (page_num < pcdp->page_code)
 
288
                    break;
 
289
            }
 
290
        }
 
291
    }
 
292
    pcdp = mode_page_cs_table(-1, &num);
358
293
    for (k = 0; k < num; ++k, ++pcdp) {
359
294
        if ((page_num == pcdp->page_code) &&
360
295
            (subpage_num == pcdp->subpage_code))
365
300
    return NULL;
366
301
}
367
302
 
368
 
static void list_page_codes(int scsi_ptype)
369
 
{
370
 
    int k;
371
 
    int num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]);
372
 
    const struct page_code_desc * pcdp = &pc_desc_all[0];
373
 
    int num_ptype;
374
 
    const struct page_code_desc * pcd_ptypep;
375
 
 
376
 
    pcd_ptypep = find_mode_page_table(scsi_ptype, &num_ptype);
377
 
    printf("Page_Code  Description\n");
378
 
    for (k = 0; k <= PG_CODE_MAX; ++k) {
379
 
        if (pcd_ptypep && (num_ptype > 0)) {
380
 
            if (k == pcd_ptypep->page_code) {
381
 
                printf(" 0x%02x      %s\n", pcd_ptypep->page_code, 
382
 
                       pcd_ptypep->desc);   
383
 
                ++pcd_ptypep;
384
 
                --num_ptype;
385
 
                continue;
386
 
            } else if (k > pcd_ptypep->page_code) {
387
 
                pcd_ptypep++;
388
 
                --num_ptype;
389
 
            }
390
 
        }
391
 
        if (pcdp && (num > 0)) {
392
 
            if (k == pcdp->page_code) {
393
 
                printf(" 0x%02x      %s\n", pcdp->page_code, pcdp->desc);   
394
 
                ++pcdp;
395
 
                --num;
396
 
                continue;
397
 
            } else if (k > pcdp->page_code) {
398
 
                pcdp++;
399
 
                --num;
400
 
            }
401
 
        }
402
 
    }
 
303
static void list_page_codes(int scsi_ptype, int inq_byte6, int t_proto)
 
304
{
 
305
    int num, num_ptype, pg, spg, c, d, valid_transport;
 
306
    const struct page_code_desc * dp;
 
307
    const struct page_code_desc * pe_dp;
 
308
 
 
309
    valid_transport = ((t_proto >= 0) && (t_proto <= 0xf)) ? 1 : 0;
 
310
    printf("Page[,subpage]   Name\n");
 
311
    printf("=====================\n");
 
312
    dp = mode_page_cs_table(-1, &num);
 
313
    pe_dp = mode_page_cs_table(scsi_ptype, &num_ptype);
 
314
    while (1) {
 
315
        pg = dp ? dp->page_code : PG_CODE_ALL + 1; 
 
316
        spg = dp ? dp->subpage_code : SPG_CODE_ALL; 
 
317
        c = (pg << 8) + spg;
 
318
        pg = pe_dp ? pe_dp->page_code : PG_CODE_ALL + 1; 
 
319
        spg = pe_dp ? pe_dp->subpage_code : SPG_CODE_ALL;
 
320
        d = (pg << 8) + spg;
 
321
        if (valid_transport &&
 
322
            ((PROTO_SPECIFIC_1 == c) || (PROTO_SPECIFIC_2 == c)))
 
323
            dp = (--num <= 0) ? NULL : (dp + 1); /* skip protocol specific */
 
324
        else if (c == d) { 
 
325
            if (pe_dp->subpage_code)
 
326
                printf(" 0x%02x,0x%02x    *  %s\n", pe_dp->page_code,
 
327
                       pe_dp->subpage_code, pe_dp->desc);   
 
328
            else
 
329
                printf(" 0x%02x         *  %s\n", pe_dp->page_code,
 
330
                       pe_dp->desc);   
 
331
            dp = (--num <= 0) ? NULL : (dp + 1);
 
332
            pe_dp = (--num_ptype <= 0) ? NULL : (pe_dp + 1);
 
333
        } else if (c < d) { 
 
334
            if (dp->subpage_code)
 
335
                printf(" 0x%02x,0x%02x       %s\n", dp->page_code,
 
336
                       dp->subpage_code, dp->desc);   
 
337
            else
 
338
                printf(" 0x%02x            %s\n", dp->page_code,
 
339
                       dp->desc);
 
340
            dp = (--num <= 0) ? NULL : (dp + 1);
 
341
        } else {
 
342
            if (pe_dp->subpage_code)
 
343
                printf(" 0x%02x,0x%02x       %s\n", pe_dp->page_code,
 
344
                       pe_dp->subpage_code, pe_dp->desc);   
 
345
            else
 
346
                printf(" 0x%02x            %s\n", pe_dp->page_code,
 
347
                       pe_dp->desc);   
 
348
            pe_dp = (--num_ptype <= 0) ? NULL : (pe_dp + 1);
 
349
        }
 
350
        if ((NULL == dp) && (NULL == pe_dp))
 
351
            break;
 
352
    }
 
353
    if ((0xd != scsi_ptype) && (inq_byte6 & 0x40)) {
 
354
        /* check for attached enclosure services processor */
 
355
        printf("\n    Attached enclosure services processor\n");
 
356
        dp = mode_page_cs_table(0xd, &num);
 
357
        while (dp) {
 
358
            if (dp->subpage_code)
 
359
                printf(" 0x%02x,0x%02x       %s\n", dp->page_code,
 
360
                       dp->subpage_code, dp->desc);   
 
361
            else
 
362
                printf(" 0x%02x            %s\n", dp->page_code,
 
363
                       dp->desc);
 
364
            dp = (--num <= 0) ? NULL : (dp + 1);
 
365
        }
 
366
    }
 
367
    if ((0x8 != scsi_ptype) && (inq_byte6 & 0x8)) {
 
368
        /* check for attached medium changer device */
 
369
        printf("\n    Attached medium changer device\n");
 
370
        dp = mode_page_cs_table(0x8, &num);
 
371
        while (dp) {
 
372
            if (dp->subpage_code)
 
373
                printf(" 0x%02x,0x%02x       %s\n", dp->page_code,
 
374
                       dp->subpage_code, dp->desc);   
 
375
            else
 
376
                printf(" 0x%02x            %s\n", dp->page_code,
 
377
                       dp->desc);
 
378
            dp = (--num <= 0) ? NULL : (dp + 1);
 
379
        }
 
380
    }
 
381
    if (valid_transport) {
 
382
        printf("\n    Transport protocol: %s\n",
 
383
               transport_proto_arr[t_proto]);
 
384
        dp = mode_page_transp_table(t_proto, &num);
 
385
        while (dp) {
 
386
            if (dp->subpage_code)
 
387
                printf(" 0x%02x,0x%02x       %s\n", dp->page_code,
 
388
                       dp->subpage_code, dp->desc);   
 
389
            else
 
390
                printf(" 0x%02x            %s\n", dp->page_code,
 
391
                       dp->desc);
 
392
            dp = (--num <= 0) ? NULL : (dp + 1);
 
393
        }
 
394
    }
 
395
}
 
396
 
 
397
static int examine_pages(int sg_fd, int do_mode6, int inq_pdt, int inq_byte6,
 
398
                         int verbose)
 
399
{
 
400
    int k, res, header;
 
401
    unsigned char rbuf[4];
 
402
    const char * cp;
 
403
 
 
404
    for (header = 0, k = 0; k < 0x3f; ++k) {
 
405
        if (do_mode6) {
 
406
            res = sg_ll_mode_sense6(sg_fd, 0, 0, k, 0,
 
407
                                    rbuf, sizeof(rbuf), 0, verbose);
 
408
            if (SG_LIB_CAT_INVALID_OP == res) {
 
409
                fprintf(stderr, ">>>>>> try again without the '-6' "
 
410
                        "switch for a 10 byte MODE SENSE command\n");
 
411
                return res;
 
412
            }
 
413
        } else {
 
414
            res = sg_ll_mode_sense10(sg_fd, 0, 0, 0, k,
 
415
                                     0, rbuf, sizeof(rbuf), 1, verbose);
 
416
            if (SG_LIB_CAT_INVALID_OP == res) {
 
417
                fprintf(stderr, ">>>>>> try again with a '-6' "
 
418
                        "switch for a 6 byte MODE SENSE command\n");
 
419
                return res;
 
420
            }
 
421
        }
 
422
        if (0 == res) {
 
423
            if (0 == header) {
 
424
                printf("Discovered mode pages:\n");
 
425
                header = 1;
 
426
            }
 
427
            cp = find_page_code_desc(k, 0, inq_pdt, inq_byte6, -1);
 
428
            if (cp)
 
429
                printf("    %s\n", cp);
 
430
            else
 
431
                printf("    [0x%x]\n", k);
 
432
        } else if (SG_LIB_CAT_NOT_READY == res)
 
433
            fprintf(stderr, "MODE SENSE failed, device not ready\n");
 
434
    }
 
435
    return res;
403
436
}
404
437
 
405
438
static const char * pg_control_str_arr[] = {
406
439
    "current",
407
440
    "changeable",
408
441
    "default",
409
 
    "saved"};
 
442
    "saved",
 
443
};
410
444
 
411
445
static void usage()
412
446
{
413
 
    printf("Usage: 'sg_modes [-a] [-c=<page_control] [-d] [-h] [-l] "
414
 
           "[-p=<page_number>]\n\t\t [-subp=<sub_page_code>] [-v] [-V] "
415
 
           "[-6] [<sg_device>]'\n"
416
 
           " where -a   get all mode pages\n"
 
447
    printf("Usage:  sg_modes [-a] [-A] [-c=<page_control] [-d] [-D] [-f] "
 
448
           "[-e] [-h] [-H]\n\t\t"
 
449
           " [-l] [-L] [-p=<page_number>[,<sub_page_code>]] [-r]"
 
450
           "\n\t\t [-subp=<sub_page_code>] [-v] [-V] [-6] [<scsi_device>]\n"
 
451
           " where -a   get all mode pages supported by device\n"
 
452
           "       -A   get all mode pages and subpages supported by device\n"
417
453
           "       -c=<page_control> page control (def: 0 [current],"
418
454
           " 1 [changeable],\n            2 [default], 3 [saved])\n"
419
 
           "       -d   disable block descriptors\n"
420
 
           "       -h   output in hex\n"
421
 
           "       -l   list common page codes\n"
422
 
           "       -p=<page_code> page code (in hex, def: 0)\n"
 
455
           "       -d   disable block descriptors (DBD field in cdb)\n"
 
456
           "       -e   examine pages # 0 through to 0x3e, note if found\n"
 
457
           "       -D   disable block descriptor output\n"
 
458
           "       -f   be flexible, cope with MODE SENSE 6/10 response "
 
459
           "mixup\n");
 
460
    printf("       -h   output page number and header in hex\n"
 
461
           "       -H   output page number and header in hex (same as '-h')\n"
 
462
           "       -l   list common page codes for device peripheral type,\n"
 
463
           "            if no device given then assume disk type\n"
 
464
           "       -L   set Long LBA Accepted (LLBAA field in mode sense "
 
465
           "10 cdb)\n"
 
466
           "       -p=<page_code> page code in hex (def: 0)\n"
 
467
           "       -p=<page_code>,<sub_page_code> both in hex, (defs: 0)\n"
 
468
           "       -r   mode page output to stdout, a byte per line in "
 
469
           "ASCII hex\n"
423
470
           "       -subp=<sub_page_code> (in hex, def: 0)\n"
424
471
           "       -v   verbose\n"
425
472
           "       -V   output version string\n"
426
 
           "       -6   Use MODE SENSE(6) instead of MODE SENSE(10)\n"
427
 
           "       -?   output this usage message\n");
 
473
           "       -6   Use MODE SENSE(6), by default uses MODE SENSE(10)\n"
 
474
           "       -?   output this usage message\n\n"
 
475
           "Performs a SCSI MODE SENSE commmand\n");
428
476
}
429
477
 
430
478
 
431
479
int main(int argc, char * argv[])
432
480
{
433
 
    int sg_fd, k, num, len, md_len, bd_len, longlba, page_num, spf;
434
 
    char * file_name = 0;
 
481
    int sg_fd, k, num, len, res, md_len, bd_len, longlba, page_num, spf;
 
482
    const char * file_name = 0;
435
483
    char ebuff[EBUFF_SZ];
436
484
    const char * descp;
 
485
    const char * cp;
437
486
    unsigned char rsp_buff[MX_ALLOC_LEN];
438
487
    int rsp_buff_size = MX_ALLOC_LEN;
439
 
    unsigned int u;
 
488
    unsigned int u, uu;
440
489
    int pg_code = -1;
441
490
    int sub_pg_code = 0;
 
491
    int sub_pg_code_set = 0;
442
492
    int pc = 0;
443
493
    int do_all = 0;
 
494
    int do_all_sub = 0;
444
495
    int do_dbd = 0;
 
496
    int no_desc_out = 0;
 
497
    int do_examine = 0;
 
498
    int flexible = 0;
445
499
    int do_hex = 0;
 
500
    int do_llbaa = 0;
446
501
    int do_mode6 = 0;  /* Use MODE SENSE(6) instead of MODE SENSE(10) */
447
502
    int do_list = 0;
 
503
    int do_raw = 0;
448
504
    int do_verbose = 0;
449
 
    int oflags = O_RDONLY | O_NONBLOCK;
450
 
    int density_code_off;
 
505
    int ret = 0;
 
506
    int density_code_off, t_proto, inq_pdt, inq_byte6, resp_mode6;
 
507
    int num_ua_pages, plen, jmp_out;
451
508
    unsigned char * ucp;
452
509
    unsigned char uc;
453
 
    struct simple_inquiry_t inq_out;
 
510
    struct sg_simple_inquiry_resp inq_out;
 
511
    char pdt_name[64];
454
512
 
455
513
    for (k = 1; k < argc; ++k) {
456
 
        if (0 == strncmp("-p=", argv[k], 3)) {
457
 
            num = sscanf(argv[k] + 3, "%x", &u);
458
 
            if ((1 != num) || (u > 63)) {
459
 
                printf("Bad page code after '-p' switch\n");
460
 
                file_name = 0;
461
 
                break;
462
 
            }
463
 
            pg_code = u;
464
 
        }
465
 
        else if (0 == strncmp("-subp=", argv[k], 6)) {
466
 
            num = sscanf(argv[k] + 6, "%x", &u);
467
 
            if ((1 != num) || (u > 255)) {
468
 
                printf("Bad sub page code after '-subp' switch\n");
469
 
                file_name = 0;
470
 
                break;
471
 
            }
472
 
            sub_pg_code = u;
473
 
            if (-1 == pg_code)
474
 
                pg_code = 0;
475
 
        }
476
 
        else if (0 == strncmp("-c=", argv[k], 3)) {
477
 
            num = sscanf(argv[k] + 3, "%x", &u);
478
 
            if ((1 != num) || (u > 3)) {
479
 
                printf("Bad page control after '-c' switch\n");
480
 
                file_name = 0;
481
 
                break;
482
 
            }
483
 
            pc = u;
484
 
        }
485
 
        else if (0 == strcmp("-d", argv[k]))
486
 
            do_dbd = 1;
487
 
        else if (0 == strcmp("-a", argv[k]))
488
 
            do_all = 1;
489
 
        else if (0 == strcmp("-h", argv[k]))
490
 
            do_hex = 1;
491
 
        else if (0 == strcmp("-6", argv[k]))
492
 
            do_mode6 = 1;
493
 
        else if (0 == strcmp("-l", argv[k]))
494
 
            do_list = 1;
495
 
        else if (0 == strcmp("-v", argv[k]))
496
 
            ++do_verbose;
497
 
        else if (0 == strcmp("-?", argv[k])) {
498
 
            usage();
499
 
            return 0;
500
 
        }
501
 
        else if (0 == strcmp("-V", argv[k])) {
502
 
            printf("Version string: %s\n", version_str);
503
 
            exit(0);
504
 
        }
505
 
        else if (*argv[k] == '-') {
506
 
            printf("Unrecognized switch: %s\n", argv[k]);
507
 
            file_name = 0;
508
 
            break;
509
 
        }
510
 
        else if (0 == file_name)
511
 
            file_name = argv[k];
 
514
        cp = argv[k];
 
515
        plen = strlen(cp);
 
516
        if (plen <= 0)
 
517
            continue;
 
518
        if ('-' == *cp) {
 
519
            for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
 
520
                switch (*cp) {
 
521
                case '6':
 
522
                    do_mode6 = 1;
 
523
                    break;
 
524
                case 'a':
 
525
                    do_all = 1;
 
526
                    break;
 
527
                case 'A':
 
528
                    do_all = 1;
 
529
                    do_all_sub = 1;
 
530
                    break;
 
531
                case 'd':
 
532
                    do_dbd = 1;
 
533
                    break;
 
534
                case 'D':
 
535
                    no_desc_out = 1;
 
536
                    break;
 
537
                case 'e':
 
538
                    do_examine = 1;
 
539
                    break;
 
540
                case 'f':
 
541
                    flexible = 1;
 
542
                    break;
 
543
                case 'h':
 
544
                case 'H':
 
545
                    do_hex = 1;
 
546
                    break;
 
547
                case 'l':
 
548
                    do_list = 1;
 
549
                    break;
 
550
                case 'L':
 
551
                    do_llbaa = 1;
 
552
                    break;
 
553
                case 'r':
 
554
                    do_raw = 1;
 
555
                    break;
 
556
                case 'v':
 
557
                    ++do_verbose;
 
558
                    break;
 
559
                case 'V':
 
560
                    fprintf(stderr, "Version string: %s\n", version_str);
 
561
                    exit(0);
 
562
                case '?':
 
563
                    usage();
 
564
                    return 0;
 
565
                default:
 
566
                    jmp_out = 1;
 
567
                    break;
 
568
                }
 
569
                if (jmp_out)
 
570
                    break;
 
571
            }
 
572
            if (plen <= 0)
 
573
                continue;
 
574
            if (0 == strncmp("c=", cp, 2)) {
 
575
                num = sscanf(cp + 2, "%x", &u);
 
576
                if ((1 != num) || (u > 3)) {
 
577
                    fprintf(stderr, "Bad page control after 'c=' option\n");
 
578
                    usage();
 
579
                    return SG_LIB_SYNTAX_ERROR;
 
580
                }
 
581
                pc = u;
 
582
            } else if (0 == strncmp("p=", cp, 2)) {
 
583
                if (NULL == strchr(cp + 2, ',')) {
 
584
                    num = sscanf(cp + 2, "%x", &u);
 
585
                    if ((1 != num) || (u > 63)) {
 
586
                        fprintf(stderr, "Bad page code value after 'p=' "
 
587
                                "option\n");
 
588
                        usage();
 
589
                        return SG_LIB_SYNTAX_ERROR;
 
590
                    }
 
591
                    pg_code = u;
 
592
                } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) {
 
593
                    if (uu > 255) {
 
594
                        fprintf(stderr, "Bad sub page code value after 'p=' "
 
595
                                "option\n");
 
596
                        usage();
 
597
                        return SG_LIB_SYNTAX_ERROR;
 
598
                    }
 
599
                    pg_code = u;
 
600
                    sub_pg_code = uu;
 
601
                    sub_pg_code_set = 1;
 
602
                } else {
 
603
                    fprintf(stderr, "Bad page code, subpage code sequence "
 
604
                            "after 'p=' option\n");
 
605
                    usage();
 
606
                    return SG_LIB_SYNTAX_ERROR;
 
607
                }
 
608
            } else if (0 == strncmp("subp=", cp, 5)) {
 
609
                num = sscanf(cp + 5, "%x", &u);
 
610
                if ((1 != num) || (u > 255)) {
 
611
                    fprintf(stderr, "Bad sub page code after 'subp=' "
 
612
                            "option\n");
 
613
                    usage();
 
614
                    return SG_LIB_SYNTAX_ERROR;
 
615
                }
 
616
                sub_pg_code = u;
 
617
                sub_pg_code_set = 1;
 
618
                if (-1 == pg_code)
 
619
                    pg_code = 0;
 
620
            } else if (jmp_out) {
 
621
                fprintf(stderr, "Unrecognized option: %s\n", cp);
 
622
                usage();
 
623
                return SG_LIB_SYNTAX_ERROR;
 
624
            }
 
625
        } else if (0 == file_name)
 
626
            file_name = cp;
512
627
        else {
513
 
            printf("too many arguments\n");
514
 
            file_name = 0;
515
 
            break;
 
628
            fprintf(stderr, "too many arguments, got: %s, not expecting: "
 
629
                    "%s\n", file_name, cp);
 
630
            usage();
 
631
            return SG_LIB_SYNTAX_ERROR;
516
632
        }
517
633
    }
 
634
    
518
635
    if (0 == file_name) {
519
636
        if (do_list) {
520
 
            printf("Assume 'disk' device type\n");
521
 
            list_page_codes(0);
 
637
            if ((pg_code < 0) || (pg_code > 0x1f)) {
 
638
                printf("    Assume peripheral device type: disk\n");
 
639
                list_page_codes(0, 0, -1);
 
640
            } else {
 
641
                printf("    peripheral device type: %s\n",
 
642
                       sg_get_pdt_str(pg_code, sizeof(pdt_name), pdt_name));
 
643
                if (sub_pg_code_set)
 
644
                    list_page_codes(pg_code, 0, sub_pg_code);
 
645
                else
 
646
                    list_page_codes(pg_code, 0, -1);
 
647
            }
522
648
            return 0;
523
649
        }
 
650
        fprintf(stderr, "No <scsi_device> argument given\n");
524
651
        usage();
525
 
        return 1;
 
652
        return SG_LIB_SYNTAX_ERROR;
 
653
    }
 
654
 
 
655
    if (do_examine && (pg_code >= 0)) {
 
656
        fprintf(stderr, "can't give '-e' and a page number\n");
 
657
        return SG_LIB_SYNTAX_ERROR;
526
658
    }
527
659
 
528
660
    /* The 6 bytes command only allows up to 252 bytes of response data */
529
 
    if (do_mode6) 
 
661
    if (do_mode6) { 
 
662
        if (do_llbaa) {
 
663
            fprintf(stderr, "LLBAA not defined for MODE SENSE 6, try "
 
664
                    "without '-L'\n");
 
665
            return SG_LIB_SYNTAX_ERROR;
 
666
        }
530
667
        rsp_buff_size = 252;
 
668
    }
531
669
    /* If no pages or list selected than treat as 'a' */
532
 
    if (! ((pg_code >= 0) || do_all || do_list))
 
670
    if (! ((pg_code >= 0) || do_all || do_list || do_examine))
533
671
        do_all = 1;
534
672
 
535
 
    if ((sg_fd = open(file_name, oflags)) < 0) {
536
 
        snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", file_name);
537
 
        perror(ebuff);
538
 
        return 1;
539
 
    }
540
 
 
541
 
    if (do_simple_inq(sg_fd, 1, &inq_out, do_verbose)) {
542
 
        printf(ME "%s doesn't respond to a SCSI INQUIRY\n", file_name);
543
 
        close(sg_fd);
544
 
        return 1;
545
 
    }
546
 
    printf("    %.8s  %.16s  %.4s   peripheral_type: %s [0x%x]\n", 
547
 
           inq_out.vendor, inq_out.product, inq_out.revision,
548
 
           get_ptype_str(inq_out.peripheral_type), inq_out.peripheral_type);
549
 
 
 
673
    if ((sg_fd = sg_cmds_open_device(file_name, 1 /* ro */, do_verbose)) < 0) {
 
674
        fprintf(stderr, ME "error opening file: %s: %s\n", file_name,
 
675
                safe_strerror(-sg_fd));
 
676
        return SG_LIB_FILE_ERROR;
 
677
    }
 
678
 
 
679
    if (sg_simple_inquiry(sg_fd, &inq_out, 1, do_verbose)) {
 
680
        fprintf(stderr, ME "%s doesn't respond to a SCSI INQUIRY\n",
 
681
                file_name);
 
682
        sg_cmds_close_device(sg_fd);
 
683
        return SG_LIB_CAT_OTHER;
 
684
    }
 
685
    inq_pdt = inq_out.peripheral_type;
 
686
    inq_byte6 = inq_out.byte_6;
 
687
    if (0 == do_raw)
 
688
        printf("    %.8s  %.16s  %.4s   peripheral_type: %s [0x%x]\n", 
 
689
               inq_out.vendor, inq_out.product, inq_out.revision,
 
690
               sg_get_pdt_str(inq_pdt, sizeof(pdt_name), pdt_name), inq_pdt);
550
691
    if (do_list) {
551
 
        list_page_codes(inq_out.peripheral_type);
 
692
        if (sub_pg_code_set)
 
693
            list_page_codes(inq_pdt, inq_byte6, sub_pg_code);
 
694
        else
 
695
            list_page_codes(inq_pdt, inq_byte6, -1);
552
696
        return 0;
553
697
    }
 
698
    if (do_examine) {
 
699
        ret = examine_pages(sg_fd, do_mode6, inq_pdt, inq_byte6, do_verbose);
 
700
        goto finish;
 
701
    }
554
702
    if (PG_CODE_ALL == pg_code)
555
703
        do_all = 1;
556
704
    else if (do_all)
557
705
        pg_code = PG_CODE_ALL;
558
 
 
559
 
    if (0 == do_modes(sg_fd, do_dbd, pc, pg_code, sub_pg_code, 
560
 
                      rsp_buff, rsp_buff_size, 1, do_mode6, do_verbose)) {
 
706
    if (do_all && do_all_sub)
 
707
        sub_pg_code = SPG_CODE_ALL;
 
708
 
 
709
    if (do_raw) {
 
710
        if (do_all) {
 
711
            fprintf(stderr, "'-r' requires a given (sub)page (not all)\n");
 
712
            usage();
 
713
            return SG_LIB_SYNTAX_ERROR;
 
714
        }
 
715
        if (do_hex) {
 
716
            fprintf(stderr, "'-r' and '-h' clash");
 
717
            usage();
 
718
            return SG_LIB_SYNTAX_ERROR;
 
719
        }
 
720
    }
 
721
 
 
722
    memset(rsp_buff, 0, sizeof(rsp_buff));
 
723
    if (do_mode6) {
 
724
        res = sg_ll_mode_sense6(sg_fd, do_dbd, pc, pg_code, sub_pg_code,
 
725
                                rsp_buff, rsp_buff_size, 1, do_verbose);
 
726
        if (SG_LIB_CAT_INVALID_OP == res)
 
727
            fprintf(stderr, ">>>>>> try again without the '-6' "
 
728
                    "switch for a 10 byte MODE SENSE command\n");
 
729
        else if (SG_LIB_CAT_ILLEGAL_REQ == res)
 
730
            fprintf(stderr, "invalid field in cdb (perhaps subpages "
 
731
                    "or page control (PC) not supported)\n");
 
732
    } else {
 
733
        res = sg_ll_mode_sense10(sg_fd, do_llbaa, do_dbd, pc, pg_code,
 
734
                                 sub_pg_code, rsp_buff, rsp_buff_size, 1,
 
735
                                 do_verbose);
 
736
        if (SG_LIB_CAT_INVALID_OP == res)
 
737
            fprintf(stderr, ">>>>>> try again with a '-6' "
 
738
                    "switch for a 6 byte MODE SENSE command\n");
 
739
        else if (SG_LIB_CAT_ILLEGAL_REQ == res)
 
740
            fprintf(stderr, "invalid field in cdb (perhaps subpages "
 
741
                    "or page control (PC) not supported)\n");
 
742
    }
 
743
    if (SG_LIB_CAT_ILLEGAL_REQ == res)
 
744
        fprintf(stderr, "invalid field in cdb (perhaps subpages "
 
745
                "or page control (PC) not supported)\n");
 
746
    else if (SG_LIB_CAT_NOT_READY == res)
 
747
        fprintf(stderr, "device not ready\n");
 
748
    else if (SG_LIB_CAT_UNIT_ATTENTION == res)
 
749
        fprintf(stderr, "unit attention\n");
 
750
    ret = res;
 
751
    if (0 == res) {
561
752
        int medium_type, specific, headerlen;
562
753
 
563
 
        printf("Mode parameter header from %s byte MODE SENSE:\n",
564
 
               (do_mode6 ? "6" : "10"));
565
 
        if (do_mode6) {
 
754
        ret = 0;
 
755
        resp_mode6 = do_mode6;
 
756
        if (flexible) {
 
757
            num = rsp_buff[0];
 
758
            if (do_mode6 && (num < 3))
 
759
                resp_mode6 = 0;
 
760
            if ((0 == do_mode6) && (num > 5)) {
 
761
                if ((num > 11) && (0 == (num % 2)) && (0 == rsp_buff[4]) &&
 
762
                    (0 == rsp_buff[5]) && (0 == rsp_buff[6])) {
 
763
                    rsp_buff[1] = num;
 
764
                    rsp_buff[0] = 0;
 
765
                    fprintf(stderr, ">>> msense(10) but resp[0]=%d and "
 
766
                            "not msense(6) response so fix length\n", num);
 
767
                } else
 
768
                    resp_mode6 = 1;
 
769
            }
 
770
        }
 
771
        if (! do_raw) {
 
772
            if (resp_mode6 == do_mode6)
 
773
                printf("Mode parameter header from %s byte MODE SENSE:\n",
 
774
                       (do_mode6 ? "6" : "10"));
 
775
            else
 
776
                printf(" >>> Mode parameter header from %s byte MODE "
 
777
                       "SENSE,\n     decoded as %s byte response:\n",
 
778
                       (do_mode6 ? "6" : "10"), (resp_mode6 ? "6" : "10"));
 
779
        }
 
780
        if (resp_mode6) {
566
781
            headerlen = 4;
567
 
            md_len = rsp_buff[0]+1;
 
782
            md_len = rsp_buff[0] + 1;
568
783
            bd_len = rsp_buff[3];
569
784
            medium_type = rsp_buff[1];
570
785
            specific = rsp_buff[2];
571
 
            longlba = 0; /* what is this field? */
 
786
            longlba = 0;
572
787
        } else {
573
788
            headerlen = 8;
574
789
            md_len = (rsp_buff[0] << 8) + rsp_buff[1] + 2;
577
792
            specific = rsp_buff[3];
578
793
            longlba = rsp_buff[4] & 1;
579
794
        }
 
795
        if (do_raw) {
 
796
            ucp = rsp_buff + bd_len + headerlen; 
 
797
            md_len -= bd_len + headerlen;
 
798
            spf = ((ucp[0] & 0x40) ? 1 : 0);
 
799
            len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2));
 
800
            len = (len < md_len) ? len : md_len;
 
801
            for (k = 0; k < len; ++k)
 
802
                printf("%02x\n", ucp[k]);
 
803
            sg_cmds_close_device(sg_fd);
 
804
            return 0;
 
805
        }
580
806
        if (do_hex)
581
807
            dStrHex((const char *)rsp_buff, headerlen, 1);
582
 
        printf("  Mode data length=%d, medium type=0x%.2x, specific"
583
 
               " param=0x%.2x, longlba=%d\n", md_len, medium_type, 
584
 
               specific, longlba);
 
808
        if (0 == inq_pdt)
 
809
            printf("  Mode data length=%d, medium type=0x%.2x, WP=%d,"
 
810
                   " DpoFua=%d, longlba=%d\n", md_len, medium_type, 
 
811
                   !!(specific & 0x80), !!(specific & 0x10), longlba);
 
812
        else
 
813
            printf("  Mode data length=%d, medium type=0x%.2x, specific"
 
814
                   " param=0x%.2x, longlba=%d\n", md_len, medium_type, 
 
815
                   specific, longlba);
585
816
        if (md_len > rsp_buff_size) {
586
817
            printf("Only fetched %d bytes of response, truncate output\n",
587
818
                   rsp_buff_size);
589
820
            if (bd_len + headerlen > rsp_buff_size)
590
821
                bd_len = rsp_buff_size - headerlen;
591
822
        }
592
 
        printf("  Block descriptor length=%d\n", bd_len);
593
 
        if (bd_len > 0) {
594
 
            len = 8;
595
 
            density_code_off = 0;
596
 
            num = bd_len;
597
 
            if (longlba) {
598
 
                printf("> longlba block descriptors:\n");
599
 
                len = 16;
600
 
                density_code_off = 8;
601
 
            }
602
 
            else if (0 == inq_out.peripheral_type) { 
603
 
                printf("> Direct access device block descriptors:\n");
604
 
                density_code_off = 4;
605
 
            }
606
 
            else
607
 
                printf("> General mode parameter block descriptors:\n");
608
 
 
609
 
            ucp = rsp_buff + headerlen;
610
 
            while (num > 0) {
611
 
                printf("   Density code=0x%x\n", *(ucp + density_code_off));
612
 
                dStrHex((const char *)ucp, len, 1);
613
 
                ucp += len;
614
 
                num -= len;
615
 
            }
616
 
            printf("\n");
 
823
        if (! no_desc_out) {
 
824
            printf("  Block descriptor length=%d\n", bd_len);
 
825
            if (bd_len > 0) {
 
826
                len = 8;
 
827
                density_code_off = 0;
 
828
                num = bd_len;
 
829
                if (longlba) {
 
830
                    printf("> longlba block descriptors:\n");
 
831
                    len = 16;
 
832
                    density_code_off = 8;
 
833
                }
 
834
                else if (0 == inq_pdt) { 
 
835
                    printf("> Direct access device block descriptors:\n");
 
836
                    density_code_off = 4;
 
837
                }
 
838
                else
 
839
                    printf("> General mode parameter block descriptors:\n");
 
840
    
 
841
                ucp = rsp_buff + headerlen;
 
842
                while (num > 0) {
 
843
                    printf("   Density code=0x%x\n", *(ucp + density_code_off));
 
844
                    dStrHex((const char *)ucp, len, 1);
 
845
                    ucp += len;
 
846
                    num -= len;
 
847
                }
 
848
                printf("\n");
 
849
            }
617
850
        }
618
851
        ucp = rsp_buff + bd_len + headerlen;    /* start of mode page(s) */
619
852
        md_len -= bd_len + headerlen;           /* length of mode page(s) */
 
853
        num_ua_pages = 0;
620
854
        for (k = 0; md_len > 0; ++k) { /* got mode page(s) */
621
855
            if ((k > 0) && (! do_all) && (SPG_CODE_ALL != sub_pg_code)) {
622
856
                fprintf(stderr, "Unexpectedly received extra mode page "
627
861
            spf = ((uc & 0x40) ? 1 : 0);
628
862
            len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2));
629
863
            page_num = ucp[0] & PG_CODE_MASK;
 
864
            if (0x0 == page_num) {
 
865
                ++num_ua_pages;
 
866
                if((num_ua_pages > 3) && (md_len > 0xa00)) {
 
867
                    fprintf(stderr, ">>> Seen 3 unit attention pages "
 
868
                            "(only one should be at end)\n     and mpage "
 
869
                            "length=%d, looks malformed, try '-f' option\n",
 
870
                            md_len);
 
871
                    break;
 
872
                }
 
873
            }
630
874
            if (do_hex) {
631
875
                if (spf)
632
876
                    printf(">> page_code=0x%x, subpage_code=0x%x, "
635
879
                    printf(">> page_code=0x%x, page_control=%d\n", page_num,
636
880
                           pc);
637
881
            } else {
638
 
                descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0),
639
 
                                            inq_out.peripheral_type);
 
882
                descp = NULL;
 
883
                if ((0x18 == page_num) || (0x19 == page_num)) {
 
884
                    t_proto = (spf ? ucp[5] : ucp[2]) & 0xf;
 
885
                    descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0),
 
886
                                                inq_pdt, inq_byte6, t_proto);
 
887
                } else
 
888
                    descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0),
 
889
                                                inq_pdt, inq_byte6, -1);
640
890
                if (NULL == descp) {
641
891
                    if (spf)
642
892
                        snprintf(ebuff, EBUFF_SZ, "0x%x, subpage_code: 0x%x",
644
894
                    else
645
895
                        snprintf(ebuff, EBUFF_SZ, "0x%x", page_num);
646
896
                }
647
 
                printf(">> page_code: %s, page_control: %s\n", 
648
 
                       (descp ? descp: ebuff), pg_control_str_arr[pc]);
649
 
            }
650
 
            dStrHex((const char *)ucp, ((len > md_len) ? md_len : len) , 1);
 
897
                if (descp)
 
898
                    printf(">> %s, page_control: %s\n", descp,
 
899
                           pg_control_str_arr[pc]);
 
900
                else
 
901
                    printf(">> page_code: %s, page_control: %s\n", ebuff,
 
902
                           pg_control_str_arr[pc]);
 
903
            }
 
904
            num = (len > md_len) ? md_len : len;
 
905
            if ((k > 0) && (num > 256)) {
 
906
                num = 256;
 
907
                fprintf(stderr, ">>> page length (%d) > 256 bytes, unlikely "
 
908
                                "trim\n    Try '-f' option\n", len);
 
909
            }
 
910
            dStrHex((const char *)ucp, num , 1);
651
911
            ucp += len;
652
912
            md_len -= len;
653
913
        }
654
914
    }
655
 
    close(sg_fd);
656
 
    return 0;
 
915
finish:
 
916
    sg_cmds_close_device(sg_fd);
 
917
    return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
657
918
}