• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1999-2022 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  * SPDX-License-Identifier: BSD-2-Clause
8  */
9 
10 /*
11  * CONTENTS
12  *    Some SCSI commands are executed in many contexts and hence began
13  *    to appear in several sg3_utils utilities. This files centralizes
14  *    some of the low level command execution code. In most cases the
15  *    interpretation of the command response is left to the each
16  *    utility.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <stdbool.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #define __STDC_FORMAT_MACROS 1
27 #include <inttypes.h>
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "sg_lib.h"
34 #include "sg_cmds_basic.h"
35 #include "sg_pt.h"
36 #include "sg_unaligned.h"
37 #include "sg_pr2serr.h"
38 
39 /* Needs to be after config.h */
40 #ifdef SG_LIB_LINUX
41 #include <errno.h>
42 #endif
43 
44 
45 static const char * const version_str = "2.00 20220118";
46 
47 
48 #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
49 #define EBUFF_SZ 256
50 
51 #define DEF_PT_TIMEOUT 60       /* 60 seconds */
52 #define START_PT_TIMEOUT 120    /* 120 seconds == 2 minutes */
53 #define LONG_PT_TIMEOUT 7200    /* 7,200 seconds == 120 minutes */
54 
55 #define INQUIRY_CMD     0x12
56 #define INQUIRY_CMDLEN  6
57 #define REQUEST_SENSE_CMD 0x3
58 #define REQUEST_SENSE_CMDLEN 6
59 #define REPORT_LUNS_CMD 0xa0
60 #define REPORT_LUNS_CMDLEN 12
61 #define TUR_CMD  0x0
62 #define TUR_CMDLEN  6
63 
64 #define SAFE_STD_INQ_RESP_LEN 36 /* other lengths lock up some devices */
65 
66 
67 const char *
sg_cmds_version()68 sg_cmds_version()
69 {
70     return version_str;
71 }
72 
73 /* Returns file descriptor >= 0 if successful. If error in Unix returns
74    negated errno. */
75 int
sg_cmds_open_device(const char * device_name,bool read_only,int verbose)76 sg_cmds_open_device(const char * device_name, bool read_only, int verbose)
77 {
78     return scsi_pt_open_device(device_name, read_only, verbose);
79 }
80 
81 /* Returns file descriptor >= 0 if successful. If error in Unix returns
82    negated errno. */
83 int
sg_cmds_open_flags(const char * device_name,int flags,int verbose)84 sg_cmds_open_flags(const char * device_name, int flags, int verbose)
85 {
86     return scsi_pt_open_flags(device_name, flags, verbose);
87 }
88 
89 /* Returns 0 if successful. If error in Unix returns negated errno. */
90 int
sg_cmds_close_device(int device_fd)91 sg_cmds_close_device(int device_fd)
92 {
93     return scsi_pt_close_device(device_fd);
94 }
95 
96 static const char * const pass_through_s = "pass-through";
97 
98 static void
sg_cmds_resid_print(const char * leadin,bool is_din,int num_req,int num_got)99 sg_cmds_resid_print(const char * leadin, bool is_din, int num_req,
100                     int num_got)
101 {
102     pr2ws("    %s: %s requested %d bytes (data-%s  got %d "
103           "bytes%s\n", leadin, pass_through_s,num_req,
104           (is_din ? "in), got" : "out) but reported"), num_got,
105           (is_din ? "" : " sent"));
106 }
107 
108 static int
sg_cmds_process_helper(const char * leadin,int req_din_x,int act_din_x,int req_dout_x,int act_dout_x,const uint8_t * sbp,int slen,bool noisy,int verbose,int * o_sense_cat)109 sg_cmds_process_helper(const char * leadin, int req_din_x, int act_din_x,
110                        int req_dout_x, int act_dout_x, const uint8_t * sbp,
111                        int slen, bool noisy, int verbose, int * o_sense_cat)
112 {
113     int scat;
114     bool n = false;
115     bool check_data_in = false;
116 
117     scat = sg_err_category_sense(sbp, slen);
118     switch (scat) {
119     case SG_LIB_CAT_NOT_READY:
120     case SG_LIB_CAT_INVALID_OP:
121     case SG_LIB_CAT_ILLEGAL_REQ:
122     case SG_LIB_LBA_OUT_OF_RANGE:
123     case SG_LIB_CAT_ABORTED_COMMAND:
124     case SG_LIB_CAT_COPY_ABORTED:
125     case SG_LIB_CAT_DATA_PROTECT:
126     case SG_LIB_CAT_PROTECTION:
127     case SG_LIB_CAT_NO_SENSE:
128     case SG_LIB_CAT_MISCOMPARE:
129     case SG_LIB_CAT_STANDBY:
130     case SG_LIB_CAT_UNAVAILABLE:
131         n = false;
132         break;
133     case SG_LIB_CAT_RECOVERED:
134     case SG_LIB_CAT_MEDIUM_HARD:
135         check_data_in = true;
136 #if defined(__GNUC__)
137 #if (__GNUC__ >= 7)
138         __attribute__((fallthrough));
139         /* FALL THROUGH */
140 #endif
141 #endif
142     case SG_LIB_CAT_UNIT_ATTENTION:
143     case SG_LIB_CAT_SENSE:
144     default:
145         n = noisy;
146         break;
147     }
148     if (verbose || n) {
149         char b[512];
150 
151         if (leadin && (strlen(leadin) > 0))
152             pr2ws("%s:\n", leadin);
153         sg_get_sense_str(NULL, sbp, slen, (verbose > 1),
154                          sizeof(b), b);
155         pr2ws("%s", b);
156         if (req_din_x > 0) {
157             if (act_din_x != req_din_x) {
158                 if ((verbose > 2) || check_data_in || (act_din_x > 0))
159                     sg_cmds_resid_print(leadin, true, req_din_x, act_din_x);
160                 if (act_din_x < 0) {
161                     if (verbose)
162                         pr2ws("    %s: %s can't get negative bytes, say it "
163                               "got none\n", leadin, pass_through_s);
164                 }
165             }
166         }
167         if (req_dout_x > 0) {
168             if (act_dout_x != req_dout_x) {
169                 if ((verbose > 1) && (act_dout_x > 0))
170                     sg_cmds_resid_print(leadin, false, req_dout_x, act_dout_x);
171                 if (act_dout_x < 0) {
172                     if (verbose)
173                         pr2ws("    %s: %s can't send negative bytes, say it "
174                               "sent none\n", leadin, pass_through_s);
175                 }
176             }
177         }
178     }
179     if (o_sense_cat)
180         *o_sense_cat = scat;
181     return -2;
182 }
183 
184 /* This is a helper function used by sg_cmds_* implementations after the
185  * call to the pass-through. pt_res is returned from do_scsi_pt(). If valid
186  * sense data is found it is decoded and output to sg_warnings_strm (def:
187  * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for
188  * o_sense_cat (sense category) written which may not be fatal. Returns
189  * -1 for other types of failure. Returns 0, or a positive number. If data-in
190  * type command (or bidi) then returns actual number of bytes read
191  * (din_len - resid); otherwise returns 0. Note that several sense categories
192  * also have data in bytes received; -2 is still returned. */
193 int
sg_cmds_process_resp(struct sg_pt_base * ptvp,const char * leadin,int pt_res,bool noisy,int verbose,int * o_sense_cat)194 sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin,
195                      int pt_res, bool noisy, int verbose, int * o_sense_cat)
196 {
197     int cat, slen, sstat, req_din_x, req_dout_x;
198     int act_din_x, act_dout_x;
199     const uint8_t * sbp;
200     char b[1024];
201 
202     if (NULL == leadin)
203         leadin = "";
204     if (pt_res < 0) {
205 #ifdef SG_LIB_LINUX
206         if (verbose)
207             pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
208                   safe_strerror(-pt_res));
209         if ((-ENXIO == pt_res) && o_sense_cat) {
210             if (verbose > 2)
211                 pr2ws("map ENXIO to SG_LIB_CAT_NOT_READY\n");
212             *o_sense_cat = SG_LIB_CAT_NOT_READY;
213             return -2;
214         } else if (noisy && (0 == verbose))
215             pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
216                   safe_strerror(-pt_res));
217 #else
218         if (noisy || verbose)
219             pr2ws("%s: %s os error: %s\n", leadin, pass_through_s,
220                   safe_strerror(-pt_res));
221 #endif
222         return -1;
223     } else if (SCSI_PT_DO_BAD_PARAMS == pt_res) {
224         pr2ws("%s: bad %s setup\n", leadin, pass_through_s);
225         return -1;
226     } else if (SCSI_PT_DO_TIMEOUT == pt_res) {
227         pr2ws("%s: %s timeout\n", leadin, pass_through_s);
228         return -1;
229     }
230     if (verbose > 2) {
231         uint64_t duration = get_pt_duration_ns(ptvp);
232 
233         if (duration > 0)
234             pr2ws("      duration=%" PRIu64 " ns\n", duration);
235         else {
236             int d = get_scsi_pt_duration_ms(ptvp);
237 
238             if (d != -1)
239                 pr2ws("      duration=%u ms\n", (uint32_t)d);
240         }
241     }
242     get_pt_req_lengths(ptvp, &req_din_x, &req_dout_x);
243     get_pt_actual_lengths(ptvp, &act_din_x, &act_dout_x);
244     slen = get_scsi_pt_sense_len(ptvp);
245     sbp = get_scsi_pt_sense_buf(ptvp);
246     switch ((cat = get_scsi_pt_result_category(ptvp))) {
247     case SCSI_PT_RESULT_GOOD:
248         if (sbp && (slen > 7)) {
249             int resp_code = sbp[0] & 0x7f;
250 
251             /* SBC referrals can have status=GOOD and sense_key=COMPLETED */
252             if (resp_code >= 0x70) {
253                 if (resp_code < 0x72) {
254                     if (SPC_SK_NO_SENSE != (0xf & sbp[2]))
255                         sg_err_category_sense(sbp, slen);
256                 } else if (resp_code < 0x74) {
257                     if (SPC_SK_NO_SENSE != (0xf & sbp[1]))
258                         sg_err_category_sense(sbp, slen);
259                 }
260             }
261         }
262         if (req_din_x > 0) {
263             if (act_din_x != req_din_x) {
264                 if ((verbose > 1) && (act_din_x >= 0))
265                     sg_cmds_resid_print(leadin, true, req_din_x, act_din_x);
266                 if (act_din_x < 0) {
267                     if (verbose)
268                         pr2ws("    %s: %s can't get negative bytes, say it "
269                               "got none\n", leadin, pass_through_s);
270                     act_din_x = 0;
271                 }
272             }
273         }
274         if (req_dout_x > 0) {
275             if (act_dout_x != req_dout_x) {
276                 if ((verbose > 1) && (act_dout_x >= 0))
277                     sg_cmds_resid_print(leadin, false, req_dout_x, act_dout_x);
278                 if (act_dout_x < 0) {
279                     if (verbose)
280                         pr2ws("    %s: %s can't send negative bytes, say it "
281                               "sent none\n", leadin, pass_through_s);
282                     act_dout_x = 0;
283                 }
284             }
285         }
286         return act_din_x;
287     case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */
288         sstat = get_scsi_pt_status_response(ptvp);
289         if (o_sense_cat) {
290             switch (sstat) {
291             case SAM_STAT_RESERVATION_CONFLICT:
292                 *o_sense_cat = SG_LIB_CAT_RES_CONFLICT;
293                 return -2;
294             case SAM_STAT_CONDITION_MET:
295                 *o_sense_cat = SG_LIB_CAT_CONDITION_MET;
296                 return -2;
297             case SAM_STAT_BUSY:
298                 *o_sense_cat = SG_LIB_CAT_BUSY;
299                 return -2;
300             case SAM_STAT_TASK_SET_FULL:
301                 *o_sense_cat = SG_LIB_CAT_TS_FULL;
302                 return -2;
303             case SAM_STAT_ACA_ACTIVE:
304                 *o_sense_cat = SG_LIB_CAT_ACA_ACTIVE;
305                 return -2;
306             case SAM_STAT_TASK_ABORTED:
307                 *o_sense_cat = SG_LIB_CAT_TASK_ABORTED;
308                 return -2;
309             default:
310                 break;
311             }
312         }
313         if (verbose || noisy) {
314             sg_get_scsi_status_str(sstat, sizeof(b), b);
315             pr2ws("%s: scsi status: %s\n", leadin, b);
316         }
317         return -1;
318     case SCSI_PT_RESULT_SENSE:
319         return sg_cmds_process_helper(leadin, req_din_x, act_din_x,
320                                       req_dout_x, act_dout_x, sbp, slen,
321                                       noisy, verbose, o_sense_cat);
322     case SCSI_PT_RESULT_TRANSPORT_ERR:
323         if (verbose || noisy) {
324             get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
325             pr2ws("%s: transport: %s\n", leadin, b);
326         }
327 #ifdef SG_LIB_LINUX
328         return -1;      /* DRIVER_SENSE is not passed through */
329 #else
330         /* Shall we favour sense data over a transport error (given both) */
331         {
332             bool favour_sense = ((SAM_STAT_CHECK_CONDITION ==
333                     get_scsi_pt_status_response(ptvp)) && (slen > 0));
334 
335             if (favour_sense)
336                 return sg_cmds_process_helper(leadin, req_din_x, act_din_x,
337                                               req_dout_x, act_dout_x, sbp,
338                                               slen, noisy, verbose,
339                                               o_sense_cat);
340             else
341                 return -1;
342         }
343 #endif
344     case SCSI_PT_RESULT_OS_ERR:
345         if (verbose || noisy) {
346             get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
347             pr2ws("%s: os: %s\n", leadin, b);
348         }
349         return -1;
350     default:
351         pr2ws("%s: unknown %s result category (%d)\n", leadin, pass_through_s,
352                cat);
353         return -1;
354     }
355 }
356 
357 bool
sg_cmds_is_nvme(const struct sg_pt_base * ptvp)358 sg_cmds_is_nvme(const struct sg_pt_base * ptvp)
359 {
360     return pt_device_is_nvme(ptvp);
361 }
362 
363 static struct sg_pt_base *
create_pt_obj(const char * cname)364 create_pt_obj(const char * cname)
365 {
366     struct sg_pt_base * ptvp = construct_scsi_pt_obj();
367     if (NULL == ptvp)
368         pr2ws("%s: out of memory\n", cname);
369     return ptvp;
370 }
371 
372 static const char * const inquiry_s = "inquiry";
373 
374 
375 /* Returns 0 on success, while positive values are SG_LIB_CAT_* errors
376  * (e.g. SG_LIB_CAT_MALFORMED). If OS error, returns negated errno or -1. */
377 static int
sg_ll_inquiry_com(struct sg_pt_base * ptvp,int sg_fd,bool cmddt,bool evpd,int pg_op,void * resp,int mx_resp_len,int timeout_secs,int * residp,bool noisy,int verbose)378 sg_ll_inquiry_com(struct sg_pt_base * ptvp, int sg_fd, bool cmddt, bool evpd,
379                   int pg_op, void * resp, int mx_resp_len, int timeout_secs,
380                   int * residp, bool noisy, int verbose)
381 {
382     bool ptvp_given = false;
383     bool local_sense = true;
384     bool local_cdb = true;
385     int res, ret, sense_cat, resid;
386     uint8_t inq_cdb[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
387     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
388     uint8_t * up;
389 
390     if (resp == NULL) {
391         if (verbose)
392             pr2ws("Got NULL `resp` pointer");
393         return SG_LIB_CAT_MALFORMED;
394     }
395     if (cmddt)
396         inq_cdb[1] |= 0x2;
397     if (evpd)
398         inq_cdb[1] |= 0x1;
399     inq_cdb[2] = (uint8_t)pg_op;
400     /* 16 bit allocation length (was 8, increased in spc3r09, 200209) */
401     sg_put_unaligned_be16((uint16_t)mx_resp_len, inq_cdb + 3);
402     if (verbose) {
403         char b[128];
404 
405         pr2ws("    %s cdb: %s\n", inquiry_s,
406               sg_get_command_str(inq_cdb, INQUIRY_CMDLEN, false, sizeof(b),
407                                  b));
408     }
409     if (mx_resp_len > 0) {
410         up = (uint8_t *)resp;
411         up[0] = 0x7f;   /* defensive prefill */
412         if (mx_resp_len > 4)
413             up[4] = 0;
414     }
415     if (timeout_secs <= 0)
416         timeout_secs = DEF_PT_TIMEOUT;
417     if (ptvp) {
418         ptvp_given = true;
419         partial_clear_scsi_pt_obj(ptvp);
420         if (get_scsi_pt_cdb_buf(ptvp))
421             local_cdb = false; /* N.B. Ignores locally built cdb */
422         else
423             set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb));
424         if (get_scsi_pt_sense_buf(ptvp))
425             local_sense = false;
426         else
427             set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
428     } else {
429         ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
430         if (NULL == ptvp)
431             return sg_convert_errno(ENOMEM);
432         set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb));
433         set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
434     }
435     set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
436     res = do_scsi_pt(ptvp, -1, timeout_secs, verbose);
437     ret = sg_cmds_process_resp(ptvp, inquiry_s, res, noisy, verbose,
438                                &sense_cat);
439     resid = get_scsi_pt_resid(ptvp);
440     if (residp)
441         *residp = resid;
442     if (-1 == ret) {
443         if (get_scsi_pt_transport_err(ptvp))
444             ret = SG_LIB_TRANSPORT_ERROR;
445         else
446             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
447     } else if (-2 == ret) {
448         switch (sense_cat) {
449         case SG_LIB_CAT_RECOVERED:
450         case SG_LIB_CAT_NO_SENSE:
451             ret = 0;
452             break;
453         default:
454             ret = sense_cat;
455             break;
456         }
457     } else if (ret < 4) {
458         if (verbose)
459             pr2ws("%s: got too few bytes (%d)\n", __func__, ret);
460         ret = SG_LIB_CAT_MALFORMED;
461     } else
462         ret = 0;
463 
464     if (resid > 0) {
465         if (resid > mx_resp_len) {
466             pr2ws("%s resid (%d) should never exceed requested "
467                     "len=%d\n", inquiry_s, resid, mx_resp_len);
468             if (0 == ret)
469                 ret = SG_LIB_CAT_MALFORMED;
470             goto fini;
471         }
472         /* zero unfilled section of response buffer, based on resid */
473         memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid);
474     }
475 fini:
476     if (ptvp_given) {
477         if (local_sense)    /* stop caller trying to access local sense */
478             set_scsi_pt_sense(ptvp, NULL, 0);
479         if (local_cdb)
480             set_scsi_pt_cdb(ptvp, NULL, 0);
481     } else {
482         if (ptvp)
483             destruct_scsi_pt_obj(ptvp);
484     }
485     return ret;
486 }
487 
488 /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
489  * successful, various SG_LIB_CAT_* positive values, negated errno or
490  * -1 -> other errors. The CMDDT field is obsolete in the INQUIRY cdb. */
491 int
sg_ll_inquiry(int sg_fd,bool cmddt,bool evpd,int pg_op,void * resp,int mx_resp_len,bool noisy,int verbose)492 sg_ll_inquiry(int sg_fd, bool cmddt, bool evpd, int pg_op, void * resp,
493               int mx_resp_len, bool noisy, int verbose)
494 {
495     return sg_ll_inquiry_com(NULL, sg_fd, cmddt, evpd, pg_op, resp,
496                              mx_resp_len, 0 /* timeout_sec */, NULL, noisy,
497                              verbose);
498 }
499 
500 /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when
501  * successful, various SG_LIB_CAT_* positive values or -1 -> other errors.
502  * The CMDDT field is obsolete in the INQUIRY cdb (since spc3r16 in 2003) so
503  * an argument to set it has been removed (use the REPORT SUPPORTED OPERATION
504  * CODES command instead). Adds the ability to set the command abort timeout
505  * and the ability to report the residual count. If timeout_secs is zero
506  * or less the default command abort timeout (60 seconds) is used.
507  * If residp is non-NULL then the residual value is written where residp
508  * points. A residual value of 0 implies mx_resp_len bytes have be written
509  * where resp points. If the residual value equals mx_resp_len then no
510  * bytes have been written. */
511 int
sg_ll_inquiry_v2(int sg_fd,bool evpd,int pg_op,void * resp,int mx_resp_len,int timeout_secs,int * residp,bool noisy,int verbose)512 sg_ll_inquiry_v2(int sg_fd, bool evpd, int pg_op, void * resp,
513                  int mx_resp_len, int timeout_secs, int * residp,
514                  bool noisy, int verbose)
515 {
516     return sg_ll_inquiry_com(NULL, sg_fd, false, evpd, pg_op, resp,
517                              mx_resp_len, timeout_secs, residp, noisy,
518                              verbose);
519 }
520 
521 /* Similar to _v2 but takes a pointer to an object (derived from) sg_pt_base.
522  * That object is assumed to be constructed and have a device file descriptor
523  * associated with it. Caller is responsible for lifetime of ptp. */
524 int
sg_ll_inquiry_pt(struct sg_pt_base * ptvp,bool evpd,int pg_op,void * resp,int mx_resp_len,int timeout_secs,int * residp,bool noisy,int verbose)525 sg_ll_inquiry_pt(struct sg_pt_base * ptvp, bool evpd, int pg_op, void * resp,
526                  int mx_resp_len, int timeout_secs, int * residp, bool noisy,
527                  int verbose)
528 {
529     return sg_ll_inquiry_com(ptvp, -1, false, evpd, pg_op, resp, mx_resp_len,
530                              timeout_secs, residp, noisy, verbose);
531 }
532 
533 /* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response.
534  * Returns 0 when successful, various SG_LIB_CAT_* positive values, negated
535  * errno or -1 -> other errors */
536 int
sg_simple_inquiry(int sg_fd,struct sg_simple_inquiry_resp * inq_data,bool noisy,int verbose)537 sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data,
538                   bool noisy, int verbose)
539 {
540     int ret;
541     uint8_t * inq_resp = NULL;
542     uint8_t * free_irp = NULL;
543 
544     if (inq_data) {
545         memset(inq_data, 0, sizeof(* inq_data));
546         inq_data->peripheral_qualifier = 0x3;
547         inq_data->peripheral_type = PDT_UNKNOWN;
548     }
549     inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false);
550     if (NULL == inq_resp) {
551         pr2ws("%s: out of memory\n", __func__);
552         return sg_convert_errno(ENOMEM);
553     }
554     ret = sg_ll_inquiry_com(NULL, sg_fd, false, false, 0, inq_resp,
555                             SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose);
556 
557     if (inq_data && (0 == ret)) {
558         inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
559         inq_data->peripheral_type = inq_resp[0] & PDT_MASK;
560         inq_data->byte_1 = inq_resp[1];
561         inq_data->version = inq_resp[2];
562         inq_data->byte_3 = inq_resp[3];
563         inq_data->byte_5 = inq_resp[5];
564         inq_data->byte_6 = inq_resp[6];
565         inq_data->byte_7 = inq_resp[7];
566         memcpy(inq_data->vendor, inq_resp + 8, 8);
567         memcpy(inq_data->product, inq_resp + 16, 16);
568         memcpy(inq_data->revision, inq_resp + 32, 4);
569     }
570     if (free_irp)
571         free(free_irp);
572     return ret;
573 }
574 
575 /* Similar to sg_simple_inquiry() but takes pointer to pt object rather
576  * than device file descriptor. */
577 int
sg_simple_inquiry_pt(struct sg_pt_base * ptvp,struct sg_simple_inquiry_resp * inq_data,bool noisy,int verbose)578 sg_simple_inquiry_pt(struct sg_pt_base * ptvp,
579                      struct sg_simple_inquiry_resp * inq_data,
580                      bool noisy, int verbose)
581 {
582     int ret;
583     uint8_t * inq_resp = NULL;
584     uint8_t * free_irp = NULL;
585 
586     if (inq_data) {
587         memset(inq_data, 0, sizeof(* inq_data));
588         inq_data->peripheral_qualifier = 0x3;
589         inq_data->peripheral_type = PDT_MASK;
590     }
591     inq_resp = sg_memalign(SAFE_STD_INQ_RESP_LEN, 0, &free_irp, false);
592     if (NULL == inq_resp) {
593         pr2ws("%s: out of memory\n", __func__);
594         return sg_convert_errno(ENOMEM);
595     }
596     ret = sg_ll_inquiry_com(ptvp, -1, false, false, 0, inq_resp,
597                             SAFE_STD_INQ_RESP_LEN, 0, NULL, noisy, verbose);
598 
599     if (inq_data && (0 == ret)) {
600         inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
601         inq_data->peripheral_type = inq_resp[0] & PDT_MASK;
602         inq_data->byte_1 = inq_resp[1];
603         inq_data->version = inq_resp[2];
604         inq_data->byte_3 = inq_resp[3];
605         inq_data->byte_5 = inq_resp[5];
606         inq_data->byte_6 = inq_resp[6];
607         inq_data->byte_7 = inq_resp[7];
608         memcpy(inq_data->vendor, inq_resp + 8, 8);
609         memcpy(inq_data->product, inq_resp + 16, 16);
610         memcpy(inq_data->revision, inq_resp + 32, 4);
611     }
612     if (free_irp)
613         free(free_irp);
614     return ret;
615 }
616 
617 /* Invokes a SCSI TEST UNIT READY command.
618  * N.B. To access the sense buffer outside this routine then one be
619  * provided by the caller.
620  * 'pack_id' is just for diagnostics, safe to set to 0.
621  * Looks for progress indicator if 'progress' non-NULL;
622  * if found writes value [0..65535] else write -1.
623  * Returns 0 when successful, various SG_LIB_CAT_* positive values or
624  * -1 -> other errors */
625 static int
sg_ll_test_unit_ready_com(struct sg_pt_base * ptvp,int sg_fd,int pack_id,int * progress,bool noisy,int verbose)626 sg_ll_test_unit_ready_com(struct sg_pt_base * ptvp, int sg_fd, int pack_id,
627                           int * progress, bool noisy, int verbose)
628 {
629     static const char * const tur_s = "test unit ready";
630     bool ptvp_given = false;
631     bool local_sense = true;
632     bool local_cdb = true;
633     int res, ret, sense_cat;
634     uint8_t tur_cdb[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0};
635     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
636 
637     if (verbose) {
638         char b[128];
639 
640         pr2ws("    %s cdb: %s\n", tur_s,
641               sg_get_command_str(tur_cdb, TUR_CMDLEN, false, sizeof(b), b));
642     }
643     if (ptvp) {
644         ptvp_given = true;
645         partial_clear_scsi_pt_obj(ptvp);
646         if (get_scsi_pt_cdb_buf(ptvp))
647             local_cdb = false; /* N.B. Ignores locally built cdb */
648         else
649             set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb));
650         if (get_scsi_pt_sense_buf(ptvp))
651             local_sense = false;
652         else
653             set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
654     } else {
655         ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
656         if (NULL == ptvp)
657             return sg_convert_errno(ENOMEM);
658         set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb));
659         set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
660     }
661     set_scsi_pt_packet_id(ptvp, pack_id);
662     res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
663     ret = sg_cmds_process_resp(ptvp, tur_s, res, noisy, verbose, &sense_cat);
664     if (-1 == ret) {
665         if (get_scsi_pt_transport_err(ptvp))
666             ret = SG_LIB_TRANSPORT_ERROR;
667         else
668             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
669     } else if (-2 == ret) {
670         if (progress) {
671             int slen = get_scsi_pt_sense_len(ptvp);
672 
673             if (! sg_get_sense_progress_fld(sense_b, slen, progress))
674                 *progress = -1;
675         }
676         switch (sense_cat) {
677         case SG_LIB_CAT_RECOVERED:
678         case SG_LIB_CAT_NO_SENSE:
679             ret = 0;
680             break;
681         default:
682             ret = sense_cat;
683             break;
684         }
685     } else
686         ret = 0;
687     if (ptvp_given) {
688         if (local_sense)    /* stop caller trying to access local sense */
689             set_scsi_pt_sense(ptvp, NULL, 0);
690         if (local_cdb)
691             set_scsi_pt_cdb(ptvp, NULL, 0);
692     } else {
693         if (ptvp)
694             destruct_scsi_pt_obj(ptvp);
695     }
696     return ret;
697 }
698 
699 int
sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptvp,int pack_id,int * progress,bool noisy,int verbose)700 sg_ll_test_unit_ready_progress_pt(struct sg_pt_base * ptvp, int pack_id,
701                                   int * progress, bool noisy, int verbose)
702 {
703     return sg_ll_test_unit_ready_com(ptvp, -1, pack_id, progress, noisy,
704                                      verbose);
705 }
706 
707 int
sg_ll_test_unit_ready_progress(int sg_fd,int pack_id,int * progress,bool noisy,int verbose)708 sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress,
709                                bool noisy, int verbose)
710 {
711     return sg_ll_test_unit_ready_com(NULL, sg_fd, pack_id, progress, noisy,
712                                      verbose);
713 }
714 
715 /* Invokes a SCSI TEST UNIT READY command.
716  * 'pack_id' is just for diagnostics, safe to set to 0.
717  * Returns 0 when successful, various SG_LIB_CAT_* positive values or
718  * -1 -> other errors */
719 int
sg_ll_test_unit_ready(int sg_fd,int pack_id,bool noisy,int verbose)720 sg_ll_test_unit_ready(int sg_fd, int pack_id, bool noisy, int verbose)
721 {
722     return sg_ll_test_unit_ready_com(NULL, sg_fd, pack_id, NULL, noisy,
723                                      verbose);
724 }
725 
726 int
sg_ll_test_unit_ready_pt(struct sg_pt_base * ptvp,int pack_id,bool noisy,int verbose)727 sg_ll_test_unit_ready_pt(struct sg_pt_base * ptvp, int pack_id, bool noisy,
728                          int verbose)
729 {
730     return sg_ll_test_unit_ready_com(ptvp, -1, pack_id, NULL, noisy, verbose);
731 }
732 
733 /* Invokes a SCSI REQUEST SENSE command. Returns 0 when successful, various
734  * SG_LIB_CAT_* positive values or -1 -> other errors */
735 static int
sg_ll_request_sense_com(struct sg_pt_base * ptvp,int sg_fd,bool desc,void * resp,int mx_resp_len,bool noisy,int verbose)736 sg_ll_request_sense_com(struct sg_pt_base * ptvp, int sg_fd, bool desc,
737                         void * resp, int mx_resp_len, bool noisy, int verbose)
738 {
739     bool ptvp_given = false;
740     bool local_cdb = true;
741     bool local_sense = true;
742     int ret, res, sense_cat;
743     static const char * const rq_s = "request sense";
744     uint8_t rs_cdb[REQUEST_SENSE_CMDLEN] =
745         {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0};
746     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
747 
748     if (desc)
749         rs_cdb[1] |= 0x1;
750     if (mx_resp_len > 0xff) {
751         pr2ws("mx_resp_len cannot exceed 255\n");
752         return -1;
753     }
754     rs_cdb[4] = mx_resp_len & 0xff;
755     if (verbose) {
756         char b[128];
757 
758         pr2ws("    %s cdb: %s\n", rq_s,
759               sg_get_command_str(rs_cdb, REQUEST_SENSE_CMDLEN, false,
760                                  sizeof(b), b));
761     }
762     if (ptvp) {
763         ptvp_given = true;
764         if (get_scsi_pt_cdb_buf(ptvp))
765             local_cdb = false;
766         else
767             set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
768         if (get_scsi_pt_sense_buf(ptvp))
769             local_sense = false;
770         else
771             set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
772     } else {
773         ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
774         if (NULL == ptvp)
775             return sg_convert_errno(ENOMEM);
776         set_scsi_pt_cdb(ptvp, rs_cdb, sizeof(rs_cdb));
777         set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
778     }
779     set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
780     res = do_scsi_pt(ptvp, -1, DEF_PT_TIMEOUT, verbose);
781     ret = sg_cmds_process_resp(ptvp, rq_s, res, noisy, verbose, &sense_cat);
782     if (-1 == ret) {
783         if (get_scsi_pt_transport_err(ptvp))
784             ret = SG_LIB_TRANSPORT_ERROR;
785         else
786             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
787     } else if (-2 == ret) {
788         switch (sense_cat) {
789         case SG_LIB_CAT_RECOVERED:
790         case SG_LIB_CAT_NO_SENSE:
791             ret = 0;
792             break;
793         default:
794             ret = sense_cat;
795             break;
796         }
797     } else {
798         if ((mx_resp_len >= 8) && (ret < 8)) {
799             if (verbose)
800                 pr2ws("    %s: got %d bytes in response, too short\n", rq_s,
801                       ret);
802             ret = -1;
803         } else
804             ret = 0;
805     }
806     if (ptvp_given) {
807         if (local_sense)        /* stop caller accessing local sense */
808         set_scsi_pt_sense(ptvp, NULL, 0);
809         if (local_cdb)  /* stop caller accessing local sense */
810         set_scsi_pt_cdb(ptvp, NULL, 0);
811     } else if (ptvp)
812         destruct_scsi_pt_obj(ptvp);
813     return ret;
814 }
815 
816 int
sg_ll_request_sense(int sg_fd,bool desc,void * resp,int mx_resp_len,bool noisy,int verbose)817 sg_ll_request_sense(int sg_fd, bool desc, void * resp, int mx_resp_len,
818                     bool noisy, int verbose)
819 {
820     return sg_ll_request_sense_com(NULL, sg_fd, desc, resp, mx_resp_len,
821                                    noisy, verbose);
822 }
823 
824 int
sg_ll_request_sense_pt(struct sg_pt_base * ptvp,bool desc,void * resp,int mx_resp_len,bool noisy,int verbose)825 sg_ll_request_sense_pt(struct sg_pt_base * ptvp, bool desc, void * resp,
826                        int mx_resp_len, bool noisy, int verbose)
827 {
828     return sg_ll_request_sense_com(ptvp, -1, desc, resp, mx_resp_len,
829                                    noisy, verbose);
830 }
831 
832 /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
833  * various SG_LIB_CAT_* positive values or -1 -> other errors */
834 static int
sg_ll_report_luns_com(struct sg_pt_base * ptvp,int sg_fd,int select_report,void * resp,int mx_resp_len,bool noisy,int verbose)835 sg_ll_report_luns_com(struct sg_pt_base * ptvp, int sg_fd, int select_report,
836                       void * resp, int mx_resp_len, bool noisy, int verbose)
837 {
838     static const char * const report_luns_s = "report luns";
839     bool ptvp_given = false;
840     bool local_cdb = true;
841     bool local_sense = true;
842     int ret, res, sense_cat;
843     uint8_t rl_cdb[REPORT_LUNS_CMDLEN] =
844                          {REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
845     uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
846 
847     rl_cdb[2] = select_report & 0xff;
848     sg_put_unaligned_be32((uint32_t)mx_resp_len, rl_cdb + 6);
849     if (verbose) {
850         char b[128];
851 
852         pr2ws("    %s cdb: %s\n", report_luns_s,
853               sg_get_command_str(rl_cdb, REPORT_LUNS_CMDLEN, false,
854                                  sizeof(b), b));
855     }
856     if (ptvp) {
857         ptvp_given = true;
858         partial_clear_scsi_pt_obj(ptvp);
859         if (get_scsi_pt_cdb_buf(ptvp))
860             local_cdb = false;
861         else
862             set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb));
863         if (get_scsi_pt_sense_buf(ptvp))
864             local_sense = false;
865         else
866             set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
867     } else {
868         if (NULL == ((ptvp = create_pt_obj(report_luns_s))))
869             return sg_convert_errno(ENOMEM);
870         set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb));
871         set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
872     }
873     set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
874     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
875     ret = sg_cmds_process_resp(ptvp, report_luns_s, res, noisy, verbose,
876                                &sense_cat);
877     if (-1 == ret) {
878         if (get_scsi_pt_transport_err(ptvp))
879             ret = SG_LIB_TRANSPORT_ERROR;
880         else
881             ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
882     } else if (-2 == ret) {
883         switch (sense_cat) {
884         case SG_LIB_CAT_RECOVERED:
885         case SG_LIB_CAT_NO_SENSE:
886             ret = 0;
887             break;
888         default:
889             ret = sense_cat;
890             break;
891         }
892     } else
893         ret = 0;
894     if (ptvp_given) {
895         if (local_sense)        /* stop caller accessing local sense */
896             set_scsi_pt_sense(ptvp, NULL, 0);
897         if (local_cdb)
898             set_scsi_pt_cdb(ptvp, NULL, 0);
899     } else {
900         if (ptvp)
901             destruct_scsi_pt_obj(ptvp);
902     }
903     return ret;
904 }
905 
906 /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
907  * various SG_LIB_CAT_* positive values or -1 -> other errors,
908  * Expects sg_fd to be >= 0 representing an open device fd. */
909 int
sg_ll_report_luns(int sg_fd,int select_report,void * resp,int mx_resp_len,bool noisy,int verbose)910 sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len,
911                   bool noisy, int verbose)
912 {
913     return sg_ll_report_luns_com(NULL, sg_fd, select_report, resp,
914                                  mx_resp_len, noisy, verbose);
915 }
916 
917 
918 /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success,
919  * various SG_LIB_CAT_* positive values or -1 -> other errors.
920  * Expects a non-NULL ptvp containing an open device fd. */
921 int
sg_ll_report_luns_pt(struct sg_pt_base * ptvp,int select_report,void * resp,int mx_resp_len,bool noisy,int verbose)922 sg_ll_report_luns_pt(struct sg_pt_base * ptvp, int select_report,
923                      void * resp, int mx_resp_len, bool noisy, int verbose)
924 {
925     return sg_ll_report_luns_com(ptvp, -1, select_report, resp,
926                                  mx_resp_len, noisy, verbose);
927 }
928