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