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