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