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 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <string.h>
12 #include <unistd.h>
13 #define __STDC_FORMAT_MACROS 1
14 #include <inttypes.h>
15 
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19 
20 #include "sg_lib.h"
21 #include "sg_lib_data.h"
22 #include "sg_cmds_basic.h"
23 #include "sg_cmds_extra.h"
24 #include "sg_pt.h"
25 #include "sg_unaligned.h"
26 
27 
28 #define SENSE_BUFF_LEN 64       /* Arbitrary, could be larger */
29 
30 #define DEF_PT_TIMEOUT 60       /* 60 seconds */
31 #define LONG_PT_TIMEOUT 7200    /* 7,200 seconds == 120 minutes */
32 
33 #define SERVICE_ACTION_IN_16_CMD 0x9e
34 #define SERVICE_ACTION_IN_16_CMDLEN 16
35 #define SERVICE_ACTION_OUT_16_CMD 0x9f
36 #define SERVICE_ACTION_OUT_16_CMDLEN 16
37 #define MAINTENANCE_IN_CMD 0xa3
38 #define MAINTENANCE_IN_CMDLEN 12
39 #define MAINTENANCE_OUT_CMD 0xa4
40 #define MAINTENANCE_OUT_CMDLEN 12
41 
42 #define ATA_PT_12_CMD 0xa1
43 #define ATA_PT_12_CMDLEN 12
44 #define ATA_PT_16_CMD 0x85
45 #define ATA_PT_16_CMDLEN 16
46 #define ATA_PT_32_SA 0x1ff0
47 #define ATA_PT_32_CMDLEN 32
48 #define FORMAT_UNIT_CMD 0x4
49 #define FORMAT_UNIT_CMDLEN 6
50 #define PERSISTENT_RESERVE_IN_CMD 0x5e
51 #define PERSISTENT_RESERVE_IN_CMDLEN 10
52 #define PERSISTENT_RESERVE_OUT_CMD 0x5f
53 #define PERSISTENT_RESERVE_OUT_CMDLEN 10
54 #define READ_BLOCK_LIMITS_CMD 0x5
55 #define READ_BLOCK_LIMITS_CMDLEN 6
56 #define READ_BUFFER_CMD 0x3c
57 #define READ_BUFFER_CMDLEN 10
58 #define READ_DEFECT10_CMD     0x37
59 #define READ_DEFECT10_CMDLEN    10
60 #define REASSIGN_BLKS_CMD     0x7
61 #define REASSIGN_BLKS_CMDLEN  6
62 #define RECEIVE_DIAGNOSTICS_CMD   0x1c
63 #define RECEIVE_DIAGNOSTICS_CMDLEN  6
64 #define THIRD_PARTY_COPY_OUT_CMD 0x83   /* was EXTENDED_COPY_CMD */
65 #define THIRD_PARTY_COPY_OUT_CMDLEN 16
66 #define THIRD_PARTY_COPY_IN_CMD 0x84     /* was RECEIVE_COPY_RESULTS_CMD */
67 #define THIRD_PARTY_COPY_IN_CMDLEN 16
68 #define SEND_DIAGNOSTIC_CMD   0x1d
69 #define SEND_DIAGNOSTIC_CMDLEN  6
70 #define SERVICE_ACTION_IN_12_CMD 0xab
71 #define SERVICE_ACTION_IN_12_CMDLEN 12
72 #define READ_LONG10_CMD 0x3e
73 #define READ_LONG10_CMDLEN 10
74 #define UNMAP_CMD 0x42
75 #define UNMAP_CMDLEN 10
76 #define VERIFY10_CMD 0x2f
77 #define VERIFY10_CMDLEN 10
78 #define VERIFY16_CMD 0x8f
79 #define VERIFY16_CMDLEN 16
80 #define WRITE_LONG10_CMD 0x3f
81 #define WRITE_LONG10_CMDLEN 10
82 #define WRITE_BUFFER_CMD 0x3b
83 #define WRITE_BUFFER_CMDLEN 10
84 #define PRE_FETCH10_CMD 0x34
85 #define PRE_FETCH10_CMDLEN 10
86 #define PRE_FETCH16_CMD 0x90
87 #define PRE_FETCH16_CMDLEN 16
88 #define SEEK10_CMD 0x2b
89 #define SEEK10_CMDLEN 10
90 
91 #define GET_LBA_STATUS16_SA 0x12
92 #define GET_LBA_STATUS32_SA 0x12
93 #define READ_LONG_16_SA 0x11
94 #define READ_MEDIA_SERIAL_NUM_SA 0x1
95 #define REPORT_IDENTIFYING_INFORMATION_SA 0x5
96 #define REPORT_TGT_PRT_GRP_SA 0xa
97 #define SET_IDENTIFYING_INFORMATION_SA 0x6
98 #define SET_TGT_PRT_GRP_SA 0xa
99 #define WRITE_LONG_16_SA 0x11
100 #define REPORT_REFERRALS_SA 0x13
101 #define EXTENDED_COPY_LID1_SA 0x0
102 
103 #if defined(__GNUC__) || defined(__clang__)
104 static int pr2ws(const char * fmt, ...)
105         __attribute__ ((format (printf, 1, 2)));
106 #else
107 static int pr2ws(const char * fmt, ...);
108 #endif
109 
110 
111 static int
pr2ws(const char * fmt,...)112 pr2ws(const char * fmt, ...)
113 {
114     va_list args;
115     int n;
116 
117     va_start(args, fmt);
118     n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
119     va_end(args);
120     return n;
121 }
122 
123 static struct sg_pt_base *
create_pt_obj(const char * cname)124 create_pt_obj(const char * cname)
125 {
126     struct sg_pt_base * ptvp = construct_scsi_pt_obj();
127     if (NULL == ptvp)
128         pr2ws("%s: out of memory\n", cname);
129     return ptvp;
130 }
131 
132 
133 /* Invokes a SCSI GET LBA STATUS(16) command (SBC). Returns 0 -> success,
134  * various SG_LIB_CAT_* positive values or -1 -> other errors */
135 int
sg_ll_get_lba_status16(int sg_fd,uint64_t start_llba,uint8_t rt,void * resp,int alloc_len,bool noisy,int verbose)136 sg_ll_get_lba_status16(int sg_fd, uint64_t start_llba, uint8_t rt,
137                       void * resp, int alloc_len, bool noisy, int verbose)
138 {
139     static const char * const cdb_name_s = "Get LBA status(16)";
140     int k, res, sense_cat, ret;
141     unsigned char getLbaStatCmd[SERVICE_ACTION_IN_16_CMDLEN];
142     unsigned char sense_b[SENSE_BUFF_LEN];
143     struct sg_pt_base * ptvp;
144 
145     memset(getLbaStatCmd, 0, sizeof(getLbaStatCmd));
146     getLbaStatCmd[0] = SERVICE_ACTION_IN_16_CMD;
147     getLbaStatCmd[1] = GET_LBA_STATUS16_SA;
148 
149     sg_put_unaligned_be64(start_llba, getLbaStatCmd + 2);
150     sg_put_unaligned_be32((uint32_t)alloc_len, getLbaStatCmd + 10);
151     getLbaStatCmd[14] = rt;
152     if (verbose) {
153         pr2ws("    %s cdb: ", cdb_name_s);
154         for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
155             pr2ws("%02x ", getLbaStatCmd[k]);
156         pr2ws("\n");
157     }
158 
159     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
160         return -1;
161     set_scsi_pt_cdb(ptvp, getLbaStatCmd, sizeof(getLbaStatCmd));
162     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
163     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, alloc_len);
164     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
165     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, alloc_len, sense_b,
166                                noisy, verbose, &sense_cat);
167     if (-1 == ret) {
168         int os_err = get_scsi_pt_os_err(ptvp);
169 
170         if ((os_err > 0) && (os_err < 47))
171             ret = SG_LIB_OS_BASE_ERR + os_err;
172     } else if (-2 == ret) {
173         switch (sense_cat) {
174         case SG_LIB_CAT_RECOVERED:
175         case SG_LIB_CAT_NO_SENSE:
176             ret = 0;
177             break;
178         default:
179             ret = sense_cat;
180             break;
181         }
182     } else {
183         if ((verbose > 2) && (ret > 0)) {
184             pr2ws("    %s: response\n", cdb_name_s);
185             if (3 == verbose) {
186                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
187                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
188                            -1);
189             } else {
190                 pr2ws(":\n");
191                 hex2stderr((const uint8_t *)resp, ret, 0);
192             }
193         }
194         ret = 0;
195     }
196     destruct_scsi_pt_obj(ptvp);
197     return ret;
198 }
199 
200 int
sg_ll_get_lba_status(int sg_fd,uint64_t start_llba,void * resp,int alloc_len,bool noisy,int verbose)201 sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp,
202                      int alloc_len, bool noisy, int verbose)
203 {
204     return sg_ll_get_lba_status16(sg_fd, start_llba, /* rt = */ 0x0, resp,
205                                   alloc_len, noisy, verbose);
206 }
207 
208 #define GLS32_CMD_LEN 32
209 
210 int
sg_ll_get_lba_status32(int sg_fd,uint64_t start_llba,uint32_t scan_len,uint32_t element_id,uint8_t rt,void * resp,int alloc_len,bool noisy,int verbose)211 sg_ll_get_lba_status32(int sg_fd, uint64_t start_llba, uint32_t scan_len,
212                        uint32_t element_id, uint8_t rt,
213                        void * resp, int alloc_len, bool noisy,
214                        int verbose)
215 {
216     static const char * const cdb_name_s = "Get LBA status(32)";
217     int k, res, sense_cat, ret;
218     unsigned char gls32_cmd[GLS32_CMD_LEN];
219     unsigned char sense_b[SENSE_BUFF_LEN];
220     struct sg_pt_base * ptvp;
221 
222     memset(gls32_cmd, 0, sizeof(gls32_cmd));
223     gls32_cmd[0] = SG_VARIABLE_LENGTH_CMD;
224     gls32_cmd[7] = GLS32_CMD_LEN - 8;
225     sg_put_unaligned_be16((uint16_t)GET_LBA_STATUS32_SA, gls32_cmd + 8);
226     gls32_cmd[10] = rt;
227     sg_put_unaligned_be64(start_llba, gls32_cmd + 12);
228     sg_put_unaligned_be32(scan_len, gls32_cmd + 20);
229     sg_put_unaligned_be32(element_id, gls32_cmd + 24);
230     sg_put_unaligned_be32((uint32_t)alloc_len, gls32_cmd + 28);
231     if (verbose) {
232         pr2ws("    %s cdb: ", cdb_name_s);
233         for (k = 0; k < GLS32_CMD_LEN; ++k)
234             pr2ws("%02x ", gls32_cmd[k]);
235         pr2ws("\n");
236     }
237 
238     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
239         return -1;
240     set_scsi_pt_cdb(ptvp, gls32_cmd, sizeof(gls32_cmd));
241     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
242     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, alloc_len);
243     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
244     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, alloc_len, sense_b,
245                                noisy, verbose, &sense_cat);
246     if (-1 == ret) {
247         int os_err = get_scsi_pt_os_err(ptvp);
248 
249         if ((os_err > 0) && (os_err < 47))
250             ret = SG_LIB_OS_BASE_ERR + os_err;
251     } else if (-2 == ret) {
252         switch (sense_cat) {
253         case SG_LIB_CAT_RECOVERED:
254         case SG_LIB_CAT_NO_SENSE:
255             ret = 0;
256             break;
257         default:
258             ret = sense_cat;
259             break;
260         }
261     } else {
262         if ((verbose > 2) && (ret > 0)) {
263             pr2ws("    %s: response\n", cdb_name_s);
264             if (3 == verbose) {
265                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
266                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
267                            -1);
268             } else {
269                 pr2ws(":\n");
270                 hex2stderr((const uint8_t *)resp, ret, 0);
271             }
272         }
273         ret = 0;
274     }
275     destruct_scsi_pt_obj(ptvp);
276     return ret;
277 }
278 
279 int
sg_ll_report_tgt_prt_grp(int sg_fd,void * resp,int mx_resp_len,bool noisy,int verbose)280 sg_ll_report_tgt_prt_grp(int sg_fd, void * resp, int mx_resp_len,
281                          bool noisy, int verbose)
282 {
283     return sg_ll_report_tgt_prt_grp2(sg_fd, resp, mx_resp_len, false, noisy,
284                                      verbose);
285 }
286 
287 /* Invokes a SCSI REPORT TARGET PORT GROUPS command. Return of 0 -> success,
288  * various SG_LIB_CAT_* positive values or -1 -> other errors */
289 int
sg_ll_report_tgt_prt_grp2(int sg_fd,void * resp,int mx_resp_len,bool extended,bool noisy,int verbose)290 sg_ll_report_tgt_prt_grp2(int sg_fd, void * resp, int mx_resp_len,
291                           bool extended, bool noisy, int verbose)
292 {
293     static const char * const cdb_name_s = "Report target port groups";
294     int k, res, ret, sense_cat;
295     unsigned char rtpg_cdb[MAINTENANCE_IN_CMDLEN] =
296                          {MAINTENANCE_IN_CMD, REPORT_TGT_PRT_GRP_SA,
297                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
298     unsigned char sense_b[SENSE_BUFF_LEN];
299     struct sg_pt_base * ptvp;
300 
301     if (extended)
302         rtpg_cdb[1] |= 0x20;
303     sg_put_unaligned_be32((uint32_t)mx_resp_len, rtpg_cdb + 6);
304     if (verbose) {
305         pr2ws("    %s cdb: ", cdb_name_s);
306         for (k = 0; k < MAINTENANCE_IN_CMDLEN; ++k)
307             pr2ws("%02x ", rtpg_cdb[k]);
308         pr2ws("\n");
309     }
310 
311     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
312         return -1;
313     set_scsi_pt_cdb(ptvp, rtpg_cdb, sizeof(rtpg_cdb));
314     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
315     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
316     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
317     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
318                                noisy, verbose, &sense_cat);
319     if (-1 == ret) {
320         int os_err = get_scsi_pt_os_err(ptvp);
321 
322         if ((os_err > 0) && (os_err < 47))
323             ret = SG_LIB_OS_BASE_ERR + os_err;
324     } else if (-2 == ret) {
325         switch (sense_cat) {
326         case SG_LIB_CAT_RECOVERED:
327         case SG_LIB_CAT_NO_SENSE:
328             ret = 0;
329             break;
330         default:
331             ret = sense_cat;
332             break;
333         }
334     } else {
335         if ((verbose > 2) && (ret > 0)) {
336             pr2ws("    %s: response", cdb_name_s);
337             if (3 == verbose) {
338                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
339                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
340                            -1);
341             } else {
342                 pr2ws(":\n");
343                 hex2stderr((const uint8_t *)resp, ret, 0);
344             }
345         }
346         ret = 0;
347     }
348     destruct_scsi_pt_obj(ptvp);
349     return ret;
350 }
351 
352 /* Invokes a SCSI SET TARGET PORT GROUPS command. Return of 0 -> success,
353  * various SG_LIB_CAT_* positive values or -1 -> other errors */
354 int
sg_ll_set_tgt_prt_grp(int sg_fd,void * paramp,int param_len,bool noisy,int verbose)355 sg_ll_set_tgt_prt_grp(int sg_fd, void * paramp, int param_len, bool noisy,
356                       int verbose)
357 {
358     static const char * const cdb_name_s = "Set target port groups";
359     int k, res, ret, sense_cat;
360     unsigned char stpg_cdb[MAINTENANCE_OUT_CMDLEN] =
361                          {MAINTENANCE_OUT_CMD, SET_TGT_PRT_GRP_SA,
362                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
363     unsigned char sense_b[SENSE_BUFF_LEN];
364     struct sg_pt_base * ptvp;
365 
366     sg_put_unaligned_be32((uint32_t)param_len, stpg_cdb + 6);
367     if (verbose) {
368         pr2ws("    %s cdb: ", cdb_name_s);
369         for (k = 0; k < MAINTENANCE_OUT_CMDLEN; ++k)
370             pr2ws("%02x ", stpg_cdb[k]);
371         pr2ws("\n");
372         if ((verbose > 1) && paramp && param_len) {
373             pr2ws("    %s parameter list:\n", cdb_name_s);
374             hex2stderr((const uint8_t *)paramp, param_len, -1);
375         }
376     }
377 
378     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
379         return -1;
380     set_scsi_pt_cdb(ptvp, stpg_cdb, sizeof(stpg_cdb));
381     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
382     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
383     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
384     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
385                                noisy, verbose, &sense_cat);
386     if (-1 == ret) {
387         int os_err = get_scsi_pt_os_err(ptvp);
388 
389         if ((os_err > 0) && (os_err < 47))
390             ret = SG_LIB_OS_BASE_ERR + os_err;
391     } else if (-2 == ret) {
392         switch (sense_cat) {
393         case SG_LIB_CAT_RECOVERED:
394         case SG_LIB_CAT_NO_SENSE:
395             ret = 0;
396             break;
397         default:
398             ret = sense_cat;
399             break;
400         }
401     } else
402         ret = 0;
403     destruct_scsi_pt_obj(ptvp);
404     return ret;
405 }
406 
407 /* Invokes a SCSI REPORT REFERRALS command. Return of 0 -> success,
408  * various SG_LIB_CAT_* positive values or -1 -> other errors */
409 int
sg_ll_report_referrals(int sg_fd,uint64_t start_llba,bool one_seg,void * resp,int mx_resp_len,bool noisy,int verbose)410 sg_ll_report_referrals(int sg_fd, uint64_t start_llba, bool one_seg,
411                        void * resp, int mx_resp_len, bool noisy,
412                        int verbose)
413 {
414     static const char * const cdb_name_s = "Report referrals";
415     int k, res, ret, sense_cat;
416     unsigned char repRef_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
417                          {SERVICE_ACTION_IN_16_CMD, REPORT_REFERRALS_SA,
418                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
419     unsigned char sense_b[SENSE_BUFF_LEN];
420     struct sg_pt_base * ptvp;
421 
422     sg_put_unaligned_be64(start_llba, repRef_cdb + 2);
423     sg_put_unaligned_be32((uint32_t)mx_resp_len, repRef_cdb + 10);
424     if (one_seg)
425         repRef_cdb[14] = 0x1;
426     if (verbose) {
427         pr2ws("    %s cdb: ", cdb_name_s);
428         for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
429             pr2ws("%02x ", repRef_cdb[k]);
430         pr2ws("\n");
431     }
432 
433     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
434         return -1;
435     set_scsi_pt_cdb(ptvp, repRef_cdb, sizeof(repRef_cdb));
436     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
437     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
438     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
439     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
440                                noisy, verbose, &sense_cat);
441     if (-1 == ret) {
442         int os_err = get_scsi_pt_os_err(ptvp);
443 
444         if ((os_err > 0) && (os_err < 47))
445             ret = SG_LIB_OS_BASE_ERR + os_err;
446     } else if (-2 == ret) {
447         switch (sense_cat) {
448         case SG_LIB_CAT_RECOVERED:
449         case SG_LIB_CAT_NO_SENSE:
450             ret = 0;
451             break;
452         default:
453             ret = sense_cat;
454             break;
455         }
456     } else {
457         if ((verbose > 2) && (ret > 0)) {
458             pr2ws("    %s: response", cdb_name_s);
459             if (3 == verbose) {
460                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
461                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
462                            -1);
463             } else {
464                 pr2ws(":\n");
465                 hex2stderr((const uint8_t *)resp, ret, 0);
466             }
467         }
468         ret = 0;
469     }
470     destruct_scsi_pt_obj(ptvp);
471     return ret;
472 }
473 
474 /* Invokes a SCSI SEND DIAGNOSTIC command. Foreground, extended self tests can
475  * take a long time, if so set long_duration flag in which case the timeout
476  * is set to 7200 seconds; if the value of long_duration is > 7200 then that
477  * value is taken as the timeout value in seconds. Return of 0 -> success,
478  * various SG_LIB_CAT_* positive values or -1 -> other errors */
479 int
sg_ll_send_diag(int sg_fd,int st_code,bool pf_bit,bool st_bit,bool devofl_bit,bool unitofl_bit,int long_duration,void * paramp,int param_len,bool noisy,int verbose)480 sg_ll_send_diag(int sg_fd, int st_code, bool pf_bit, bool st_bit,
481                 bool devofl_bit, bool unitofl_bit, int long_duration,
482                 void * paramp, int param_len, bool noisy, int verbose)
483 {
484     static const char * const cdb_name_s = "Send diagnostic";
485     int k, res, ret, sense_cat, tmout;
486     unsigned char senddiag_cdb[SEND_DIAGNOSTIC_CMDLEN] =
487         {SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0};
488     unsigned char sense_b[SENSE_BUFF_LEN];
489     struct sg_pt_base * ptvp;
490 
491     senddiag_cdb[1] = (unsigned char)(st_code << 5);
492     if (pf_bit)
493         senddiag_cdb[1] |= 0x10;
494     if (st_bit)
495         senddiag_cdb[1] |= 0x4;
496     if (devofl_bit)
497         senddiag_cdb[1] |= 0x2;
498     if (unitofl_bit)
499         senddiag_cdb[1] |= 0x1;
500     sg_put_unaligned_be16((uint16_t)param_len, senddiag_cdb + 3);
501     if (long_duration > LONG_PT_TIMEOUT)
502         tmout = long_duration;
503     else
504         tmout = long_duration ? LONG_PT_TIMEOUT : DEF_PT_TIMEOUT;
505 
506     if (verbose) {
507         pr2ws("    %s cdb: ", cdb_name_s);
508         for (k = 0; k < SEND_DIAGNOSTIC_CMDLEN; ++k)
509             pr2ws("%02x ", senddiag_cdb[k]);
510         pr2ws("\n");
511         if (verbose > 1) {
512             if (paramp && param_len) {
513                 pr2ws("    %s parameter list:\n", cdb_name_s);
514                 hex2stderr((const uint8_t *)paramp, param_len, -1);
515             }
516             pr2ws("    %s timeout: %d seconds\n", cdb_name_s, tmout);
517         }
518     }
519 
520     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
521         return -1;
522     set_scsi_pt_cdb(ptvp, senddiag_cdb, sizeof(senddiag_cdb));
523     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
524     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
525     res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
526     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
527                                noisy, verbose, &sense_cat);
528     if (-1 == ret) {
529         int os_err = get_scsi_pt_os_err(ptvp);
530 
531         if ((os_err > 0) && (os_err < 47))
532             ret = SG_LIB_OS_BASE_ERR + os_err;
533     } else if (-2 == ret) {
534         switch (sense_cat) {
535         case SG_LIB_CAT_RECOVERED:
536         case SG_LIB_CAT_NO_SENSE:
537             ret = 0;
538             break;
539         default:
540             ret = sense_cat;
541             break;
542         }
543     } else
544         ret = 0;
545 
546     destruct_scsi_pt_obj(ptvp);
547     return ret;
548 }
549 
550 /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success,
551  * various SG_LIB_CAT_* positive values or -1 -> other errors */
552 int
sg_ll_receive_diag(int sg_fd,bool pcv,int pg_code,void * resp,int mx_resp_len,bool noisy,int verbose)553 sg_ll_receive_diag(int sg_fd, bool pcv, int pg_code, void * resp,
554                    int mx_resp_len, bool noisy, int verbose)
555 {
556     return sg_ll_receive_diag_v2(sg_fd, pcv, pg_code, resp, mx_resp_len, 0,
557                                  NULL, noisy, verbose);
558 }
559 
560 /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success,
561  * various SG_LIB_CAT_* positive values or -1 -> other errors */
562 int
sg_ll_receive_diag_v2(int sg_fd,bool pcv,int pg_code,void * resp,int mx_resp_len,int timeout_secs,int * residp,bool noisy,int verbose)563 sg_ll_receive_diag_v2(int sg_fd, bool pcv, int pg_code, void * resp,
564                       int mx_resp_len, int timeout_secs, int * residp,
565                       bool noisy, int verbose)
566 {
567     int resid = 0;
568     int k, res, ret, sense_cat;
569     static const char * const cdb_name_s = "Receive diagnostic results";
570     struct sg_pt_base * ptvp;
571     unsigned char rcvdiag_cdb[RECEIVE_DIAGNOSTICS_CMDLEN] =
572         {RECEIVE_DIAGNOSTICS_CMD, 0, 0, 0, 0, 0};
573     unsigned char sense_b[SENSE_BUFF_LEN];
574 
575     if (pcv)
576         rcvdiag_cdb[1] = 0x1;
577     rcvdiag_cdb[2] = (unsigned char)(pg_code);
578     sg_put_unaligned_be16((uint16_t)mx_resp_len, rcvdiag_cdb + 3);
579 
580     if (verbose) {
581         pr2ws("    %s cdb: ", cdb_name_s);
582         for (k = 0; k < RECEIVE_DIAGNOSTICS_CMDLEN; ++k)
583             pr2ws("%02x ", rcvdiag_cdb[k]);
584         pr2ws("\n");
585     }
586     if (timeout_secs <= 0)
587         timeout_secs = DEF_PT_TIMEOUT;
588 
589     if (NULL == ((ptvp = create_pt_obj(cdb_name_s)))) {
590         if (residp)
591             *residp = 0;
592         return -1;
593     }
594     set_scsi_pt_cdb(ptvp, rcvdiag_cdb, sizeof(rcvdiag_cdb));
595     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
596     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
597     res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
598     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
599                                noisy, verbose, &sense_cat);
600     resid = get_scsi_pt_resid(ptvp);
601     if (residp)
602         *residp = resid;
603     if (-1 == ret) {
604         int os_err = get_scsi_pt_os_err(ptvp);
605 
606         if ((os_err > 0) && (os_err < 47))
607             ret = SG_LIB_OS_BASE_ERR + os_err;
608     } else if (-2 == ret) {
609         switch (sense_cat) {
610         case SG_LIB_CAT_RECOVERED:
611         case SG_LIB_CAT_NO_SENSE:
612             ret = 0;
613             break;
614         default:
615             ret = sense_cat;
616             break;
617         }
618     } else {
619         if ((verbose > 2) && (ret > 0)) {
620             pr2ws("    %s: response", cdb_name_s);
621             if (3 == verbose) {
622                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
623                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
624                             -1);
625             } else {
626                 pr2ws(":\n");
627                 hex2stderr((const uint8_t *)resp, ret, 0);
628             }
629         }
630         ret = 0;
631     }
632     destruct_scsi_pt_obj(ptvp);
633     return ret;
634 }
635 
636 /* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 -> success
637  * various SG_LIB_CAT_* positive values or -1 -> other errors */
638 int
sg_ll_read_defect10(int sg_fd,bool req_plist,bool req_glist,int dl_format,void * resp,int mx_resp_len,bool noisy,int verbose)639 sg_ll_read_defect10(int sg_fd, bool req_plist, bool req_glist, int dl_format,
640                     void * resp, int mx_resp_len, bool noisy, int verbose)
641 {
642     static const char * const cdb_name_s = "Read defect(10)";
643     int res, k, ret, sense_cat;
644     unsigned char rdef_cdb[READ_DEFECT10_CMDLEN] =
645         {READ_DEFECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
646     unsigned char sense_b[SENSE_BUFF_LEN];
647     struct sg_pt_base * ptvp;
648 
649     rdef_cdb[2] = (dl_format & 0x7);
650     if (req_plist)
651         rdef_cdb[2] |= 0x10;
652     if (req_glist)
653         rdef_cdb[2] |= 0x8;
654     sg_put_unaligned_be16((uint16_t)mx_resp_len, rdef_cdb + 7);
655     if (mx_resp_len > 0xffff) {
656         pr2ws("mx_resp_len too big\n");
657         return -1;
658     }
659     if (verbose) {
660         pr2ws("    %s cdb: ", cdb_name_s);
661         for (k = 0; k < READ_DEFECT10_CMDLEN; ++k)
662             pr2ws("%02x ", rdef_cdb[k]);
663         pr2ws("\n");
664     }
665 
666     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
667         return -1;
668     set_scsi_pt_cdb(ptvp, rdef_cdb, sizeof(rdef_cdb));
669     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
670     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
671     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
672     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
673                                noisy, verbose, &sense_cat);
674     if (-1 == ret) {
675         int os_err = get_scsi_pt_os_err(ptvp);
676 
677         if ((os_err > 0) && (os_err < 47))
678             ret = SG_LIB_OS_BASE_ERR + os_err;
679     } else if (-2 == ret) {
680         switch (sense_cat) {
681         case SG_LIB_CAT_RECOVERED:
682         case SG_LIB_CAT_NO_SENSE:
683             ret = 0;
684             break;
685         default:
686             ret = sense_cat;
687             break;
688         }
689     } else {
690         if ((verbose > 2) && (ret > 0)) {
691             pr2ws("    %s: response\n", cdb_name_s);
692             if (3 == verbose) {
693                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
694                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
695                            -1);
696             } else {
697                 pr2ws(":\n");
698                 hex2stderr((const uint8_t *)resp, ret, 0);
699             }
700         }
701         ret = 0;
702     }
703     destruct_scsi_pt_obj(ptvp);
704     return ret;
705 }
706 
707 /* Invokes a SCSI READ MEDIA SERIAL NUMBER command. Return of 0 -> success,
708  * various SG_LIB_CAT_* positive values or -1 -> other errors */
709 int
sg_ll_read_media_serial_num(int sg_fd,void * resp,int mx_resp_len,bool noisy,int verbose)710 sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len,
711                             bool noisy, int verbose)
712 {
713     static const char * const cdb_name_s = "Read media serial number";
714     int k, res, ret, sense_cat;
715     unsigned char rmsn_cdb[SERVICE_ACTION_IN_12_CMDLEN] =
716                          {SERVICE_ACTION_IN_12_CMD, READ_MEDIA_SERIAL_NUM_SA,
717                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
718     unsigned char sense_b[SENSE_BUFF_LEN];
719     struct sg_pt_base * ptvp;
720 
721     sg_put_unaligned_be32((uint32_t)mx_resp_len, rmsn_cdb + 6);
722     if (verbose) {
723         pr2ws("    %s cdb: ", cdb_name_s);
724         for (k = 0; k < SERVICE_ACTION_IN_12_CMDLEN; ++k)
725             pr2ws("%02x ", rmsn_cdb[k]);
726         pr2ws("\n");
727     }
728 
729     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
730         return -1;
731     set_scsi_pt_cdb(ptvp, rmsn_cdb, sizeof(rmsn_cdb));
732     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
733     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
734     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
735     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
736                                noisy, verbose, &sense_cat);
737     if (-1 == ret) {
738         int os_err = get_scsi_pt_os_err(ptvp);
739 
740         if ((os_err > 0) && (os_err < 47))
741             ret = SG_LIB_OS_BASE_ERR + os_err;
742     } else if (-2 == ret) {
743         switch (sense_cat) {
744         case SG_LIB_CAT_RECOVERED:
745         case SG_LIB_CAT_NO_SENSE:
746             ret = 0;
747             break;
748         default:
749             ret = sense_cat;
750             break;
751         }
752     } else {
753         if ((verbose > 2) && (ret > 0)) {
754             pr2ws("    %s: response", cdb_name_s);
755             if (3 == verbose) {
756                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
757                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
758                            -1);
759             } else {
760                 pr2ws(":\n");
761                 hex2stderr((const uint8_t *)resp, ret, 0);
762             }
763         }
764         ret = 0;
765     }
766     destruct_scsi_pt_obj(ptvp);
767     return ret;
768 }
769 
770 /* Invokes a SCSI REPORT IDENTIFYING INFORMATION command. This command was
771  * called REPORT DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success,
772  * various SG_LIB_CAT_* positive values or -1 -> other errors */
773 int
sg_ll_report_id_info(int sg_fd,int itype,void * resp,int max_resp_len,bool noisy,int verbose)774 sg_ll_report_id_info(int sg_fd, int itype, void * resp, int max_resp_len,
775                      bool noisy, int verbose)
776 {
777     static const char * const cdb_name_s = "Report identifying information";
778     int k, res, ret, sense_cat;
779     unsigned char rii_cdb[MAINTENANCE_IN_CMDLEN] = {MAINTENANCE_IN_CMD,
780                         REPORT_IDENTIFYING_INFORMATION_SA,
781                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
782     unsigned char sense_b[SENSE_BUFF_LEN];
783     struct sg_pt_base * ptvp;
784 
785     sg_put_unaligned_be32((uint32_t)max_resp_len, rii_cdb + 6);
786     rii_cdb[10] |= (itype << 1) & 0xfe;
787 
788     if (verbose) {
789         pr2ws("    %s cdb: ", cdb_name_s);
790         for (k = 0; k < MAINTENANCE_IN_CMDLEN; ++k)
791             pr2ws("%02x ", rii_cdb[k]);
792         pr2ws("\n");
793     }
794 
795     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
796         return -1;
797     set_scsi_pt_cdb(ptvp, rii_cdb, sizeof(rii_cdb));
798     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
799     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, max_resp_len);
800     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
801     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, max_resp_len, sense_b,
802                                noisy, verbose, &sense_cat);
803     if (-1 == ret) {
804         int os_err = get_scsi_pt_os_err(ptvp);
805 
806         if ((os_err > 0) && (os_err < 47))
807             ret = SG_LIB_OS_BASE_ERR + os_err;
808     } else if (-2 == ret) {
809         switch (sense_cat) {
810         case SG_LIB_CAT_RECOVERED:
811         case SG_LIB_CAT_NO_SENSE:
812             ret = 0;
813             break;
814         default:
815             ret = sense_cat;
816             break;
817         }
818     } else {
819         if ((verbose > 2) && (ret > 0)) {
820             pr2ws("    %s: response", cdb_name_s);
821             if (3 == verbose) {
822                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
823                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
824                            -1);
825             } else {
826                 pr2ws(":\n");
827                 hex2stderr((const uint8_t *)resp, ret, 0);
828             }
829         }
830         ret = 0;
831     }
832     destruct_scsi_pt_obj(ptvp);
833     return ret;
834 }
835 
836 /* Invokes a SCSI SET IDENTIFYING INFORMATION command. This command was
837  * called SET DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success,
838  * various SG_LIB_CAT_* positive values or -1 -> other errors */
839 int
sg_ll_set_id_info(int sg_fd,int itype,void * paramp,int param_len,bool noisy,int verbose)840 sg_ll_set_id_info(int sg_fd, int itype, void * paramp, int param_len,
841                   bool noisy, int verbose)
842 {
843     static const char * const cdb_name_s = "Set identifying information";
844     int k, res, ret, sense_cat;
845     unsigned char sii_cdb[MAINTENANCE_OUT_CMDLEN] = {MAINTENANCE_OUT_CMD,
846                          SET_IDENTIFYING_INFORMATION_SA,
847                          0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
848     unsigned char sense_b[SENSE_BUFF_LEN];
849     struct sg_pt_base * ptvp;
850 
851     sg_put_unaligned_be32((uint32_t)param_len, sii_cdb + 6);
852     sii_cdb[10] |= (itype << 1) & 0xfe;
853     if (verbose) {
854         pr2ws("    %s cdb: ", cdb_name_s);
855         for (k = 0; k < MAINTENANCE_OUT_CMDLEN; ++k)
856             pr2ws("%02x ", sii_cdb[k]);
857         pr2ws("\n");
858         if ((verbose > 1) && paramp && param_len) {
859             pr2ws("    %s parameter list:\n", cdb_name_s);
860             hex2stderr((const uint8_t *)paramp, param_len, -1);
861         }
862     }
863 
864     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
865         return -1;
866     set_scsi_pt_cdb(ptvp, sii_cdb, sizeof(sii_cdb));
867     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
868     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
869     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
870     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
871                                noisy, verbose, &sense_cat);
872     if (-1 == ret) {
873         int os_err = get_scsi_pt_os_err(ptvp);
874 
875         if ((os_err > 0) && (os_err < 47))
876             ret = SG_LIB_OS_BASE_ERR + os_err;
877     } else if (-2 == ret) {
878         switch (sense_cat) {
879         case SG_LIB_CAT_RECOVERED:
880         case SG_LIB_CAT_NO_SENSE:
881             ret = 0;
882             break;
883         default:
884             ret = sense_cat;
885             break;
886         }
887     } else
888         ret = 0;
889 
890     destruct_scsi_pt_obj(ptvp);
891     return ret;
892 }
893 
894 /* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success,
895  * various SG_LIB_CAT_* positive values or -1 -> other errors */
896 int
sg_ll_format_unit(int sg_fd,int fmtpinfo,bool longlist,bool fmtdata,bool cmplst,int dlist_format,int timeout_secs,void * paramp,int param_len,bool noisy,int verbose)897 sg_ll_format_unit(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
898                   bool cmplst, int dlist_format, int timeout_secs,
899                   void * paramp, int param_len, bool noisy, int verbose)
900 {
901     return sg_ll_format_unit_v2(sg_fd, fmtpinfo, longlist, fmtdata, cmplst,
902                                 dlist_format, 0, timeout_secs, paramp,
903                                 param_len, noisy, verbose);
904 }
905 
906 /* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success,
907  * various SG_LIB_CAT_* positive values or -1 -> other errors */
908 int
sg_ll_format_unit2(int sg_fd,int fmtpinfo,bool longlist,bool fmtdata,bool cmplst,int dlist_format,int ffmt,int timeout_secs,void * paramp,int param_len,bool noisy,int verbose)909 sg_ll_format_unit2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
910                    bool cmplst, int dlist_format, int ffmt, int timeout_secs,
911                    void * paramp, int param_len, bool noisy, int verbose)
912 {
913     return sg_ll_format_unit_v2(sg_fd, fmtpinfo, longlist, fmtdata, cmplst,
914                                 dlist_format, ffmt, timeout_secs, paramp,
915                                 param_len, noisy, verbose);
916 }
917 
918 /* Invokes a FORMAT UNIT (SBC-4) command. Return of 0 -> success,
919  * various SG_LIB_CAT_* positive values or -1 -> other errors.
920  * FFMT field added in sbc4r10 [20160121] */
921 int
sg_ll_format_unit_v2(int sg_fd,int fmtpinfo,bool longlist,bool fmtdata,bool cmplst,int dlist_format,int ffmt,int timeout_secs,void * paramp,int param_len,bool noisy,int verbose)922 sg_ll_format_unit_v2(int sg_fd, int fmtpinfo, bool longlist, bool fmtdata,
923                      bool cmplst, int dlist_format, int ffmt,
924                      int timeout_secs, void * paramp, int param_len,
925                      bool noisy, int verbose)
926 {
927     static const char * const cdb_name_s = "Format unit";
928     int k, res, ret, sense_cat, tmout;
929     unsigned char fu_cdb[FORMAT_UNIT_CMDLEN] =
930                 {FORMAT_UNIT_CMD, 0, 0, 0, 0, 0};
931     unsigned char sense_b[SENSE_BUFF_LEN];
932     struct sg_pt_base * ptvp;
933 
934     if (fmtpinfo)
935         fu_cdb[1] |= (fmtpinfo << 6);
936     if (longlist)
937         fu_cdb[1] |= 0x20;
938     if (fmtdata)
939         fu_cdb[1] |= 0x10;
940     if (cmplst)
941         fu_cdb[1] |= 0x8;
942     if (dlist_format)
943         fu_cdb[1] |= (dlist_format & 0x7);
944     if (ffmt)
945         fu_cdb[4] |= (ffmt & 0x3);
946     tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
947     if (verbose) {
948         pr2ws("    %s cdb: ", cdb_name_s);
949         for (k = 0; k < 6; ++k)
950             pr2ws("%02x ", fu_cdb[k]);
951         pr2ws("\n");
952         if (verbose > 1) {
953             if (param_len > 0) {
954                 pr2ws("    %s parameter list:\n", cdb_name_s);
955                 hex2stderr((const uint8_t *)paramp, param_len, -1);
956             }
957             pr2ws("    %s timeout: %d seconds\n", cdb_name_s, tmout);
958         }
959     }
960 
961     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
962         return -1;
963     set_scsi_pt_cdb(ptvp, fu_cdb, sizeof(fu_cdb));
964     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
965     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
966     res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
967     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
968                                noisy, verbose, &sense_cat);
969     if (-1 == ret) {
970         int os_err = get_scsi_pt_os_err(ptvp);
971 
972         if ((os_err > 0) && (os_err < 47))
973             ret = SG_LIB_OS_BASE_ERR + os_err;
974     } else if (-2 == ret) {
975         switch (sense_cat) {
976         case SG_LIB_CAT_RECOVERED:
977         case SG_LIB_CAT_NO_SENSE:
978             ret = 0;
979             break;
980         default:
981             ret = sense_cat;
982             break;
983         }
984     } else
985         ret = 0;
986 
987     destruct_scsi_pt_obj(ptvp);
988     return ret;
989 }
990 
991 /* Invokes a SCSI REASSIGN BLOCKS command.  Return of 0 -> success,
992  * various SG_LIB_CAT_* positive values or -1 -> other errors */
993 int
sg_ll_reassign_blocks(int sg_fd,bool longlba,bool longlist,void * paramp,int param_len,bool noisy,int verbose)994 sg_ll_reassign_blocks(int sg_fd, bool longlba, bool longlist, void * paramp,
995                       int param_len, bool noisy, int verbose)
996 {
997     static const char * const cdb_name_s = "Reassign blocks";
998     int res, k, ret, sense_cat;
999     unsigned char reass_cdb[REASSIGN_BLKS_CMDLEN] =
1000         {REASSIGN_BLKS_CMD, 0, 0, 0, 0, 0};
1001     unsigned char sense_b[SENSE_BUFF_LEN];
1002     struct sg_pt_base * ptvp;
1003 
1004     if (longlba)
1005         reass_cdb[1] = 0x2;
1006     if (longlist)
1007         reass_cdb[1] |= 0x1;
1008     if (verbose) {
1009         pr2ws("    %s cdb: ", cdb_name_s);
1010         for (k = 0; k < REASSIGN_BLKS_CMDLEN; ++k)
1011             pr2ws("%02x ", reass_cdb[k]);
1012         pr2ws("\n");
1013     }
1014     if (verbose > 1) {
1015         pr2ws("    %s parameter list\n", cdb_name_s);
1016         hex2stderr((const uint8_t *)paramp, param_len, -1);
1017     }
1018 
1019     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1020         return -1;
1021     set_scsi_pt_cdb(ptvp, reass_cdb, sizeof(reass_cdb));
1022     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1023     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
1024     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1025     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1026                                noisy, verbose, &sense_cat);
1027     if (-1 == ret) {
1028         int os_err = get_scsi_pt_os_err(ptvp);
1029 
1030         if ((os_err > 0) && (os_err < 47))
1031             ret = SG_LIB_OS_BASE_ERR + os_err;
1032     } else if (-2 == ret) {
1033         switch (sense_cat) {
1034         case SG_LIB_CAT_RECOVERED:
1035         case SG_LIB_CAT_NO_SENSE:
1036             ret = 0;
1037             break;
1038         default:
1039             ret = sense_cat;
1040             break;
1041         }
1042     } else
1043         ret = 0;
1044 
1045     destruct_scsi_pt_obj(ptvp);
1046     return ret;
1047 }
1048 
1049 /* Invokes a SCSI PERSISTENT RESERVE IN command (SPC). Returns 0
1050  * when successful, various SG_LIB_CAT_* positive values or
1051  * -1 -> other errors */
1052 int
sg_ll_persistent_reserve_in(int sg_fd,int rq_servact,void * resp,int mx_resp_len,bool noisy,int verbose)1053 sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp,
1054                             int mx_resp_len, bool noisy, int verbose)
1055 {
1056     static const char * const cdb_name_s = "Persistent reservation in";
1057     int res, k, ret, sense_cat;
1058     unsigned char prin_cdb[PERSISTENT_RESERVE_IN_CMDLEN] =
1059                  {PERSISTENT_RESERVE_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1060     unsigned char sense_b[SENSE_BUFF_LEN];
1061     struct sg_pt_base * ptvp;
1062 
1063     if (rq_servact > 0)
1064         prin_cdb[1] = (unsigned char)(rq_servact & 0x1f);
1065     sg_put_unaligned_be16((uint16_t)mx_resp_len, prin_cdb + 7);
1066 
1067     if (verbose) {
1068         pr2ws("    %s cdb: ", cdb_name_s);
1069         for (k = 0; k < PERSISTENT_RESERVE_IN_CMDLEN; ++k)
1070             pr2ws("%02x ", prin_cdb[k]);
1071         pr2ws("\n");
1072     }
1073 
1074     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1075         return -1;
1076     set_scsi_pt_cdb(ptvp, prin_cdb, sizeof(prin_cdb));
1077     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1078     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
1079     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1080     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
1081                                noisy, verbose, &sense_cat);
1082     if (-1 == ret) {
1083         int os_err = get_scsi_pt_os_err(ptvp);
1084 
1085         if ((os_err > 0) && (os_err < 47))
1086             ret = SG_LIB_OS_BASE_ERR + os_err;
1087     } else if (-2 == ret) {
1088         switch (sense_cat) {
1089         case SG_LIB_CAT_RECOVERED:
1090         case SG_LIB_CAT_NO_SENSE:
1091             ret = 0;
1092             break;
1093         default:
1094             ret = sense_cat;
1095             break;
1096         }
1097     } else {
1098         if ((verbose > 2) && (ret > 0)) {
1099             pr2ws("    %s: response", cdb_name_s);
1100             if (3 == verbose) {
1101                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
1102                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
1103                            -1);
1104             } else {
1105                 pr2ws(":\n");
1106                 hex2stderr((const uint8_t *)resp, ret, 0);
1107             }
1108         }
1109         ret = 0;
1110     }
1111     destruct_scsi_pt_obj(ptvp);
1112     return ret;
1113 }
1114 
1115 /* Invokes a SCSI PERSISTENT RESERVE OUT command (SPC). Returns 0
1116  * when successful, various SG_LIB_CAT_* positive values or
1117  * -1 -> other errors */
1118 int
sg_ll_persistent_reserve_out(int sg_fd,int rq_servact,int rq_scope,unsigned int rq_type,void * paramp,int param_len,bool noisy,int verbose)1119 sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope,
1120                              unsigned int rq_type, void * paramp,
1121                              int param_len, bool noisy, int verbose)
1122 {
1123     static const char * const cdb_name_s = "Persistent reservation out";
1124     int res, k, ret, sense_cat;
1125     unsigned char prout_cdb[PERSISTENT_RESERVE_OUT_CMDLEN] =
1126                  {PERSISTENT_RESERVE_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1127     unsigned char sense_b[SENSE_BUFF_LEN];
1128     struct sg_pt_base * ptvp;
1129 
1130     if (rq_servact > 0)
1131         prout_cdb[1] = (unsigned char)(rq_servact & 0x1f);
1132     prout_cdb[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf));
1133     sg_put_unaligned_be16((uint16_t)param_len, prout_cdb + 7);
1134 
1135     if (verbose) {
1136         pr2ws("    %s cdb: ", cdb_name_s);
1137         for (k = 0; k < PERSISTENT_RESERVE_OUT_CMDLEN; ++k)
1138             pr2ws("%02x ", prout_cdb[k]);
1139         pr2ws("\n");
1140         if (verbose > 1) {
1141             pr2ws("    %s parameters:\n", cdb_name_s);
1142             hex2stderr((const uint8_t *)paramp, param_len, 0);
1143         }
1144     }
1145 
1146     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1147         return -1;
1148     set_scsi_pt_cdb(ptvp, prout_cdb, sizeof(prout_cdb));
1149     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1150     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
1151     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1152     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1153                                noisy, verbose, &sense_cat);
1154     if (-1 == ret) {
1155         int os_err = get_scsi_pt_os_err(ptvp);
1156 
1157         if ((os_err > 0) && (os_err < 47))
1158             ret = SG_LIB_OS_BASE_ERR + os_err;
1159     } else if (-2 == ret) {
1160         switch (sense_cat) {
1161         case SG_LIB_CAT_RECOVERED:
1162         case SG_LIB_CAT_NO_SENSE:
1163             ret = 0;
1164             break;
1165         default:
1166             ret = sense_cat;
1167             break;
1168         }
1169     } else
1170         ret = 0;
1171 
1172     destruct_scsi_pt_obj(ptvp);
1173     return ret;
1174 }
1175 
1176 static bool
has_blk_ili(unsigned char * sensep,int sb_len)1177 has_blk_ili(unsigned char * sensep, int sb_len)
1178 {
1179     int resp_code;
1180     const unsigned char * cup;
1181 
1182     if (sb_len < 8)
1183         return false;
1184     resp_code = (0x7f & sensep[0]);
1185     if (resp_code >= 0x72) { /* descriptor format */
1186         /* find block command descriptor */
1187         if ((cup = sg_scsi_sense_desc_find(sensep, sb_len, 0x5)))
1188             return (cup[3] & 0x20);
1189     } else /* fixed */
1190         return (sensep[2] & 0x20);
1191     return false;
1192 }
1193 
1194 /* Invokes a SCSI READ LONG (10) command (SBC). Note that 'xfer_len'
1195  * is in bytes. Returns 0 -> success,
1196  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1197 int
sg_ll_read_long10(int sg_fd,bool pblock,bool correct,unsigned int lba,void * resp,int xfer_len,int * offsetp,bool noisy,int verbose)1198 sg_ll_read_long10(int sg_fd, bool pblock, bool correct, unsigned int lba,
1199                   void * resp, int xfer_len, int * offsetp, bool noisy,
1200                   int verbose)
1201 {
1202     static const char * const cdb_name_s = "read long(10)";
1203     int k, res, sense_cat, ret;
1204     unsigned char readLong_cdb[READ_LONG10_CMDLEN];
1205     unsigned char sense_b[SENSE_BUFF_LEN];
1206     struct sg_pt_base * ptvp;
1207 
1208     memset(readLong_cdb, 0, READ_LONG10_CMDLEN);
1209     readLong_cdb[0] = READ_LONG10_CMD;
1210     if (pblock)
1211         readLong_cdb[1] |= 0x4;
1212     if (correct)
1213         readLong_cdb[1] |= 0x2;
1214 
1215     sg_put_unaligned_be32((uint32_t)lba, readLong_cdb + 2);
1216     sg_put_unaligned_be16((uint16_t)xfer_len, readLong_cdb + 7);
1217     if (verbose) {
1218         pr2ws("    %s cdb: ", cdb_name_s);
1219         for (k = 0; k < READ_LONG10_CMDLEN; ++k)
1220             pr2ws("%02x ", readLong_cdb[k]);
1221         pr2ws("\n");
1222     }
1223 
1224     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1225         return -1;
1226     set_scsi_pt_cdb(ptvp, readLong_cdb, sizeof(readLong_cdb));
1227     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1228     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len);
1229     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1230     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, xfer_len, sense_b,
1231                                noisy, verbose, &sense_cat);
1232     if (-1 == ret) {
1233         int os_err = get_scsi_pt_os_err(ptvp);
1234 
1235         if ((os_err > 0) && (os_err < 47))
1236             ret = SG_LIB_OS_BASE_ERR + os_err;
1237     } else if (-2 == ret) {
1238         switch (sense_cat) {
1239         case SG_LIB_CAT_RECOVERED:
1240         case SG_LIB_CAT_NO_SENSE:
1241             ret = 0;
1242             break;
1243         case SG_LIB_CAT_ILLEGAL_REQ:
1244             {
1245                 bool valid, ili;
1246                 int slen;
1247                 uint64_t ull = 0;
1248 
1249                 slen = get_scsi_pt_sense_len(ptvp);
1250                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1251                 ili = has_blk_ili(sense_b, slen);
1252                 if (valid && ili) {
1253                     if (offsetp)
1254                         *offsetp = (int)(int64_t)ull;
1255                     ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
1256                 } else {
1257                     if (verbose > 1)
1258                         pr2ws("  info field: 0x%" PRIx64 ",  valid: %d, "
1259                               "ili: %d\n", ull, valid, ili);
1260                     ret = SG_LIB_CAT_ILLEGAL_REQ;
1261                 }
1262             }
1263             break;
1264         default:
1265             ret = sense_cat;
1266             break;
1267         }
1268     } else {
1269         if ((verbose > 2) && (ret > 0)) {
1270             pr2ws("    %s: response", cdb_name_s);
1271             if (3 == verbose) {
1272                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
1273                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
1274                            -1);
1275             } else {
1276                 pr2ws(":\n");
1277                 hex2stderr((const uint8_t *)resp, ret, 0);
1278             }
1279         }
1280         ret = 0;
1281     }
1282     destruct_scsi_pt_obj(ptvp);
1283     return ret;
1284 }
1285 
1286 /* Invokes a SCSI READ LONG (16) command (SBC). Note that 'xfer_len'
1287  * is in bytes. Returns 0 -> success,
1288  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1289 int
sg_ll_read_long16(int sg_fd,bool pblock,bool correct,uint64_t llba,void * resp,int xfer_len,int * offsetp,bool noisy,int verbose)1290 sg_ll_read_long16(int sg_fd, bool pblock, bool correct, uint64_t llba,
1291                   void * resp, int xfer_len, int * offsetp, bool noisy,
1292                   int verbose)
1293 {
1294     static const char * const cdb_name_s = "read long(16)";
1295     int k, res, sense_cat, ret;
1296     unsigned char readLong_cdb[SERVICE_ACTION_IN_16_CMDLEN];
1297     unsigned char sense_b[SENSE_BUFF_LEN];
1298     struct sg_pt_base * ptvp;
1299 
1300     memset(readLong_cdb, 0, sizeof(readLong_cdb));
1301     readLong_cdb[0] = SERVICE_ACTION_IN_16_CMD;
1302     readLong_cdb[1] = READ_LONG_16_SA;
1303     if (pblock)
1304         readLong_cdb[14] |= 0x2;
1305     if (correct)
1306         readLong_cdb[14] |= 0x1;
1307 
1308     sg_put_unaligned_be64(llba, readLong_cdb + 2);
1309     sg_put_unaligned_be16((uint16_t)xfer_len, readLong_cdb + 12);
1310     if (verbose) {
1311         pr2ws("    %s cdb: ", cdb_name_s);
1312         for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k)
1313             pr2ws("%02x ", readLong_cdb[k]);
1314         pr2ws("\n");
1315     }
1316 
1317     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1318         return -1;
1319     set_scsi_pt_cdb(ptvp, readLong_cdb, sizeof(readLong_cdb));
1320     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1321     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len);
1322     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1323     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, xfer_len, sense_b,
1324                                noisy, verbose, &sense_cat);
1325     if (-1 == ret) {
1326         int os_err = get_scsi_pt_os_err(ptvp);
1327 
1328         if ((os_err > 0) && (os_err < 47))
1329             ret = SG_LIB_OS_BASE_ERR + os_err;
1330     } else if (-2 == ret) {
1331         switch (sense_cat) {
1332         case SG_LIB_CAT_RECOVERED:
1333         case SG_LIB_CAT_NO_SENSE:
1334             ret = 0;
1335             break;
1336         case SG_LIB_CAT_ILLEGAL_REQ:
1337             {
1338                 bool valid, ili;
1339                 int slen;
1340                 uint64_t ull = 0;
1341 
1342                 slen = get_scsi_pt_sense_len(ptvp);
1343                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1344                 ili = has_blk_ili(sense_b, slen);
1345                 if (valid && ili) {
1346                     if (offsetp)
1347                         *offsetp = (int)(int64_t)ull;
1348                     ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
1349                 } else {
1350                     if (verbose > 1)
1351                         pr2ws("  info field: 0x%" PRIx64 ",  valid: %d, "
1352                               "ili: %d\n", ull, (int)valid, (int)ili);
1353                     ret = SG_LIB_CAT_ILLEGAL_REQ;
1354                 }
1355             }
1356             break;
1357         default:
1358             ret = sense_cat;
1359             break;
1360         }
1361     } else {
1362         if ((verbose > 2) && (ret > 0)) {
1363             pr2ws("    %s: response", cdb_name_s);
1364             if (3 == verbose) {
1365                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
1366                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
1367                            -1);
1368             } else {
1369                 pr2ws(":\n");
1370                 hex2stderr((const uint8_t *)resp, ret, 0);
1371             }
1372         }
1373         ret = 0;
1374     }
1375     destruct_scsi_pt_obj(ptvp);
1376     return ret;
1377 }
1378 
1379 /* Invokes a SCSI WRITE LONG (10) command (SBC). Note that 'xfer_len'
1380  * is in bytes. Returns 0 -> success,
1381  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1382 int
sg_ll_write_long10(int sg_fd,bool cor_dis,bool wr_uncor,bool pblock,unsigned int lba,void * data_out,int xfer_len,int * offsetp,bool noisy,int verbose)1383 sg_ll_write_long10(int sg_fd, bool cor_dis, bool wr_uncor, bool pblock,
1384                    unsigned int lba, void * data_out, int xfer_len,
1385                    int * offsetp, bool noisy, int verbose)
1386 {
1387     static const char * const cdb_name_s = "write long(10)";
1388     int k, res, sense_cat, ret;
1389     unsigned char writeLong_cdb[WRITE_LONG10_CMDLEN];
1390     unsigned char sense_b[SENSE_BUFF_LEN];
1391     struct sg_pt_base * ptvp;
1392 
1393     memset(writeLong_cdb, 0, WRITE_LONG10_CMDLEN);
1394     writeLong_cdb[0] = WRITE_LONG10_CMD;
1395     if (cor_dis)
1396         writeLong_cdb[1] |= 0x80;
1397     if (wr_uncor)
1398         writeLong_cdb[1] |= 0x40;
1399     if (pblock)
1400         writeLong_cdb[1] |= 0x20;
1401 
1402     sg_put_unaligned_be32((uint32_t)lba, writeLong_cdb + 2);
1403     sg_put_unaligned_be16((uint16_t)xfer_len, writeLong_cdb + 7);
1404     if (verbose) {
1405         pr2ws("    %s cdb: ", cdb_name_s);
1406         for (k = 0; k < (int)sizeof(writeLong_cdb); ++k)
1407             pr2ws("%02x ", writeLong_cdb[k]);
1408         pr2ws("\n");
1409     }
1410 
1411     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1412         return -1;
1413     set_scsi_pt_cdb(ptvp, writeLong_cdb, sizeof(writeLong_cdb));
1414     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1415     set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len);
1416     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1417     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1418                                noisy, verbose, &sense_cat);
1419     if (-1 == ret)
1420         ;
1421     else if (-2 == ret) {
1422         switch (sense_cat) {
1423         case SG_LIB_CAT_RECOVERED:
1424         case SG_LIB_CAT_NO_SENSE:
1425             ret = 0;
1426             break;
1427         case SG_LIB_CAT_ILLEGAL_REQ:
1428             {
1429                 int valid, slen, ili;
1430                 uint64_t ull = 0;
1431 
1432                 slen = get_scsi_pt_sense_len(ptvp);
1433                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1434                 ili = has_blk_ili(sense_b, slen);
1435                 if (valid && ili) {
1436                     if (offsetp)
1437                         *offsetp = (int)(int64_t)ull;
1438                     ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
1439                 } else {
1440                     if (verbose > 1)
1441                         pr2ws("  info field: 0x%" PRIx64 ",  valid: %d, "
1442                               "ili: %d\n", ull, (int)valid, (int)ili);
1443                     ret = SG_LIB_CAT_ILLEGAL_REQ;
1444                 }
1445             }
1446             break;
1447         default:
1448             ret = sense_cat;
1449             break;
1450         }
1451     } else
1452         ret = 0;
1453 
1454     destruct_scsi_pt_obj(ptvp);
1455     return ret;
1456 }
1457 
1458 /* Invokes a SCSI WRITE LONG (16) command (SBC). Note that 'xfer_len'
1459  * is in bytes. Returns 0 -> success,
1460  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1461 int
sg_ll_write_long16(int sg_fd,bool cor_dis,bool wr_uncor,bool pblock,uint64_t llba,void * data_out,int xfer_len,int * offsetp,bool noisy,int verbose)1462 sg_ll_write_long16(int sg_fd, bool cor_dis, bool wr_uncor, bool pblock,
1463                    uint64_t llba, void * data_out, int xfer_len,
1464                    int * offsetp, bool noisy, int verbose)
1465 {
1466     static const char * const cdb_name_s = "write long(16)";
1467     int k, res, sense_cat, ret;
1468     unsigned char writeLong_cdb[SERVICE_ACTION_OUT_16_CMDLEN];
1469     unsigned char sense_b[SENSE_BUFF_LEN];
1470     struct sg_pt_base * ptvp;
1471 
1472     memset(writeLong_cdb, 0, sizeof(writeLong_cdb));
1473     writeLong_cdb[0] = SERVICE_ACTION_OUT_16_CMD;
1474     writeLong_cdb[1] = WRITE_LONG_16_SA;
1475     if (cor_dis)
1476         writeLong_cdb[1] |= 0x80;
1477     if (wr_uncor)
1478         writeLong_cdb[1] |= 0x40;
1479     if (pblock)
1480         writeLong_cdb[1] |= 0x20;
1481 
1482     sg_put_unaligned_be64(llba, writeLong_cdb + 2);
1483     sg_put_unaligned_be16((uint16_t)xfer_len, writeLong_cdb + 12);
1484     if (verbose) {
1485         pr2ws("    %s cdb: ", cdb_name_s);
1486         for (k = 0; k < SERVICE_ACTION_OUT_16_CMDLEN; ++k)
1487             pr2ws("%02x ", writeLong_cdb[k]);
1488         pr2ws("\n");
1489     }
1490 
1491     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1492         return -1;
1493     set_scsi_pt_cdb(ptvp, writeLong_cdb, sizeof(writeLong_cdb));
1494     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1495     set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len);
1496     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1497     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1498                                noisy, verbose, &sense_cat);
1499     if (-1 == ret) {
1500         int os_err = get_scsi_pt_os_err(ptvp);
1501 
1502         if ((os_err > 0) && (os_err < 47))
1503             ret = SG_LIB_OS_BASE_ERR + os_err;
1504     } else if (-2 == ret) {
1505         switch (sense_cat) {
1506         case SG_LIB_CAT_RECOVERED:
1507         case SG_LIB_CAT_NO_SENSE:
1508             ret = 0;
1509             break;
1510         case SG_LIB_CAT_ILLEGAL_REQ:
1511             {
1512                 bool valid, ili;
1513                 int slen;
1514                 uint64_t ull = 0;
1515 
1516                 slen = get_scsi_pt_sense_len(ptvp);
1517                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1518                 ili = has_blk_ili(sense_b, slen);
1519                 if (valid && ili) {
1520                     if (offsetp)
1521                         *offsetp = (int)(int64_t)ull;
1522                     ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO;
1523                 } else {
1524                     if (verbose > 1)
1525                         pr2ws("  info field: 0x%" PRIx64 ",  valid: %d, "
1526                               "ili: %d\n", ull, (int)valid, (int)ili);
1527                     ret = SG_LIB_CAT_ILLEGAL_REQ;
1528                 }
1529             }
1530             break;
1531         default:
1532             ret = sense_cat;
1533             break;
1534         }
1535     } else
1536         ret = 0;
1537 
1538     destruct_scsi_pt_obj(ptvp);
1539     return ret;
1540 }
1541 
1542 /* Invokes a SCSI VERIFY (10) command (SBC and MMC).
1543  * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes.
1544  * Returns of 0 -> success, * various SG_LIB_CAT_* positive values or
1545  * -1 -> other errors */
1546 int
sg_ll_verify10(int sg_fd,int vrprotect,bool dpo,int bytchk,unsigned int lba,int veri_len,void * data_out,int data_out_len,unsigned int * infop,bool noisy,int verbose)1547 sg_ll_verify10(int sg_fd, int vrprotect, bool dpo, int bytchk,
1548                unsigned int lba, int veri_len, void * data_out,
1549                int data_out_len, unsigned int * infop, bool noisy,
1550                int verbose)
1551 {
1552     static const char * const cdb_name_s = "verify(10)";
1553     int k, res, ret, sense_cat, slen;
1554     unsigned char v_cdb[VERIFY10_CMDLEN] =
1555                 {VERIFY10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1556     unsigned char sense_b[SENSE_BUFF_LEN];
1557     struct sg_pt_base * ptvp;
1558 
1559     /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */
1560     v_cdb[1] = (((vrprotect & 0x7) << 5) | ((bytchk & 0x3) << 1)) ;
1561     if (dpo)
1562         v_cdb[1] |= 0x10;
1563     sg_put_unaligned_be32((uint32_t)lba, v_cdb + 2);
1564     sg_put_unaligned_be16((uint16_t)veri_len, v_cdb + 7);
1565     if (verbose > 1) {
1566         pr2ws("    %s cdb: ", cdb_name_s);
1567         for (k = 0; k < VERIFY10_CMDLEN; ++k)
1568             pr2ws("%02x ", v_cdb[k]);
1569         pr2ws("\n");
1570         if ((verbose > 3) && bytchk && data_out && (data_out_len > 0)) {
1571             k = data_out_len > 4104 ? 4104 : data_out_len;
1572             pr2ws("    data_out buffer%s\n",
1573                   (data_out_len > 4104 ? ", first 4104 bytes" : ""));
1574             hex2stderr((const uint8_t *)data_out, k, verbose < 5);
1575         }
1576     }
1577     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1578         return -1;
1579     set_scsi_pt_cdb(ptvp, v_cdb, sizeof(v_cdb));
1580     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1581     if (data_out_len > 0)
1582         set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len);
1583     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1584     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1585                                noisy, verbose, &sense_cat);
1586     if (-1 == ret) {
1587         int os_err = get_scsi_pt_os_err(ptvp);
1588 
1589         if ((os_err > 0) && (os_err < 47))
1590             ret = SG_LIB_OS_BASE_ERR + os_err;
1591     } else if (-2 == ret) {
1592         switch (sense_cat) {
1593         case SG_LIB_CAT_RECOVERED:
1594         case SG_LIB_CAT_NO_SENSE:
1595             ret = 0;
1596             break;
1597         case SG_LIB_CAT_MEDIUM_HARD:
1598             {
1599                 bool valid;
1600                 uint64_t ull = 0;
1601 
1602                 slen = get_scsi_pt_sense_len(ptvp);
1603                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1604                 if (valid) {
1605                     if (infop)
1606                         *infop = (unsigned int)ull;
1607                     ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;
1608                 } else
1609                     ret = SG_LIB_CAT_MEDIUM_HARD;
1610             }
1611             break;
1612         default:
1613             ret = sense_cat;
1614             break;
1615         }
1616     } else
1617         ret = 0;
1618 
1619     destruct_scsi_pt_obj(ptvp);
1620     return ret;
1621 }
1622 
1623 /* Invokes a SCSI VERIFY (16) command (SBC and MMC).
1624  * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes.
1625  * Returns of 0 -> success,
1626  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1627 int
sg_ll_verify16(int sg_fd,int vrprotect,bool dpo,int bytchk,uint64_t llba,int veri_len,int group_num,void * data_out,int data_out_len,uint64_t * infop,bool noisy,int verbose)1628 sg_ll_verify16(int sg_fd, int vrprotect, bool dpo, int bytchk, uint64_t llba,
1629                int veri_len, int group_num, void * data_out,
1630                int data_out_len, uint64_t * infop, bool noisy, int verbose)
1631 {
1632     static const char * const cdb_name_s = "verify(16)";
1633     int k, res, ret, sense_cat, slen;
1634     unsigned char v_cdb[VERIFY16_CMDLEN] =
1635                 {VERIFY16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1636     unsigned char sense_b[SENSE_BUFF_LEN];
1637     struct sg_pt_base * ptvp;
1638 
1639     /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */
1640     v_cdb[1] = (((vrprotect & 0x7) << 5) | ((bytchk & 0x3) << 1)) ;
1641     if (dpo)
1642         v_cdb[1] |= 0x10;
1643     sg_put_unaligned_be64(llba, v_cdb + 2);
1644     sg_put_unaligned_be32((uint32_t)veri_len, v_cdb + 10);
1645     v_cdb[14] = group_num & 0x1f;
1646     if (verbose > 1) {
1647         pr2ws("    %s cdb: ", cdb_name_s);
1648         for (k = 0; k < VERIFY16_CMDLEN; ++k)
1649             pr2ws("%02x ", v_cdb[k]);
1650         pr2ws("\n");
1651         if ((verbose > 3) && bytchk && data_out && (data_out_len > 0)) {
1652             k = data_out_len > 4104 ? 4104 : data_out_len;
1653             pr2ws("    data_out buffer%s\n",
1654                   (data_out_len > 4104 ? ", first 4104 bytes" : ""));
1655             hex2stderr((const uint8_t *)data_out, k, verbose < 5);
1656         }
1657     }
1658     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1659         return -1;
1660     set_scsi_pt_cdb(ptvp, v_cdb, sizeof(v_cdb));
1661     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1662     if (data_out_len > 0)
1663         set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len);
1664     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1665     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1666                                noisy, verbose, &sense_cat);
1667     if (-1 == ret) {
1668         int os_err = get_scsi_pt_os_err(ptvp);
1669 
1670         if ((os_err > 0) && (os_err < 47))
1671             ret = SG_LIB_OS_BASE_ERR + os_err;
1672     } else if (-2 == ret) {
1673         switch (sense_cat) {
1674         case SG_LIB_CAT_RECOVERED:
1675         case SG_LIB_CAT_NO_SENSE:
1676             ret = 0;
1677             break;
1678         case SG_LIB_CAT_MEDIUM_HARD:
1679             {
1680                 bool valid;
1681                 uint64_t ull = 0;
1682 
1683                 slen = get_scsi_pt_sense_len(ptvp);
1684                 valid = sg_get_sense_info_fld(sense_b, slen, &ull);
1685                 if (valid) {
1686                     if (infop)
1687                         *infop = ull;
1688                     ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;
1689                 } else
1690                     ret = SG_LIB_CAT_MEDIUM_HARD;
1691             }
1692             break;
1693         default:
1694             ret = sense_cat;
1695             break;
1696         }
1697     } else
1698         ret = 0;
1699 
1700     destruct_scsi_pt_obj(ptvp);
1701     return ret;
1702 }
1703 
1704 /* Invokes a ATA PASS-THROUGH (12, 16 or 32) SCSI command (SAT). This is
1705  * selected by the cdb_len argument that can take values of 12, 16 or 32
1706  * only (else -1 is returned). The byte at offset 0 (and bytes 0 to 9
1707  * inclusive for ATA PT(32)) pointed to be cdbp are ignored and apart from
1708  * the control byte, the rest is copied into an internal cdb which is then
1709  * sent to the device. The control byte is byte 11 for ATA PT(12), byte 15
1710  * for ATA PT(16) and byte 1 for ATA PT(32). If timeout_secs <= 0 then the
1711  * timeout is set to 60 seconds. For data in or out transfers set dinp or
1712  * doutp, and dlen to the number of bytes to transfer. If dlen is zero then
1713  * no data transfer is assumed. If sense buffer obtained then it is written
1714  * to sensep, else sensep[0] is set to 0x0. If ATA return descriptor is
1715  * obtained then written to ata_return_dp, else ata_return_dp[0] is set to
1716  * 0x0. Either sensep or ata_return_dp (or both) may be NULL pointers.
1717  * Returns SCSI status value (>= 0) or -1 if other error. Users are
1718  * expected to check the sense buffer themselves. If available the data in
1719  * resid is written to residp. Note in SAT-2 and later, fixed format sense
1720  * data may be placed in *sensep in which case sensep[0]==0x70, prior to
1721  * SAT-2 descriptor sense format was required (i.e. sensep[0]==0x72).
1722  */
1723 int
sg_ll_ata_pt(int sg_fd,const unsigned char * cdbp,int cdb_len,int timeout_secs,void * dinp,void * doutp,int dlen,unsigned char * sensep,int max_sense_len,unsigned char * ata_return_dp,int max_ata_return_len,int * residp,int verbose)1724 sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len,
1725              int timeout_secs, void * dinp, void * doutp, int dlen,
1726              unsigned char * sensep, int max_sense_len,
1727              unsigned char * ata_return_dp, int max_ata_return_len,
1728              int * residp, int verbose)
1729 {
1730     int k, res, slen, duration;
1731     int ret = -1;
1732     unsigned char apt_cdb[ATA_PT_32_CMDLEN];
1733     unsigned char sense_b[SENSE_BUFF_LEN];
1734     unsigned char * sp;
1735     const unsigned char * bp;
1736     struct sg_pt_base * ptvp;
1737     const char * cnamep;
1738     char b[256];
1739 
1740     memset(apt_cdb, 0, sizeof(apt_cdb));
1741     b[0] = '\0';
1742     switch (cdb_len) {
1743     case 12:
1744         cnamep = "ATA pass-through(12)";
1745         apt_cdb[0] = ATA_PT_12_CMD;
1746         memcpy(apt_cdb + 1, cdbp + 1,  10);
1747         /* control byte at cdb[11] left at zero */
1748         break;
1749     case 16:
1750         cnamep = "ATA pass-through(16)";
1751         apt_cdb[0] = ATA_PT_16_CMD;
1752         memcpy(apt_cdb + 1, cdbp + 1,  14);
1753         /* control byte at cdb[15] left at zero */
1754         break;
1755     case 32:
1756         cnamep = "ATA pass-through(32)";
1757         apt_cdb[0] = SG_VARIABLE_LENGTH_CMD;
1758         /* control byte at cdb[1] left at zero */
1759         apt_cdb[7] = 0x18;    /* length starting at next byte */
1760         sg_put_unaligned_be16(ATA_PT_32_SA, apt_cdb + 8);
1761         memcpy(apt_cdb + 10, cdbp + 10,  32 - 10);
1762         break;
1763     default:
1764         pr2ws("cdb_len must be 12, 16 or 32\n");
1765         return -1;
1766     }
1767     if (NULL == cdbp) {
1768         if (verbose)
1769             pr2ws("%s NULL cdb pointer\n", cnamep);
1770         return -1;
1771     }
1772     if (sensep && (max_sense_len >= (int)sizeof(sense_b))) {
1773         sp = sensep;
1774         slen = max_sense_len;
1775     } else {
1776         sp = sense_b;
1777         slen = sizeof(sense_b);
1778     }
1779     if (verbose) {
1780         pr2ws("    %s cdb: ", cnamep);
1781         if (cdb_len < 32) {
1782             for (k = 0; k < cdb_len; ++k)
1783                 pr2ws("%02x ", apt_cdb[k]);
1784             pr2ws("\n");
1785         } else {
1786             pr2ws("\n");
1787             hex2stderr(apt_cdb, cdb_len, -1);
1788         }
1789     }
1790     if (NULL == ((ptvp = create_pt_obj(cnamep))))
1791         return -1;
1792     set_scsi_pt_cdb(ptvp, apt_cdb, cdb_len);
1793     set_scsi_pt_sense(ptvp, sp, slen);
1794     if (dlen > 0) {
1795         if (dinp)
1796             set_scsi_pt_data_in(ptvp, (unsigned char *)dinp, dlen);
1797         else if (doutp)
1798             set_scsi_pt_data_out(ptvp, (unsigned char *)doutp, dlen);
1799     }
1800     res = do_scsi_pt(ptvp, sg_fd,
1801                      ((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT),
1802                      verbose);
1803     if (SCSI_PT_DO_BAD_PARAMS == res) {
1804         if (verbose)
1805             pr2ws("%s: bad parameters\n", cnamep);
1806         goto out;
1807     } else if (SCSI_PT_DO_TIMEOUT == res) {
1808         if (verbose)
1809             pr2ws("%s: timeout\n", cnamep);
1810         goto out;
1811     } else if (res > 2) {
1812         if (verbose)
1813             pr2ws("%s: do_scsi_pt: errno=%d\n", cnamep, -res);
1814     }
1815 
1816     if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
1817         pr2ws("      duration=%d ms\n", duration);
1818 
1819     switch (get_scsi_pt_result_category(ptvp)) {
1820     case SCSI_PT_RESULT_GOOD:
1821         if ((sensep) && (max_sense_len > 0))
1822             *sensep = 0;
1823         if ((ata_return_dp) && (max_ata_return_len > 0))
1824             *ata_return_dp = 0;
1825         if (residp && (dlen > 0))
1826             *residp = get_scsi_pt_resid(ptvp);
1827         ret = 0;
1828         break;
1829     case SCSI_PT_RESULT_STATUS: /* other than GOOD + CHECK CONDITION */
1830         if ((sensep) && (max_sense_len > 0))
1831             *sensep = 0;
1832         if ((ata_return_dp) && (max_ata_return_len > 0))
1833             *ata_return_dp = 0;
1834         ret = get_scsi_pt_status_response(ptvp);
1835         break;
1836     case SCSI_PT_RESULT_SENSE:
1837         if (sensep && (sp != sensep)) {
1838             k = get_scsi_pt_sense_len(ptvp);
1839             k = (k > max_sense_len) ? max_sense_len : k;
1840             memcpy(sensep, sp, k);
1841         }
1842         if (ata_return_dp && (max_ata_return_len > 0))  {
1843             /* search for ATA return descriptor */
1844             bp = sg_scsi_sense_desc_find(sp, slen, 0x9);
1845             if (bp) {
1846                 k = bp[1] + 2;
1847                 k = (k > max_ata_return_len) ? max_ata_return_len : k;
1848                 memcpy(ata_return_dp, bp, k);
1849             } else
1850                 ata_return_dp[0] = 0x0;
1851         }
1852         if (residp && (dlen > 0))
1853             *residp = get_scsi_pt_resid(ptvp);
1854         ret = get_scsi_pt_status_response(ptvp);
1855         break;
1856     case SCSI_PT_RESULT_TRANSPORT_ERR:
1857         if (verbose)
1858             pr2ws("%s: transport error: %s\n", cnamep,
1859                   get_scsi_pt_transport_err_str(ptvp, sizeof(b), b));
1860         break;
1861     case SCSI_PT_RESULT_OS_ERR:
1862         if (verbose)
1863             pr2ws("%s: os error: %s\n", cnamep,
1864                   get_scsi_pt_os_err_str(ptvp, sizeof(b) , b));
1865         break;
1866     default:
1867         if (verbose)
1868             pr2ws("%s: unknown pt_result_category=%d\n", cnamep,
1869                   get_scsi_pt_result_category(ptvp));
1870         break;
1871     }
1872 
1873 out:
1874     destruct_scsi_pt_obj(ptvp);
1875     return ret;
1876 }
1877 
1878 /* Invokes a SCSI READ BUFFER(10) command (SPC). Return of 0 -> success
1879  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1880 int
sg_ll_read_buffer(int sg_fd,int mode,int buffer_id,int buffer_offset,void * resp,int mx_resp_len,bool noisy,int verbose)1881 sg_ll_read_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
1882                   void * resp, int mx_resp_len, bool noisy, int verbose)
1883 {
1884     static const char * const cdb_name_s = "read buffer(10)";
1885     int res, k, ret, sense_cat;
1886     unsigned char rbuf_cdb[READ_BUFFER_CMDLEN] =
1887         {READ_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1888     unsigned char sense_b[SENSE_BUFF_LEN];
1889     struct sg_pt_base * ptvp;
1890 
1891     rbuf_cdb[1] = (unsigned char)(mode & 0x1f);
1892     rbuf_cdb[2] = (unsigned char)(buffer_id & 0xff);
1893     sg_put_unaligned_be24((uint32_t)buffer_offset, rbuf_cdb + 3);
1894     sg_put_unaligned_be24((uint32_t)mx_resp_len, rbuf_cdb + 6);
1895     if (verbose) {
1896         pr2ws("    %s cdb: ", cdb_name_s);
1897         for (k = 0; k < READ_BUFFER_CMDLEN; ++k)
1898             pr2ws("%02x ", rbuf_cdb[k]);
1899         pr2ws("\n");
1900     }
1901 
1902     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1903         return -1;
1904     set_scsi_pt_cdb(ptvp, rbuf_cdb, sizeof(rbuf_cdb));
1905     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1906     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
1907     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1908     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
1909                                noisy, verbose, &sense_cat);
1910     if (-1 == ret) {
1911         int os_err = get_scsi_pt_os_err(ptvp);
1912 
1913         if ((os_err > 0) && (os_err < 47))
1914             ret = SG_LIB_OS_BASE_ERR + os_err;
1915     } else if (-2 == ret) {
1916         switch (sense_cat) {
1917         case SG_LIB_CAT_RECOVERED:
1918         case SG_LIB_CAT_NO_SENSE:
1919             ret = 0;
1920             break;
1921         default:
1922             ret = sense_cat;
1923             break;
1924         }
1925     } else {
1926         if ((verbose > 2) && (ret > 0)) {
1927             pr2ws("    %s: response", cdb_name_s);
1928             if (3 == verbose) {
1929                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
1930                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
1931                            -1);
1932             } else {
1933                 pr2ws(":\n");
1934                 hex2stderr((const uint8_t *)resp, ret, 0);
1935             }
1936         }
1937         ret = 0;
1938     }
1939     destruct_scsi_pt_obj(ptvp);
1940     return ret;
1941 }
1942 
1943 /* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 -> success
1944  * various SG_LIB_CAT_* positive values or -1 -> other errors */
1945 int
sg_ll_write_buffer(int sg_fd,int mode,int buffer_id,int buffer_offset,void * paramp,int param_len,bool noisy,int verbose)1946 sg_ll_write_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset,
1947                    void * paramp, int param_len, bool noisy, int verbose)
1948 {
1949     static const char * const cdb_name_s = "write buffer";
1950     int k, res, ret, sense_cat;
1951     unsigned char wbuf_cdb[WRITE_BUFFER_CMDLEN] =
1952         {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1953     unsigned char sense_b[SENSE_BUFF_LEN];
1954     struct sg_pt_base * ptvp;
1955 
1956     wbuf_cdb[1] = (unsigned char)(mode & 0x1f);
1957     wbuf_cdb[2] = (unsigned char)(buffer_id & 0xff);
1958     sg_put_unaligned_be24((uint32_t)buffer_offset, wbuf_cdb + 3);
1959     sg_put_unaligned_be24((uint32_t)param_len, wbuf_cdb + 6);
1960     if (verbose) {
1961         pr2ws("    %s cdb: ", cdb_name_s);
1962         for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k)
1963             pr2ws("%02x ", wbuf_cdb[k]);
1964         pr2ws("\n");
1965         if ((verbose > 1) && paramp && param_len) {
1966             pr2ws("    %s parameter list", cdb_name_s);
1967             if (2 == verbose) {
1968                 pr2ws("%s:\n", (param_len > 256 ? ", first 256 bytes" : ""));
1969                 hex2stderr((const uint8_t *)paramp,
1970                            (param_len > 256 ? 256 : param_len), -1);
1971             } else {
1972                 pr2ws(":\n");
1973                 hex2stderr((const uint8_t *)paramp, param_len, 0);
1974             }
1975         }
1976     }
1977 
1978     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
1979         return -1;
1980     set_scsi_pt_cdb(ptvp, wbuf_cdb, sizeof(wbuf_cdb));
1981     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1982     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
1983     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1984     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
1985                                noisy, verbose, &sense_cat);
1986     if (-1 == ret) {
1987         int os_err = get_scsi_pt_os_err(ptvp);
1988 
1989         if ((os_err > 0) && (os_err < 47))
1990             ret = SG_LIB_OS_BASE_ERR + os_err;
1991     } else if (-2 == ret) {
1992         switch (sense_cat) {
1993         case SG_LIB_CAT_RECOVERED:
1994         case SG_LIB_CAT_NO_SENSE:
1995             ret = 0;
1996             break;
1997         default:
1998             ret = sense_cat;
1999             break;
2000         }
2001     } else
2002         ret = 0;
2003 
2004     destruct_scsi_pt_obj(ptvp);
2005     return ret;
2006 }
2007 
2008 /* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 ->
2009  * success, SG_LIB_CAT_INVALID_OP -> invalid opcode,
2010  * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION,
2011  * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND,
2012  * -1 -> other failure. Adds mode specific field (spc4r32) and timeout
2013  *  to command abort to override default of 60 seconds. If timeout_secs is
2014  *  0 or less then the default timeout is used instead. */
2015 int
sg_ll_write_buffer_v2(int sg_fd,int mode,int m_specific,int buffer_id,uint32_t buffer_offset,void * paramp,uint32_t param_len,int timeout_secs,bool noisy,int verbose)2016 sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id,
2017                       uint32_t buffer_offset, void * paramp,
2018                       uint32_t param_len, int timeout_secs, bool noisy,
2019                       int verbose)
2020 {
2021     int k, res, ret, sense_cat;
2022     uint8_t wbuf_cdb[WRITE_BUFFER_CMDLEN] =
2023         {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2024     uint8_t sense_b[SENSE_BUFF_LEN];
2025     struct sg_pt_base * ptvp;
2026 
2027     if (buffer_offset > 0xffffff) {
2028         pr2ws("%s: buffer_offset value too large for 24 bits\n", __func__);
2029         return -1;
2030     }
2031     if (param_len > 0xffffff) {
2032         pr2ws("%s: param_len value too large for 24 bits\n", __func__);
2033         return -1;
2034     }
2035     wbuf_cdb[1] = (uint8_t)(mode & 0x1f);
2036     wbuf_cdb[1] |= (uint8_t)((m_specific & 0x7) << 5);
2037     wbuf_cdb[2] = (uint8_t)(buffer_id & 0xff);
2038     sg_put_unaligned_be24(buffer_offset, wbuf_cdb + 3);
2039     sg_put_unaligned_be24(param_len, wbuf_cdb + 6);
2040     if (verbose) {
2041         pr2ws("    Write buffer cdb: ");
2042         for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k)
2043             pr2ws("%02x ", wbuf_cdb[k]);
2044         pr2ws("\n");
2045         if ((verbose > 1) && paramp && param_len) {
2046             pr2ws("    Write buffer parameter list%s:\n",
2047                   ((param_len > 256) ? " (first 256 bytes)" : ""));
2048             hex2stderr((const uint8_t *)paramp,
2049                        ((param_len > 256) ? 256 : param_len), -1);
2050         }
2051     }
2052     if (timeout_secs <= 0)
2053         timeout_secs = DEF_PT_TIMEOUT;
2054 
2055     ptvp = construct_scsi_pt_obj();
2056     if (NULL == ptvp) {
2057         pr2ws("%s: out of memory\n", __func__);
2058         return -1;
2059     }
2060     set_scsi_pt_cdb(ptvp, wbuf_cdb, sizeof(wbuf_cdb));
2061     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2062     set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len);
2063     res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
2064     ret = sg_cmds_process_resp(ptvp, "Write buffer", res, SG_NO_DATA_IN,
2065                                sense_b, noisy, verbose, &sense_cat);
2066     if (-1 == ret) {
2067         int os_err = get_scsi_pt_os_err(ptvp);
2068 
2069         if ((os_err > 0) && (os_err < 47))
2070             ret = SG_LIB_OS_BASE_ERR + os_err;
2071     } else if (-2 == ret) {
2072         switch (sense_cat) {
2073         case SG_LIB_CAT_RECOVERED:
2074         case SG_LIB_CAT_NO_SENSE:
2075             ret = 0;
2076             break;
2077         default:
2078             ret = sense_cat;
2079             break;
2080         }
2081     } else
2082         ret = 0;
2083 
2084     destruct_scsi_pt_obj(ptvp);
2085     return ret;
2086 }
2087 
2088 /* Invokes a SCSI UNMAP command. Return of 0 -> success,
2089  * various SG_LIB_CAT_* positive values or -1 -> other errors */
2090 int
sg_ll_unmap(int sg_fd,int group_num,int timeout_secs,void * paramp,int param_len,bool noisy,int verbose)2091 sg_ll_unmap(int sg_fd, int group_num, int timeout_secs, void * paramp,
2092             int param_len, bool noisy, int verbose)
2093 {
2094     return sg_ll_unmap_v2(sg_fd, false, group_num, timeout_secs, paramp,
2095                           param_len, noisy, verbose);
2096 }
2097 
2098 /* Invokes a SCSI UNMAP (SBC-3) command. Version 2 adds anchor field
2099  * (sbc3r22). Otherwise same as sg_ll_unmap() . */
2100 int
sg_ll_unmap_v2(int sg_fd,bool anchor,int group_num,int timeout_secs,void * paramp,int param_len,bool noisy,int verbose)2101 sg_ll_unmap_v2(int sg_fd, bool anchor, int group_num, int timeout_secs,
2102                void * paramp, int param_len, bool noisy, int verbose)
2103 {
2104     static const char * const cdb_name_s = "unmap";
2105     int k, res, ret, sense_cat, tmout;
2106     unsigned char u_cdb[UNMAP_CMDLEN] =
2107                          {UNMAP_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2108     unsigned char sense_b[SENSE_BUFF_LEN];
2109     struct sg_pt_base * ptvp;
2110 
2111     if (anchor)
2112         u_cdb[1] |= 0x1;
2113     tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
2114     u_cdb[6] = group_num & 0x1f;
2115     sg_put_unaligned_be16((uint16_t)param_len, u_cdb + 7);
2116     if (verbose) {
2117         pr2ws("    %s cdb: ", cdb_name_s);
2118         for (k = 0; k < UNMAP_CMDLEN; ++k)
2119             pr2ws("%02x ", u_cdb[k]);
2120         pr2ws("\n");
2121         if ((verbose > 1) && paramp && param_len) {
2122             pr2ws("    %s parameter list:\n", cdb_name_s);
2123             hex2stderr((const uint8_t *)paramp, param_len, -1);
2124         }
2125     }
2126 
2127     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
2128         return -1;
2129     set_scsi_pt_cdb(ptvp, u_cdb, sizeof(u_cdb));
2130     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2131     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
2132     res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
2133     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
2134                                noisy, verbose, &sense_cat);
2135     if (-1 == ret) {
2136         int os_err = get_scsi_pt_os_err(ptvp);
2137 
2138         if ((os_err > 0) && (os_err < 47))
2139             ret = SG_LIB_OS_BASE_ERR + os_err;
2140     } else if (-2 == ret) {
2141         switch (sense_cat) {
2142         case SG_LIB_CAT_RECOVERED:
2143         case SG_LIB_CAT_NO_SENSE:
2144             ret = 0;
2145             break;
2146         default:
2147             ret = sense_cat;
2148             break;
2149         }
2150     } else
2151         ret = 0;
2152     destruct_scsi_pt_obj(ptvp);
2153     return ret;
2154 }
2155 
2156 /* Invokes a SCSI READ BLOCK LIMITS command. Return of 0 -> success,
2157  * various SG_LIB_CAT_* positive values or -1 -> other errors */
2158 int
sg_ll_read_block_limits(int sg_fd,void * resp,int mx_resp_len,bool noisy,int verbose)2159 sg_ll_read_block_limits(int sg_fd, void * resp, int mx_resp_len,
2160                         bool noisy, int verbose)
2161 {
2162     static const char * const cdb_name_s = "read block limits";
2163     int k, ret, res, sense_cat;
2164     unsigned char rl_cdb[READ_BLOCK_LIMITS_CMDLEN] =
2165       {READ_BLOCK_LIMITS_CMD, 0, 0, 0, 0, 0};
2166     unsigned char sense_b[SENSE_BUFF_LEN];
2167     struct sg_pt_base * ptvp;
2168 
2169     if (verbose) {
2170         pr2ws("    %s cdb: ", cdb_name_s);
2171         for (k = 0; k < READ_BLOCK_LIMITS_CMDLEN; ++k)
2172             pr2ws("%02x ", rl_cdb[k]);
2173         pr2ws("\n");
2174     }
2175 
2176     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
2177         return -1;
2178     set_scsi_pt_cdb(ptvp, rl_cdb, sizeof(rl_cdb));
2179     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2180     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
2181     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
2182     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, mx_resp_len, sense_b,
2183                                noisy, verbose, &sense_cat);
2184     if (-1 == ret) {
2185         int os_err = get_scsi_pt_os_err(ptvp);
2186 
2187         if ((os_err > 0) && (os_err < 47))
2188             ret = SG_LIB_OS_BASE_ERR + os_err;
2189     } else if (-2 == ret) {
2190         switch (sense_cat) {
2191         case SG_LIB_CAT_RECOVERED:
2192         case SG_LIB_CAT_NO_SENSE:
2193             ret = 0;
2194             break;
2195         default:
2196             ret = sense_cat;
2197             break;
2198         }
2199     } else {
2200         if ((verbose > 2) && (ret > 0)) {
2201             pr2ws("    %s: response", cdb_name_s);
2202             if (3 == verbose) {
2203                 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
2204                 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
2205                            -1);
2206             } else {
2207                 pr2ws(":\n");
2208                 hex2stderr((const uint8_t *)resp, ret, 0);
2209             }
2210         }
2211         ret = 0;
2212     }
2213     destruct_scsi_pt_obj(ptvp);
2214     return ret;
2215 }
2216 
2217 /* Invokes a SCSI RECEIVE COPY RESULTS command. Actually cover all current
2218  * uses of opcode 0x84 (Third-party copy IN). Return of 0 -> success,
2219  * various SG_LIB_CAT_* positive values or -1 -> other errors */
2220 int
sg_ll_receive_copy_results(int sg_fd,int sa,int list_id,void * resp,int mx_resp_len,bool noisy,int verbose)2221 sg_ll_receive_copy_results(int sg_fd, int sa, int list_id, void * resp,
2222                            int mx_resp_len, bool noisy, int verbose)
2223 {
2224     int k, res, ret, sense_cat;
2225     unsigned char rcvcopyres_cdb[THIRD_PARTY_COPY_IN_CMDLEN] =
2226       {THIRD_PARTY_COPY_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2227     unsigned char sense_b[SENSE_BUFF_LEN];
2228     struct sg_pt_base * ptvp;
2229     char b[64];
2230 
2231     sg_get_opcode_sa_name(THIRD_PARTY_COPY_IN_CMD, sa, 0, (int)sizeof(b), b);
2232     rcvcopyres_cdb[1] = (unsigned char)(sa & 0x1f);
2233     if (sa <= 4)        /* LID1 variants */
2234         rcvcopyres_cdb[2] = (unsigned char)(list_id);
2235     else if ((sa >= 5) && (sa <= 7))    /* LID4 variants */
2236         sg_put_unaligned_be32((uint32_t)list_id, rcvcopyres_cdb + 2);
2237     sg_put_unaligned_be32((uint32_t)mx_resp_len, rcvcopyres_cdb + 10);
2238 
2239     if (verbose) {
2240         pr2ws("    %s cdb: ", b);
2241         for (k = 0; k < THIRD_PARTY_COPY_IN_CMDLEN; ++k)
2242             pr2ws("%02x ", rcvcopyres_cdb[k]);
2243         pr2ws("\n");
2244     }
2245 
2246     if (NULL == ((ptvp = create_pt_obj(b))))
2247         return -1;
2248     set_scsi_pt_cdb(ptvp, rcvcopyres_cdb, sizeof(rcvcopyres_cdb));
2249     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2250     set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len);
2251     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
2252     ret = sg_cmds_process_resp(ptvp, b, res, mx_resp_len, sense_b, noisy,
2253                                verbose, &sense_cat);
2254     if (-1 == ret) {
2255         int os_err = get_scsi_pt_os_err(ptvp);
2256 
2257         if ((os_err > 0) && (os_err < 47))
2258             ret = SG_LIB_OS_BASE_ERR + os_err;
2259     } else if (-2 == ret) {
2260         switch (sense_cat) {
2261         case SG_LIB_CAT_RECOVERED:
2262         case SG_LIB_CAT_NO_SENSE:
2263             ret = 0;
2264             break;
2265         default:
2266             ret = sense_cat;
2267             break;
2268         }
2269     } else
2270         ret = 0;
2271     destruct_scsi_pt_obj(ptvp);
2272     return ret;
2273 }
2274 
2275 
2276 /* SPC-4 rev 35 and later calls this opcode (0x83) "Third-party copy OUT"
2277  * The original EXTENDED COPY command (now called EXTENDED COPY (LID1))
2278  * is the only one supported by sg_ll_extended_copy(). See function
2279  * sg_ll_3party_copy_out() for the other service actions ( > 0 ). */
2280 
2281 /* Invokes a SCSI EXTENDED COPY (LID1) command. Return of 0 -> success,
2282  * various SG_LIB_CAT_* positive values or -1 -> other errors */
2283 int
sg_ll_extended_copy(int sg_fd,void * paramp,int param_len,bool noisy,int verbose)2284 sg_ll_extended_copy(int sg_fd, void * paramp, int param_len, bool noisy,
2285                     int verbose)
2286 {
2287     int k, res, ret, sense_cat;
2288     unsigned char xcopy_cdb[THIRD_PARTY_COPY_OUT_CMDLEN] =
2289       {THIRD_PARTY_COPY_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2290     unsigned char sense_b[SENSE_BUFF_LEN];
2291     struct sg_pt_base * ptvp;
2292     const char * opcode_name = "Extended copy (LID1)";
2293 
2294     xcopy_cdb[1] = (unsigned char)(EXTENDED_COPY_LID1_SA & 0x1f);
2295     sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10);
2296 
2297     if (verbose) {
2298         pr2ws("    %s cdb: ", opcode_name);
2299         for (k = 0; k < THIRD_PARTY_COPY_OUT_CMDLEN; ++k)
2300             pr2ws("%02x ", xcopy_cdb[k]);
2301         pr2ws("\n");
2302         if ((verbose > 1) && paramp && param_len) {
2303             pr2ws("    %s parameter list:\n", opcode_name);
2304             hex2stderr((const uint8_t *)paramp, param_len, -1);
2305         }
2306     }
2307 
2308     if (NULL == ((ptvp = create_pt_obj(opcode_name))))
2309         return -1;
2310     set_scsi_pt_cdb(ptvp, xcopy_cdb, sizeof(xcopy_cdb));
2311     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2312     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
2313     res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
2314     ret = sg_cmds_process_resp(ptvp, opcode_name, res, SG_NO_DATA_IN, sense_b,
2315                                noisy, verbose, &sense_cat);
2316     if (-1 == ret) {
2317         int os_err = get_scsi_pt_os_err(ptvp);
2318 
2319         if ((os_err > 0) && (os_err < 47))
2320             ret = SG_LIB_OS_BASE_ERR + os_err;
2321     } else if (-2 == ret) {
2322         switch (sense_cat) {
2323         case SG_LIB_CAT_RECOVERED:
2324         case SG_LIB_CAT_NO_SENSE:
2325             ret = 0;
2326             break;
2327         default:
2328             ret = sense_cat;
2329             break;
2330         }
2331     } else
2332         ret = 0;
2333     destruct_scsi_pt_obj(ptvp);
2334     return ret;
2335 }
2336 
2337 /* Handles various service actions associated with opcode 0x83 which is
2338  * called THIRD PARTY COPY OUT. These include the EXTENDED COPY(LID1 and
2339  * LID4), POPULATE TOKEN and WRITE USING TOKEN commands.
2340  * Return of 0 -> success,
2341  * various SG_LIB_CAT_* positive values or -1 -> other errors */
2342 int
sg_ll_3party_copy_out(int sg_fd,int sa,unsigned int list_id,int group_num,int timeout_secs,void * paramp,int param_len,bool noisy,int verbose)2343 sg_ll_3party_copy_out(int sg_fd, int sa, unsigned int list_id, int group_num,
2344                       int timeout_secs, void * paramp, int param_len,
2345                       bool noisy, int verbose)
2346 {
2347     int k, res, ret, sense_cat, tmout;
2348     unsigned char xcopy_cdb[THIRD_PARTY_COPY_OUT_CMDLEN] =
2349       {THIRD_PARTY_COPY_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2350     unsigned char sense_b[SENSE_BUFF_LEN];
2351     struct sg_pt_base * ptvp;
2352     char cname[80];
2353 
2354     sg_get_opcode_sa_name(THIRD_PARTY_COPY_OUT_CMD, sa, 0, sizeof(cname),
2355                           cname);
2356     xcopy_cdb[1] = (unsigned char)(sa & 0x1f);
2357     switch (sa) {
2358     case 0x0:   /* XCOPY(LID1) */
2359     case 0x1:   /* XCOPY(LID4) */
2360         sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10);
2361         break;
2362     case 0x10:  /* POPULATE TOKEN (SBC-3) */
2363     case 0x11:  /* WRITE USING TOKEN (SBC-3) */
2364         sg_put_unaligned_be32((uint32_t)list_id, xcopy_cdb + 6);
2365         sg_put_unaligned_be32((uint32_t)param_len, xcopy_cdb + 10);
2366         xcopy_cdb[14] = (unsigned char)(group_num & 0x1f);
2367         break;
2368     case 0x1c:  /* COPY OPERATION ABORT */
2369         sg_put_unaligned_be32((uint32_t)list_id, xcopy_cdb + 2);
2370         break;
2371     default:
2372         pr2ws("%s: unknown service action 0x%x\n", __func__, sa);
2373         return -1;
2374     }
2375     tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
2376 
2377     if (verbose) {
2378         pr2ws("    %s cdb: ", cname);
2379         for (k = 0; k < THIRD_PARTY_COPY_OUT_CMDLEN; ++k)
2380             pr2ws("%02x ", xcopy_cdb[k]);
2381         pr2ws("\n");
2382         if ((verbose > 1) && paramp && param_len) {
2383             pr2ws("    %s parameter list:\n", cname);
2384             hex2stderr((const uint8_t *)paramp, param_len, -1);
2385         }
2386     }
2387 
2388     if (NULL == ((ptvp = create_pt_obj(cname))))
2389         return -1;
2390     set_scsi_pt_cdb(ptvp, xcopy_cdb, sizeof(xcopy_cdb));
2391     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2392     set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len);
2393     res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
2394     ret = sg_cmds_process_resp(ptvp, cname, res, SG_NO_DATA_IN, sense_b,
2395                                noisy, verbose, &sense_cat);
2396     if (-1 == ret) {
2397         int os_err = get_scsi_pt_os_err(ptvp);
2398 
2399         if ((os_err > 0) && (os_err < 47))
2400             ret = SG_LIB_OS_BASE_ERR + os_err;
2401     } else if (-2 == ret) {
2402         switch (sense_cat) {
2403         case SG_LIB_CAT_RECOVERED:
2404         case SG_LIB_CAT_NO_SENSE:
2405             ret = 0;
2406             break;
2407         default:
2408             ret = sense_cat;
2409             break;
2410         }
2411     } else
2412         ret = 0;
2413     destruct_scsi_pt_obj(ptvp);
2414     return ret;
2415 }
2416 
2417 /* Invokes a SCSI PRE-FETCH(10), PRE-FETCH(16) or SEEK(10) command (SBC).
2418  * Returns 0 -> success, 25 (SG_LIB_CAT_CONDITION_MET), various SG_LIB_CAT_*
2419  * positive values or -1 -> other errors. Note that CONDITION MET status
2420  * is returned when immed=true and num_blocks can fit in device's cache,
2421  * somewaht strangely, GOOD status (return 0) is returned if num_blocks
2422  * cannot fit in device's cache. If do_seek10==true then does a SEEK(10)
2423  * command with given lba, if that LBA is < 2**32 . Unclear what SEEK(10)
2424  * does, assume it is like PRE-FETCH. If timeout_secs is 0 (or less) then
2425  * use DEF_PT_TIMEOUT (60 seconds) as command timeout. */
2426 int
sg_ll_pre_fetch_x(int sg_fd,bool do_seek10,bool cdb16,bool immed,uint64_t lba,uint32_t num_blocks,int group_num,int timeout_secs,bool noisy,int verbose)2427 sg_ll_pre_fetch_x(int sg_fd, bool do_seek10, bool cdb16, bool immed,
2428                   uint64_t lba, uint32_t num_blocks, int group_num,
2429                   int timeout_secs, bool noisy, int verbose)
2430 {
2431     static const char * const cdb10_name_s = "Pre-fetch(10)";
2432     static const char * const cdb16_name_s = "Pre-fetch(16)";
2433     static const char * const cdb_seek_name_s = "Seek(10)";
2434     int k, res, sense_cat, ret, cdb_len, tmout;
2435     const char *cdb_name_s;
2436     unsigned char preFetchCdb[PRE_FETCH16_CMDLEN]; /* all use longest cdb */
2437     unsigned char sense_b[SENSE_BUFF_LEN];
2438     struct sg_pt_base * ptvp;
2439 
2440     memset(preFetchCdb, 0, sizeof(preFetchCdb));
2441     if (do_seek10) {
2442         if (lba > UINT32_MAX) {
2443             if (verbose)
2444                 pr2ws("%s: LBA exceeds 2**32 in %s\n", __func__,
2445                       cdb_seek_name_s);
2446             return -1;
2447         }
2448         preFetchCdb[0] = SEEK10_CMD;
2449         cdb_len = SEEK10_CMDLEN;
2450         cdb_name_s = cdb_seek_name_s;
2451         sg_put_unaligned_be32((uint32_t)lba, preFetchCdb + 2);
2452     } else {
2453         if ((! cdb16) &&
2454             ((lba > UINT32_MAX) || (num_blocks > UINT16_MAX))) {
2455             cdb16 = true;
2456             if (noisy || verbose)
2457                 pr2ws("%s: do %s due to %s size\n", __func__, cdb16_name_s,
2458                       (lba > UINT32_MAX) ? "LBA" : "NUM_BLOCKS");
2459         }
2460         if (cdb16) {
2461             preFetchCdb[0] = PRE_FETCH16_CMD;
2462             cdb_len = PRE_FETCH16_CMDLEN;
2463             cdb_name_s = cdb16_name_s;
2464             if (immed)
2465                 preFetchCdb[1] = 0x2;
2466             sg_put_unaligned_be64(lba, preFetchCdb + 2);
2467             sg_put_unaligned_be32(num_blocks, preFetchCdb + 10);
2468             preFetchCdb[14] = 0x3f & group_num;
2469         } else {
2470             preFetchCdb[0] = PRE_FETCH10_CMD;
2471             cdb_len = PRE_FETCH10_CMDLEN;
2472             cdb_name_s = cdb10_name_s;
2473             if (immed)
2474                 preFetchCdb[1] = 0x2;
2475             sg_put_unaligned_be32((uint32_t)lba, preFetchCdb + 2);
2476             preFetchCdb[6] = 0x3f & group_num;
2477             sg_put_unaligned_be16((uint16_t)num_blocks, preFetchCdb + 7);
2478         }
2479     }
2480     tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT;
2481     if (verbose) {
2482         pr2ws("    %s cdb: ", cdb_name_s);
2483         for (k = 0; k < cdb_len; ++k)
2484             pr2ws("%02x ", preFetchCdb[k]);
2485         pr2ws("\n");
2486     }
2487     if (NULL == ((ptvp = create_pt_obj(cdb_name_s))))
2488         return -1;
2489     set_scsi_pt_cdb(ptvp, preFetchCdb, cdb_len);
2490     set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
2491     res = do_scsi_pt(ptvp, sg_fd, tmout, verbose);
2492     if (0 == res) {
2493         int sstat = get_scsi_pt_status_response(ptvp);
2494 
2495         if (SG_LIB_CAT_CONDITION_MET == sstat) {
2496             ret = SG_LIB_CAT_CONDITION_MET;
2497             if (verbose > 2)
2498                 pr2ws("%s: returns SG_LIB_CAT_CONDITION_MET\n", __func__);
2499             goto fini;
2500         }
2501     }
2502     ret = sg_cmds_process_resp(ptvp, cdb_name_s, res, SG_NO_DATA_IN, sense_b,
2503                                noisy, verbose, &sense_cat);
2504     if (-1 == ret) {
2505         int os_err = get_scsi_pt_os_err(ptvp);
2506 
2507         if ((os_err > 0) && (os_err < 47))
2508             ret = SG_LIB_OS_BASE_ERR + os_err;
2509     } else if (-2 == ret) {
2510         switch (sense_cat) {
2511         case SG_LIB_CAT_RECOVERED:
2512         case SG_LIB_CAT_NO_SENSE:
2513             ret = 0;
2514             break;
2515         default:
2516             ret = sense_cat;
2517             break;
2518         }
2519     } else
2520         ret = 0;
2521 fini:
2522     destruct_scsi_pt_obj(ptvp);
2523     return ret;
2524 }
2525