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