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