1/*
2 * Copyright (c) 1999-2018 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 */
7
8/*
9 * CONTENTS
10 *    Some SCSI commands are executed in many contexts and hence began
11 *    to appear in several sg3_utils utilities. This files centralizes
12 *    some of the low level command execution code. In most cases the
13 *    interpretation of the command response is left to the each
14 *    utility.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <stdarg.h>
20#include <string.h>
21#include <unistd.h>
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "sg_lib.h"
28#include "sg_cmds_basic.h"
29#include "sg_pt.h"
30#include "sg_unaligned.h"
31
32
33
34#define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
35#define EBUFF_SZ 256
36
37#define DEF_PT_TIMEOUT 60       /* 60 seconds */
38#define START_PT_TIMEOUT 120    /* 120 seconds == 2 minutes */
39#define LONG_PT_TIMEOUT 7200    /* 7,200 seconds == 120 minutes */
40
41#define SYNCHRONIZE_CACHE_CMD     0x35
42#define SYNCHRONIZE_CACHE_CMDLEN  10
43#define SERVICE_ACTION_IN_16_CMD 0x9e
44#define SERVICE_ACTION_IN_16_CMDLEN 16
45#define READ_CAPACITY_16_SA 0x10
46#define READ_CAPACITY_10_CMD 0x25
47#define READ_CAPACITY_10_CMDLEN 10
48#define MODE_SENSE6_CMD      0x1a
49#define MODE_SENSE6_CMDLEN   6
50#define MODE_SENSE10_CMD     0x5a
51#define MODE_SENSE10_CMDLEN  10
52#define MODE_SELECT6_CMD   0x15
53#define MODE_SELECT6_CMDLEN   6
54#define MODE_SELECT10_CMD   0x55
55#define MODE_SELECT10_CMDLEN  10
56#define LOG_SENSE_CMD     0x4d
57#define LOG_SENSE_CMDLEN  10
58#define LOG_SELECT_CMD     0x4c
59#define LOG_SELECT_CMDLEN  10
60#define START_STOP_CMD          0x1b
61#define START_STOP_CMDLEN       6
62#define PREVENT_ALLOW_CMD    0x1e
63#define PREVENT_ALLOW_CMDLEN   6
64
65#define MODE6_RESP_HDR_LEN 4
66#define MODE10_RESP_HDR_LEN 8
67#define MODE_RESP_ARB_LEN 1024
68
69#define INQUIRY_RESP_INITIAL_LEN 36
70
71
72#if defined(__GNUC__) || defined(__clang__)
73static int pr2ws(const char * fmt, ...)
74        __attribute__ ((format (printf, 1, 2)));
75#else
76static int pr2ws(const char * fmt, ...);
77#endif
78
79
80static int
81pr2ws(const char * fmt, ...)
82{
83    va_list args;
84    int n;
85
86    va_start(args, fmt);
87    n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
88    va_end(args);
89    return n;
90}
91
92static struct sg_pt_base *
93create_pt_obj(const char * cname)
94{
95    struct sg_pt_base * ptvp = construct_scsi_pt_obj();
96    if (NULL == ptvp)
97        pr2ws("%s: out of memory\n", cname);
98    return ptvp;
99}
100
101/* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
102 * various SG_LIB_CAT_* positive values or -1 -> other errors */
103int
104sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
105                    unsigned int lba, unsigned int count, bool noisy,
106                    int verbose)
107{
108    static const char * const cdb_name_s = "synchronize cache(10)";
109    int res, ret, k, sense_cat;
110    unsigned char sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] =
111                {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
112    unsigned char sense_b[SENSE_BUFF_LEN];
113    struct sg_pt_base * ptvp;
114
115    if (sync_nv)
116        sc_cdb[1] |= 4;
117    if (immed)
118        sc_cdb[1] |= 2;
119    sg_put_unaligned_be32((uint32_t)lba, sc_cdb + 2);
120    sc_cdb[6] = group & 0x1f;
121    if (count > 0xffff) {
122        pr2ws("count too big\n");
123        return -1;
124    }
125    sg_put_unaligned_be16((int16_t)count, sc_cdb + 7);
126
127    if (verbose) {
128        pr2ws("    %s cdb: ", cdb_name_s);
129        for (k = 0; k < SYNCHRONIZE_CACHE_CMDLEN; ++k)
130            pr2ws("%02x ", sc_cdb[k]);
131        pr2ws("\n");
132    }
133    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
134        return -1;
135    set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb));
136    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
137    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
138    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
139                               noisy, verbose, &sense_cat);
140    if (-1 == ret) {
141        int os_err = get_scsi_pt_os_err(ptvp);
142
143        if ((os_err > 0) && (os_err < 47))
144            ret = SG_LIB_OS_BASE_ERR + os_err;
145    } else if (-2 == ret) {
146        switch (sense_cat) {
147        case SG_LIB_CAT_RECOVERED:
148        case SG_LIB_CAT_NO_SENSE:
149            ret = 0;
150            break;
151        default:
152            ret = sense_cat;
153            break;
154        }
155    } else
156        ret = 0;
157
158    destruct_scsi_pt_obj(ptvp);
159    return ret;
160}
161
162/* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
163 * various SG_LIB_CAT_* positive values or -1 -> other errors */
164int
165sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
166                 int mx_resp_len, bool noisy, int verbose)
167{
168    static const char * const cdb_name_s = "read capacity(16)";
169    int k, ret, res, sense_cat;
170    unsigned char rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
171                        {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
172                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
173    unsigned char sense_b[SENSE_BUFF_LEN];
174    struct sg_pt_base * ptvp;
175
176    if (pmi) { /* lbs only valid when pmi set */
177        rc_cdb[14] |= 1;
178        sg_put_unaligned_be64(llba, rc_cdb + 2);
179    }
180    /* Allocation length, no guidance in SBC-2 rev 15b */
181    sg_put_unaligned_be32((uint32_t)mx_resp_len, rc_cdb + 10);
182    if (verbose) {
183        pr2ws("    %s cdb: ", cdb_name_s);
184        for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
185            pr2ws("%02x ", rc_cdb[k]);
186        pr2ws("\n");
187    }
188    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
189        return -1;
190    set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
191    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
192    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
193    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
194    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
195                               noisy, verbose, &sense_cat);
196    if (-1 == ret) {
197        int os_err = get_scsi_pt_os_err(ptvp);
198
199        if ((os_err > 0) && (os_err < 47))
200            ret = SG_LIB_OS_BASE_ERR + os_err;
201    } else if (-2 == ret) {
202        switch (sense_cat) {
203        case SG_LIB_CAT_RECOVERED:
204        case SG_LIB_CAT_NO_SENSE:
205            ret = 0;
206            break;
207        default:
208            ret = sense_cat;
209            break;
210        }
211    } else
212        ret = 0;
213
214    destruct_scsi_pt_obj(ptvp);
215    return ret;
216}
217
218/* Invokes a SCSI READ CAPACITY (10) command. Returns 0 -> success,
219 * various SG_LIB_CAT_* positive values or -1 -> other errors */
220int
221sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
222                 int mx_resp_len, bool noisy, int verbose)
223{
224    static const char * const cdb_name_s = "read capacity(10)";
225    int k, ret, res, sense_cat;
226    unsigned char rc_cdb[READ_CAPACITY_10_CMDLEN] =
227                         {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
228    unsigned char sense_b[SENSE_BUFF_LEN];
229    struct sg_pt_base * ptvp;
230
231    if (pmi) { /* lbs only valid when pmi set */
232        rc_cdb[8] |= 1;
233        sg_put_unaligned_be32((uint32_t)lba, rc_cdb + 2);
234    }
235    if (verbose) {
236        pr2ws("    %s cdb: ", cdb_name_s);
237        for (k = 0; k < READ_CAPACITY_10_CMDLEN; ++k)
238            pr2ws("%02x ", rc_cdb[k]);
239        pr2ws("\n");
240    }
241    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
242        return -1;
243    set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
244    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
245    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
246    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
247    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
248                               noisy, verbose, &sense_cat);
249    if (-1 == ret) {
250        int os_err = get_scsi_pt_os_err(ptvp);
251
252        if ((os_err > 0) && (os_err < 47))
253            ret = SG_LIB_OS_BASE_ERR + os_err;
254    } else if (-2 == ret) {
255        switch (sense_cat) {
256        case SG_LIB_CAT_RECOVERED:
257        case SG_LIB_CAT_NO_SENSE:
258            ret = 0;
259            break;
260        default:
261            ret = sense_cat;
262            break;
263        }
264    } else
265        ret = 0;
266
267    destruct_scsi_pt_obj(ptvp);
268    return ret;
269}
270
271/* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success,
272 * various SG_LIB_CAT_* positive values or -1 -> other errors */
273int
274sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code, int sub_pg_code,
275                  void * resp, int mx_resp_len, bool noisy, int verbose)
276{
277    static const char * const cdb_name_s = "mode sense(6)";
278    int res, ret, k, sense_cat, resid;
279    unsigned char modes_cdb[MODE_SENSE6_CMDLEN] =
280        {MODE_SENSE6_CMD, 0, 0, 0, 0, 0};
281    unsigned char sense_b[SENSE_BUFF_LEN];
282    struct sg_pt_base * ptvp;
283
284    modes_cdb[1] = (unsigned char)(dbd ? 0x8 : 0);
285    modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
286    modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
287    modes_cdb[4] = (unsigned char)(mx_resp_len & 0xff);
288    if (mx_resp_len > 0xff) {
289        pr2ws("mx_resp_len too big\n");
290        return -1;
291    }
292    if (verbose) {
293        pr2ws("    %s cdb: ", cdb_name_s);
294        for (k = 0; k < MODE_SENSE6_CMDLEN; ++k)
295            pr2ws("%02x ", modes_cdb[k]);
296        pr2ws("\n");
297    }
298    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
299        return -1;
300    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
301    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
302    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
303    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
304    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
305                               noisy, verbose, &sense_cat);
306    resid = get_scsi_pt_resid(ptvp);
307    if (-1 == ret) {
308        int os_err = get_scsi_pt_os_err(ptvp);
309
310        if ((os_err > 0) && (os_err < 47))
311            ret = SG_LIB_OS_BASE_ERR + os_err;
312    } else if (-2 == ret) {
313        switch (sense_cat) {
314        case SG_LIB_CAT_RECOVERED:
315        case SG_LIB_CAT_NO_SENSE:
316            ret = 0;
317            break;
318        default:
319            ret = sense_cat;
320            break;
321        }
322    } else {
323        if ((verbose > 2) && (ret > 0)) {
324            pr2ws("    %s: response", cdb_name_s);
325            if (3 == verbose) {
326                pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
327                hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
328                           -1);
329            } else {
330                pr2ws(":\n");
331                hex2stderr((const uint8_t *)resp, ret, 0);
332            }
333        }
334        ret = 0;
335    }
336    destruct_scsi_pt_obj(ptvp);
337
338    if (resid > 0) {
339        if (resid > mx_resp_len) {
340            pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
341                  cdb_name_s, resid, mx_resp_len);
342            return ret ? ret : SG_LIB_CAT_MALFORMED;
343        }
344        /* zero unfilled section of response buffer */
345        memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
346    }
347    return ret;
348}
349
350/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
351 * various SG_LIB_CAT_* positive values or -1 -> other errors */
352int
353sg_ll_mode_sense10(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
354                   int sub_pg_code, void * resp, int mx_resp_len,
355                   bool noisy, int verbose)
356{
357    return sg_ll_mode_sense10_v2(sg_fd, llbaa, dbd, pc, pg_code, sub_pg_code,
358                                 resp, mx_resp_len, 0, NULL, noisy, verbose);
359}
360
361/* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
362 * various SG_LIB_CAT_* positive values or -1 -> other errors.
363 * Adds the ability to set the command abort timeout
364 * and the ability to report the residual count. If timeout_secs is zero
365 * or less the default command abort timeout (60 seconds) is used.
366 * If residp is non-NULL then the residual value is written where residp
367 * points. A residual value of 0 implies mx_resp_len bytes have be written
368 * where resp points. If the residual value equals mx_resp_len then no
369 * bytes have been written. */
370int
371sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
372                      int sub_pg_code, void * resp, int mx_resp_len,
373                      int timeout_secs, int * residp, bool noisy, int verbose)
374{
375    int res, ret, k, sense_cat, resid;
376    static const char * const cdb_name_s = "mode sense(10)";
377    struct sg_pt_base * ptvp;
378    unsigned char modes_cdb[MODE_SENSE10_CMDLEN] =
379        {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
380    unsigned char sense_b[SENSE_BUFF_LEN];
381
382    modes_cdb[1] = (unsigned char)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0));
383    modes_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
384    modes_cdb[3] = (unsigned char)(sub_pg_code & 0xff);
385    sg_put_unaligned_be16((int16_t)mx_resp_len, modes_cdb + 7);
386    if (mx_resp_len > 0xffff) {
387        pr2ws("mx_resp_len too big\n");
388        goto gen_err;
389    }
390    if (verbose) {
391        pr2ws("    %s cdb: ", cdb_name_s);
392        for (k = 0; k < MODE_SENSE10_CMDLEN; ++k)
393            pr2ws("%02x ", modes_cdb[k]);
394        pr2ws("\n");
395    }
396    if (timeout_secs <= 0)
397        timeout_secs = DEF_PT_TIMEOUT;
398
399    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
400        goto gen_err;
401    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
402    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
403    set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
404    res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
405    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
406                               noisy, verbose, &sense_cat);
407    resid = get_scsi_pt_resid(ptvp);
408    if (residp)
409        *residp = resid;
410    if (-1 == ret) {
411        int os_err = get_scsi_pt_os_err(ptvp);
412
413        if ((os_err > 0) && (os_err < 47))
414            ret = SG_LIB_OS_BASE_ERR + os_err;
415    } else if (-2 == ret) {
416        switch (sense_cat) {
417        case SG_LIB_CAT_RECOVERED:
418        case SG_LIB_CAT_NO_SENSE:
419            ret = 0;
420            break;
421        default:
422            ret = sense_cat;
423            break;
424        }
425    } else {
426        if ((verbose > 2) && (ret > 0)) {
427            pr2ws("    %s: response", cdb_name_s);
428            if (3 == verbose) {
429                pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
430                hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
431                           -1);
432            } else {
433                pr2ws(":\n");
434                hex2stderr((const uint8_t *)resp, ret, 0);
435            }
436        }
437        ret = 0;
438    }
439    destruct_scsi_pt_obj(ptvp);
440
441    if (resid > 0) {
442        if (resid > mx_resp_len) {
443            pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
444                  cdb_name_s, resid, mx_resp_len);
445            return ret ? ret : SG_LIB_CAT_MALFORMED;
446        }
447        /* zero unfilled section of response buffer */
448        memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
449    }
450    return ret;
451gen_err:
452    if (residp)
453        *residp = 0;
454    return -1;
455}
456
457/* Invokes a SCSI MODE SELECT (6) command.  Return of 0 -> success,
458 * various SG_LIB_CAT_* positive values or -1 -> other errors */
459int
460sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
461                   bool noisy, int verbose)
462{
463    static const char * const cdb_name_s = "mode select(6)";
464    int res, ret, k, sense_cat;
465    unsigned char modes_cdb[MODE_SELECT6_CMDLEN] =
466        {MODE_SELECT6_CMD, 0, 0, 0, 0, 0};
467    unsigned char sense_b[SENSE_BUFF_LEN];
468    struct sg_pt_base * ptvp;
469
470    modes_cdb[1] = (unsigned char)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
471    modes_cdb[4] = (unsigned char)(param_len & 0xff);
472    if (param_len > 0xff) {
473        pr2ws("%s: param_len too big\n", cdb_name_s);
474        return -1;
475    }
476    if (verbose) {
477        pr2ws("    %s cdb: ", cdb_name_s);
478        for (k = 0; k < MODE_SELECT6_CMDLEN; ++k)
479            pr2ws("%02x ", modes_cdb[k]);
480        pr2ws("\n");
481    }
482    if (verbose > 1) {
483        pr2ws("    %s parameter list\n", cdb_name_s);
484        hex2stderr((const uint8_t *)paramp, param_len, -1);
485    }
486
487    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
488        return -1;
489    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
490    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
491    set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
492    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
493    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
494                               noisy, verbose, &sense_cat);
495    if (-1 == ret) {
496        int os_err = get_scsi_pt_os_err(ptvp);
497
498        if ((os_err > 0) && (os_err < 47))
499            ret = SG_LIB_OS_BASE_ERR + os_err;
500    } else if (-2 == ret) {
501        switch (sense_cat) {
502        case SG_LIB_CAT_RECOVERED:
503        case SG_LIB_CAT_NO_SENSE:
504            ret = 0;
505            break;
506        default:
507            ret = sense_cat;
508            break;
509        }
510    } else
511        ret = 0;
512
513    destruct_scsi_pt_obj(ptvp);
514    return ret;
515}
516
517/* Invokes a SCSI MODE SELECT (10) command.  Return of 0 -> success,
518 * various SG_LIB_CAT_* positive values or -1 -> other errors */
519int
520sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
521                    bool noisy, int verbose)
522{
523    static const char * const cdb_name_s = "mode select(10)";
524    int res, ret, k, sense_cat;
525    unsigned char modes_cdb[MODE_SELECT10_CMDLEN] =
526        {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
527    unsigned char sense_b[SENSE_BUFF_LEN];
528    struct sg_pt_base * ptvp;
529
530    modes_cdb[1] = (unsigned char)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
531    sg_put_unaligned_be16((int16_t)param_len, modes_cdb + 7);
532    if (param_len > 0xffff) {
533        pr2ws("%s: param_len too big\n", cdb_name_s);
534        return -1;
535    }
536    if (verbose) {
537        pr2ws("    %s cdb: ", cdb_name_s);
538        for (k = 0; k < MODE_SELECT10_CMDLEN; ++k)
539            pr2ws("%02x ", modes_cdb[k]);
540        pr2ws("\n");
541    }
542    if (verbose > 1) {
543        pr2ws("    %s parameter list\n", cdb_name_s);
544        hex2stderr((const uint8_t *)paramp, param_len, -1);
545    }
546
547    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
548        return -1;
549    set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
550    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
551    set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
552    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
553    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
554                               noisy, verbose, &sense_cat);
555    if (-1 == ret) {
556        int os_err = get_scsi_pt_os_err(ptvp);
557
558        if ((os_err > 0) && (os_err < 47))
559            ret = SG_LIB_OS_BASE_ERR + os_err;
560    } else if (-2 == ret) {
561        switch (sense_cat) {
562        case SG_LIB_CAT_RECOVERED:
563        case SG_LIB_CAT_NO_SENSE:
564            ret = 0;
565            break;
566        default:
567            ret = sense_cat;
568            break;
569        }
570    } else
571        ret = 0;
572
573    destruct_scsi_pt_obj(ptvp);
574    return ret;
575}
576
577/* MODE SENSE commands yield a response that has header then zero or more
578 * block descriptors followed by mode pages. In most cases users are
579 * interested in the first mode page. This function returns the (byte)
580 * offset of the start of the first mode page. Set mode_sense_6 to true for
581 * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful
582 * or -1 if failure. If there is a failure a message is written to err_buff
583 * if it is non-NULL and err_buff_len > 0. */
584int
585sg_mode_page_offset(const unsigned char * resp, int resp_len,
586                    bool mode_sense_6, char * err_buff, int err_buff_len)
587{
588    int bd_len, calc_len, offset;
589    bool err_buff_ok = ((err_buff_len > 0) && err_buff);
590
591    if ((NULL == resp) || (resp_len < 4))
592            goto too_short;
593    if (mode_sense_6) {
594        calc_len = resp[0] + 1;
595        bd_len = resp[3];
596        offset = bd_len + MODE6_RESP_HDR_LEN;
597    } else {    /* Mode sense(10) */
598        if (resp_len < 8)
599            goto too_short;
600        calc_len = sg_get_unaligned_be16(resp) + 2;
601        bd_len = sg_get_unaligned_be16(resp + 6);
602        /* LongLBA doesn't change this calculation */
603        offset = bd_len + MODE10_RESP_HDR_LEN;
604    }
605    if ((offset + 2) > calc_len) {
606        if (err_buff_ok)
607            snprintf(err_buff, err_buff_len, "calculated response "
608                     "length too small, offset=%d calc_len=%d bd_len=%d\n",
609                     offset, calc_len, bd_len);
610        offset = -1;
611    }
612    return offset;
613too_short:
614    if (err_buff_ok)
615        snprintf(err_buff, err_buff_len, "given MS(%d) response length (%d) "
616                 "too short\n", (mode_sense_6 ? 6 : 10), resp_len);
617    return -1;
618}
619
620/* MODE SENSE commands yield a response that has header then zero or more
621 * block descriptors followed by mode pages. This functions returns the
622 * length (in bytes) of those three components. Note that the return value
623 * can exceed resp_len in which case the MODE SENSE command should be
624 * re-issued with a larger response buffer. If bd_lenp is non-NULL and if
625 * successful the block descriptor length (in bytes) is written to *bd_lenp.
626 * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10)
627 * responses. Returns -1 if there is an error (e.g. response too short). */
628int
629sg_msense_calc_length(const unsigned char * resp, int resp_len,
630                      bool mode_sense_6, int * bd_lenp)
631{
632    int calc_len;
633
634    if (NULL == resp)
635        goto an_err;
636    if (mode_sense_6) {
637        if (resp_len < 4)
638            goto an_err;
639        calc_len = resp[0] + 1;
640    } else {
641        if (resp_len < 8)
642            goto an_err;
643        calc_len = sg_get_unaligned_be16(resp + 0) + 2;
644    }
645    if (bd_lenp)
646        *bd_lenp = mode_sense_6 ? resp[3] : sg_get_unaligned_be16(resp + 6);
647    return calc_len;
648an_err:
649    if (bd_lenp)
650        *bd_lenp = 0;
651    return -1;
652}
653
654/* Fetches current, changeable, default and/or saveable modes pages as
655 * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
656 * mode6==false then use MODE SENSE (10) else use MODE SENSE (6). If
657 * flexible set and mode data length seems wrong then try and
658 * fix (compensating hack for bad device or driver). pcontrol_arr
659 * should have 4 elements for output of current, changeable, default
660 * and saved values respectively. Each element should be NULL or
661 * at least mx_mpage_len bytes long.
662 * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or
663 * -1 -> other errors.
664 * If success_mask pointer is not NULL then first zeros it. Then set bits
665 * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
666 * respectively have been fetched. If error on current page
667 * then stops and returns that error; otherwise continues if an error is
668 * detected but returns the first error encountered.  */
669int
670sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code,
671                          bool dbd, bool flexible, int mx_mpage_len,
672                          int * success_mask, void * pcontrol_arr[],
673                          int * reported_lenp, int verbose)
674{
675    bool resp_mode6;
676    int k, n, res, offset, calc_len, xfer_len;
677    int resid = 0;
678    const int msense10_hlen = MODE10_RESP_HDR_LEN;
679    unsigned char buff[MODE_RESP_ARB_LEN];
680    char ebuff[EBUFF_SZ];
681    int first_err = 0;
682
683    if (success_mask)
684        *success_mask = 0;
685    if (reported_lenp)
686        *reported_lenp = 0;
687    if (mx_mpage_len < 4)
688        return 0;
689    memset(ebuff, 0, sizeof(ebuff));
690    /* first try to find length of current page response */
691    memset(buff, 0, msense10_hlen);
692    if (mode6)  /* want first 8 bytes just in case */
693        res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code,
694                                sub_pg_code, buff, msense10_hlen, true,
695                                verbose);
696    else        /* MODE SENSE(10) obviously */
697        res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
698                                    0 /* pc */, pg_code, sub_pg_code, buff,
699                                    msense10_hlen, 0, &resid, true, verbose);
700    if (0 != res)
701        return res;
702    n = buff[0];
703    if (reported_lenp) {
704        int m;
705
706        m = sg_msense_calc_length(buff, msense10_hlen, mode6, NULL) - resid;
707        if (m < 0)      /* Grrr, this should not happen */
708            m = 0;
709        *reported_lenp = m;
710    }
711    resp_mode6 = mode6;
712    if (flexible) {
713        if (mode6 && (n < 3)) {
714            resp_mode6 = false;
715            if (verbose)
716                pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) "
717                      "response processing\n", n);
718        }
719        if ((! mode6) && (n > 5)) {
720            if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) &&
721                (0 == buff[5]) && (0 == buff[6])) {
722                buff[1] = n;
723                buff[0] = 0;
724                if (verbose)
725                    pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) "
726                          "response so fix length\n", n);
727            } else
728                resp_mode6 = true;
729        }
730    }
731    if (verbose && (resp_mode6 != mode6))
732        pr2ws(">>> msense(%d) but resp[0]=%d so switch response "
733              "processing\n", (mode6 ? 6 : 10), buff[0]);
734    calc_len = sg_msense_calc_length(buff, msense10_hlen, resp_mode6, NULL);
735    if (calc_len > MODE_RESP_ARB_LEN)
736        calc_len = MODE_RESP_ARB_LEN;
737    offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ);
738    if (offset < 0) {
739        if (('\0' != ebuff[0]) && (verbose > 0))
740            pr2ws("%s: %s\n", __func__, ebuff);
741        return SG_LIB_CAT_MALFORMED;
742    }
743    xfer_len = calc_len - offset;
744    if (xfer_len > mx_mpage_len)
745        xfer_len = mx_mpage_len;
746
747    for (k = 0; k < 4; ++k) {
748        if (NULL == pcontrol_arr[k])
749            continue;
750        memset(pcontrol_arr[k], 0, mx_mpage_len);
751        resid = 0;
752        if (mode6)
753            res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */,
754                                    pg_code, sub_pg_code, buff,
755                                    calc_len, true, verbose);
756        else
757            res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
758                                        k /* pc */, pg_code, sub_pg_code,
759                                        buff, calc_len, 0, &resid, true,
760                                        verbose);
761        if (res || resid) {
762            if (0 == first_err) {
763                if (res)
764                    first_err = res;
765                else {
766                    first_err = -49;    /* unexpected resid != 0 */
767                    if (verbose)
768                        pr2ws("%s: unexpected resid=%d, page=0x%x, "
769                              "pcontrol=%d\n", __func__, resid, pg_code, k);
770                }
771            }
772            if (0 == k)
773                break;  /* if problem on current page, it won't improve */
774            else
775                continue;
776        }
777        if (xfer_len > 0)
778            memcpy(pcontrol_arr[k], buff + offset, xfer_len);
779        if (success_mask)
780            *success_mask |= (1 << k);
781    }
782    return first_err;
783}
784
785/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
786 * various SG_LIB_CAT_* positive values or -1 -> other errors. */
787int
788sg_ll_log_sense(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
789                int subpg_code, int paramp, unsigned char * resp,
790                int mx_resp_len, bool noisy, int verbose)
791{
792    return sg_ll_log_sense_v2(sg_fd, ppc, sp, pc, pg_code, subpg_code,
793                              paramp, resp, mx_resp_len, 0, NULL, noisy,
794                              verbose);
795}
796
797/* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
798 * various SG_LIB_CAT_* positive values or -1 -> other errors.
799 * Adds the ability to set the command abort timeout
800 * and the ability to report the residual count. If timeout_secs is zero
801 * or less the default command abort timeout (60 seconds) is used.
802 * If residp is non-NULL then the residual value is written where residp
803 * points. A residual value of 0 implies mx_resp_len bytes have be written
804 * where resp points. If the residual value equals mx_resp_len then no
805 * bytes have been written. */
806int
807sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
808                   int subpg_code, int paramp, unsigned char * resp,
809                   int mx_resp_len, int timeout_secs, int * residp,
810                   bool noisy, int verbose)
811{
812    static const char * const cdb_name_s = "log sense";
813    int res, ret, k, sense_cat, resid;
814    unsigned char logs_cdb[LOG_SENSE_CMDLEN] =
815        {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
816    unsigned char sense_b[SENSE_BUFF_LEN];
817    struct sg_pt_base * ptvp;
818
819    if (mx_resp_len > 0xffff) {
820        pr2ws("mx_resp_len too big\n");
821        goto gen_err;
822    }
823    logs_cdb[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
824    logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
825    logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
826    sg_put_unaligned_be16((int16_t)paramp, logs_cdb + 5);
827    sg_put_unaligned_be16((int16_t)mx_resp_len, logs_cdb + 7);
828    if (verbose) {
829        pr2ws("    %s cdb: ", cdb_name_s);
830        for (k = 0; k < LOG_SENSE_CMDLEN; ++k)
831            pr2ws("%02x ", logs_cdb[k]);
832        pr2ws("\n");
833    }
834    if (timeout_secs <= 0)
835        timeout_secs = DEF_PT_TIMEOUT;
836
837    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
838        goto gen_err;
839    set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
840    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
841    set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
842    res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
843    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len,
844                               sense_b, noisy, verbose, &sense_cat);
845    resid = get_scsi_pt_resid(ptvp);
846    if (residp)
847        *residp = resid;
848    if (-1 == ret) {
849        int os_err = get_scsi_pt_os_err(ptvp);
850
851        if ((os_err > 0) && (os_err < 47))
852            ret = SG_LIB_OS_BASE_ERR + os_err;
853    } else if (-2 == ret) {
854        switch (sense_cat) {
855        case SG_LIB_CAT_RECOVERED:
856        case SG_LIB_CAT_NO_SENSE:
857            ret = 0;
858            break;
859        default:
860            ret = sense_cat;
861            break;
862        }
863    } else {
864        if ((mx_resp_len > 3) && (ret < 4)) {
865            /* resid indicates LOG SENSE response length bad, so zero it */
866            resp[2] = 0;
867            resp[3] = 0;
868        }
869        ret = 0;
870    }
871    destruct_scsi_pt_obj(ptvp);
872
873    if (resid > 0) {
874        if (resid > mx_resp_len) {
875            pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
876                  cdb_name_s, resid, mx_resp_len);
877            return ret ? ret : SG_LIB_CAT_MALFORMED;
878        }
879        /* zero unfilled section of response buffer */
880        memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid);
881    }
882    return ret;
883gen_err:
884    if (residp)
885        *residp = 0;
886    return -1;
887}
888
889/* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
890 * various SG_LIB_CAT_* positive values or -1 -> other errors */
891int
892sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
893                 int subpg_code, unsigned char * paramp, int param_len,
894                 bool noisy, int verbose)
895{
896    static const char * const cdb_name_s = "log select";
897    int res, ret, k, sense_cat;
898    unsigned char logs_cdb[LOG_SELECT_CMDLEN] =
899        {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
900    unsigned char sense_b[SENSE_BUFF_LEN];
901    struct sg_pt_base * ptvp;
902
903    if (param_len > 0xffff) {
904        pr2ws("%s: param_len too big\n", cdb_name_s);
905        return -1;
906    }
907    logs_cdb[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0));
908    logs_cdb[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
909    logs_cdb[3] = (unsigned char)(subpg_code & 0xff);
910    sg_put_unaligned_be16((int16_t)param_len, logs_cdb + 7);
911    if (verbose) {
912        pr2ws("    %s cdb: ", cdb_name_s);
913        for (k = 0; k < LOG_SELECT_CMDLEN; ++k)
914            pr2ws("%02x ", logs_cdb[k]);
915        pr2ws("\n");
916    }
917    if ((verbose > 1) && (param_len > 0)) {
918        pr2ws("    %s parameter list\n", cdb_name_s);
919        hex2stderr(paramp, param_len, -1);
920    }
921
922    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
923        return -1;
924    set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
925    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
926    set_scsi_pt_data_out(ptvp, paramp, param_len);
927    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
928    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
929                               noisy, verbose, &sense_cat);
930    if (-1 == ret) {
931        int os_err = get_scsi_pt_os_err(ptvp);
932
933        if ((os_err > 0) && (os_err < 47))
934            ret = SG_LIB_OS_BASE_ERR + os_err;
935    } else if (-2 == ret) {
936        switch (sense_cat) {
937        case SG_LIB_CAT_RECOVERED:
938        case SG_LIB_CAT_NO_SENSE:
939            ret = 0;
940            break;
941        default:
942            ret = sense_cat;
943            break;
944        }
945    } else
946        ret = 0;
947
948    destruct_scsi_pt_obj(ptvp);
949    return ret;
950}
951
952/* Invokes a SCSI START STOP UNIT command (SBC + MMC).
953 * Return of 0 -> success,
954 * various SG_LIB_CAT_* positive values or -1 -> other errors.
955 * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
956 * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
957 * and fl(mmc) one bit field. This is the cause of the awkardly named
958 * pc_mod__fl_num and noflush__fl arguments to this function.
959 *  */
960int
961sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num,
962                      int power_cond, bool noflush__fl, bool loej, bool start,
963                      bool noisy, int verbose)
964{
965    static const char * const cdb_name_s = "start stop unit";
966    int k, res, ret, sense_cat;
967    struct sg_pt_base * ptvp;
968    unsigned char ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
969    unsigned char sense_b[SENSE_BUFF_LEN];
970
971    if (immed)
972        ssuBlk[1] = 0x1;
973    ssuBlk[3] = pc_mod__fl_num & 0xf;  /* bits 2 and 3 are reserved in MMC */
974    ssuBlk[4] = ((power_cond & 0xf) << 4);
975    if (noflush__fl)
976        ssuBlk[4] |= 0x4;
977    if (loej)
978        ssuBlk[4] |= 0x2;
979    if (start)
980        ssuBlk[4] |= 0x1;
981    if (verbose) {
982        pr2ws("    %s command:", cdb_name_s);
983        for (k = 0; k < (int)sizeof(ssuBlk); ++k)
984                pr2ws(" %02x", ssuBlk[k]);
985        pr2ws("\n");
986    }
987
988    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
989        return -1;
990    set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
991    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
992    res = do_scsi_pt(ptvp, sg_fd, START_PT_TIMEOUT, verbose);
993    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
994                               noisy, verbose, &sense_cat);
995    if (-1 == ret) {
996        int os_err = get_scsi_pt_os_err(ptvp);
997
998        if ((os_err > 0) && (os_err < 47))
999            ret = SG_LIB_OS_BASE_ERR + os_err;
1000    } else if (-2 == ret) {
1001        switch (sense_cat) {
1002        case SG_LIB_CAT_RECOVERED:
1003        case SG_LIB_CAT_NO_SENSE:
1004            ret = 0;
1005            break;
1006        default:
1007            ret = sense_cat;
1008            break;
1009        }
1010    } else
1011            ret = 0;
1012    destruct_scsi_pt_obj(ptvp);
1013    return ret;
1014}
1015
1016/* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command
1017 * [was in SPC-3 but displaced from SPC-4 into SBC-3, MMC-5, SSC-3]
1018 * prevent==0 allows removal, prevent==1 prevents removal ...
1019 * Return of 0 -> success,
1020 * various SG_LIB_CAT_* positive values or -1 -> other errors */
1021int
1022sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose)
1023{
1024    static const char * const cdb_name_s = "prevent allow medium removal";
1025    int k, res, ret, sense_cat;
1026    unsigned char p_cdb[PREVENT_ALLOW_CMDLEN] =
1027                {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0};
1028    unsigned char sense_b[SENSE_BUFF_LEN];
1029    struct sg_pt_base * ptvp;
1030
1031    if ((prevent < 0) || (prevent > 3)) {
1032        pr2ws("prevent argument should be 0, 1, 2 or 3\n");
1033        return -1;
1034    }
1035    p_cdb[4] |= (prevent & 0x3);
1036    if (verbose) {
1037        pr2ws("    %s cdb: ", cdb_name_s);
1038        for (k = 0; k < PREVENT_ALLOW_CMDLEN; ++k)
1039            pr2ws("%02x ", p_cdb[k]);
1040        pr2ws("\n");
1041    }
1042
1043    if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1044        return -1;
1045    set_scsi_pt_cdb(ptvp, p_cdb, sizeof(p_cdb));
1046    set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1047    res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1048    ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1049                               noisy, verbose, &sense_cat);
1050    if (-1 == ret) {
1051        int os_err = get_scsi_pt_os_err(ptvp);
1052
1053        if ((os_err > 0) && (os_err < 47))
1054            ret = SG_LIB_OS_BASE_ERR + os_err;
1055    } else if (-2 == ret) {
1056        switch (sense_cat) {
1057        case SG_LIB_CAT_RECOVERED:
1058        case SG_LIB_CAT_NO_SENSE:
1059            ret = 0;
1060            break;
1061        default:
1062            ret = sense_cat;
1063            break;
1064        }
1065    } else
1066            ret = 0;
1067    destruct_scsi_pt_obj(ptvp);
1068    return ret;
1069}
1070