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 /*
11 * CONTENTS
12 * Some SCSI commands are executed in many contexts and hence began
13 * to appear in several sg3_utils utilities. This files centralizes
14 * some of the low level command execution code. In most cases the
15 * interpretation of the command response is left to the each
16 * utility.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "sg_lib.h"
31 #include "sg_cmds_basic.h"
32 #include "sg_pt.h"
33 #include "sg_unaligned.h"
34 #include "sg_pr2serr.h"
35
36
37
38 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */
39 #define EBUFF_SZ 256
40
41 #define DEF_PT_TIMEOUT 60 /* 60 seconds */
42 #define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */
43 #define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */
44
45 #define SYNCHRONIZE_CACHE_CMD 0x35
46 #define SYNCHRONIZE_CACHE_CMDLEN 10
47 #define SERVICE_ACTION_IN_16_CMD 0x9e
48 #define SERVICE_ACTION_IN_16_CMDLEN 16
49 #define READ_CAPACITY_16_SA 0x10
50 #define READ_CAPACITY_10_CMD 0x25
51 #define READ_CAPACITY_10_CMDLEN 10
52 #define MODE_SENSE6_CMD 0x1a
53 #define MODE_SENSE6_CMDLEN 6
54 #define MODE_SENSE10_CMD 0x5a
55 #define MODE_SENSE10_CMDLEN 10
56 #define MODE_SELECT6_CMD 0x15
57 #define MODE_SELECT6_CMDLEN 6
58 #define MODE_SELECT10_CMD 0x55
59 #define MODE_SELECT10_CMDLEN 10
60 #define LOG_SENSE_CMD 0x4d
61 #define LOG_SENSE_CMDLEN 10
62 #define LOG_SELECT_CMD 0x4c
63 #define LOG_SELECT_CMDLEN 10
64 #define START_STOP_CMD 0x1b
65 #define START_STOP_CMDLEN 6
66 #define PREVENT_ALLOW_CMD 0x1e
67 #define PREVENT_ALLOW_CMDLEN 6
68
69 #define MODE6_RESP_HDR_LEN 4
70 #define MODE10_RESP_HDR_LEN 8
71 #define MODE_RESP_ARB_LEN 1024
72
73 #define INQUIRY_RESP_INITIAL_LEN 36
74
75
76 static struct sg_pt_base *
create_pt_obj(const char * cname)77 create_pt_obj(const char * cname)
78 {
79 struct sg_pt_base * ptvp = construct_scsi_pt_obj();
80 if (NULL == ptvp)
81 pr2ws("%s: out of memory\n", cname);
82 return ptvp;
83 }
84
85 /* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success,
86 * various SG_LIB_CAT_* positive values or -1 -> other errors */
87 int
sg_ll_sync_cache_10(int sg_fd,bool sync_nv,bool immed,int group,unsigned int lba,unsigned int count,bool noisy,int verbose)88 sg_ll_sync_cache_10(int sg_fd, bool sync_nv, bool immed, int group,
89 unsigned int lba, unsigned int count, bool noisy,
90 int verbose)
91 {
92 static const char * const cdb_s = "synchronize cache(10)";
93 int res, ret, sense_cat;
94 uint8_t sc_cdb[SYNCHRONIZE_CACHE_CMDLEN] =
95 {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
96 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
97 struct sg_pt_base * ptvp;
98
99 if (sync_nv)
100 sc_cdb[1] |= 4;
101 if (immed)
102 sc_cdb[1] |= 2;
103 sg_put_unaligned_be32((uint32_t)lba, sc_cdb + 2);
104 sc_cdb[6] = group & GRPNUM_MASK;
105 if (count > 0xffff) {
106 pr2ws("count too big\n");
107 return -1;
108 }
109 sg_put_unaligned_be16((int16_t)count, sc_cdb + 7);
110
111 if (verbose) {
112 char b[128];
113
114 pr2ws(" %s cdb: %s\n", cdb_s,
115 sg_get_command_str(sc_cdb, SYNCHRONIZE_CACHE_CMDLEN, false,
116 sizeof(b), b));
117 }
118 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
119 return -1;
120 set_scsi_pt_cdb(ptvp, sc_cdb, sizeof(sc_cdb));
121 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
122 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
123 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
124 if (-1 == ret) {
125 if (get_scsi_pt_transport_err(ptvp))
126 ret = SG_LIB_TRANSPORT_ERROR;
127 else
128 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
129 } else if (-2 == ret) {
130 switch (sense_cat) {
131 case SG_LIB_CAT_RECOVERED:
132 case SG_LIB_CAT_NO_SENSE:
133 ret = 0;
134 break;
135 default:
136 ret = sense_cat;
137 break;
138 }
139 } else
140 ret = 0;
141
142 destruct_scsi_pt_obj(ptvp);
143 return ret;
144 }
145
146 /* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success,
147 * various SG_LIB_CAT_* positive values or -1 -> other errors */
148 int
sg_ll_readcap_16(int sg_fd,bool pmi,uint64_t llba,void * resp,int mx_resp_len,bool noisy,int verbose)149 sg_ll_readcap_16(int sg_fd, bool pmi, uint64_t llba, void * resp,
150 int mx_resp_len, bool noisy, int verbose)
151 {
152 static const char * const cdb_s = "read capacity(16)";
153 int ret, res, sense_cat;
154 uint8_t rc_cdb[SERVICE_ACTION_IN_16_CMDLEN] =
155 {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA,
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
157 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
158 struct sg_pt_base * ptvp;
159
160 if (pmi) { /* lbs only valid when pmi set */
161 rc_cdb[14] |= 1;
162 sg_put_unaligned_be64(llba, rc_cdb + 2);
163 }
164 /* Allocation length, no guidance in SBC-2 rev 15b */
165 sg_put_unaligned_be32((uint32_t)mx_resp_len, rc_cdb + 10);
166 if (verbose) {
167 char b[128];
168
169 pr2ws(" %s cdb: %s\n", cdb_s,
170 sg_get_command_str(rc_cdb, SERVICE_ACTION_IN_16_CMDLEN, false,
171 sizeof(b), b));
172 }
173 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
174 return -1;
175 set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
176 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
177 set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
178 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
179 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
180 if (-1 == ret) {
181 if (get_scsi_pt_transport_err(ptvp))
182 ret = SG_LIB_TRANSPORT_ERROR;
183 else
184 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
185 } else if (-2 == ret) {
186 switch (sense_cat) {
187 case SG_LIB_CAT_RECOVERED:
188 case SG_LIB_CAT_NO_SENSE:
189 ret = 0;
190 break;
191 default:
192 ret = sense_cat;
193 break;
194 }
195 } else
196 ret = 0;
197
198 destruct_scsi_pt_obj(ptvp);
199 return ret;
200 }
201
202 /* Invokes a SCSI READ CAPACITY (10) command. Returns 0 -> success,
203 * various SG_LIB_CAT_* positive values or -1 -> other errors */
204 int
sg_ll_readcap_10(int sg_fd,bool pmi,unsigned int lba,void * resp,int mx_resp_len,bool noisy,int verbose)205 sg_ll_readcap_10(int sg_fd, bool pmi, unsigned int lba, void * resp,
206 int mx_resp_len, bool noisy, int verbose)
207 {
208 static const char * const cdb_s = "read capacity(10)";
209 int ret, res, sense_cat;
210 uint8_t rc_cdb[READ_CAPACITY_10_CMDLEN] =
211 {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
212 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
213 struct sg_pt_base * ptvp;
214
215 if (pmi) { /* lbs only valid when pmi set */
216 rc_cdb[8] |= 1;
217 sg_put_unaligned_be32((uint32_t)lba, rc_cdb + 2);
218 }
219 if (verbose) {
220 char b[128];
221
222 pr2ws(" %s cdb: %s\n", cdb_s,
223 sg_get_command_str(rc_cdb, READ_CAPACITY_10_CMDLEN, false,
224 sizeof(b), b));
225 }
226 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
227 return -1;
228 set_scsi_pt_cdb(ptvp, rc_cdb, sizeof(rc_cdb));
229 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
230 set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
231 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
232 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
233 if (-1 == ret) {
234 if (get_scsi_pt_transport_err(ptvp))
235 ret = SG_LIB_TRANSPORT_ERROR;
236 else
237 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
238 } else if (-2 == ret) {
239 switch (sense_cat) {
240 case SG_LIB_CAT_RECOVERED:
241 case SG_LIB_CAT_NO_SENSE:
242 ret = 0;
243 break;
244 default:
245 ret = sense_cat;
246 break;
247 }
248 } else
249 ret = 0;
250
251 destruct_scsi_pt_obj(ptvp);
252 return ret;
253 }
254
255 /* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success,
256 * various SG_LIB_CAT_* positive values or -1 -> other errors */
257 int
sg_ll_mode_sense6(int sg_fd,bool dbd,int pc,int pg_code,int sub_pg_code,void * resp,int mx_resp_len,bool noisy,int verbose)258 sg_ll_mode_sense6(int sg_fd, bool dbd, int pc, int pg_code, int sub_pg_code,
259 void * resp, int mx_resp_len, bool noisy, int verbose)
260 {
261 static const char * const cdb_s = "mode sense(6)";
262 int res, ret, sense_cat, resid;
263 uint8_t modes_cdb[MODE_SENSE6_CMDLEN] =
264 {MODE_SENSE6_CMD, 0, 0, 0, 0, 0};
265 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
266 struct sg_pt_base * ptvp;
267
268 modes_cdb[1] = (uint8_t)(dbd ? 0x8 : 0);
269 modes_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
270 modes_cdb[3] = (uint8_t)(sub_pg_code & 0xff);
271 modes_cdb[4] = (uint8_t)(mx_resp_len & 0xff);
272 if (mx_resp_len > 0xff) {
273 pr2ws("mx_resp_len too big\n");
274 return -1;
275 }
276 if (verbose) {
277 char b[128];
278
279 pr2ws(" %s cdb: %s\n", cdb_s,
280 sg_get_command_str(modes_cdb, MODE_SENSE6_CMDLEN, false,
281 sizeof(b), b));
282 }
283 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
284 return -1;
285 set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
286 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
287 set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
288 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
289 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
290 resid = get_scsi_pt_resid(ptvp);
291 if (-1 == ret) {
292 if (get_scsi_pt_transport_err(ptvp))
293 ret = SG_LIB_TRANSPORT_ERROR;
294 else
295 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
296 } else if (-2 == ret) {
297 switch (sense_cat) {
298 case SG_LIB_CAT_RECOVERED:
299 case SG_LIB_CAT_NO_SENSE:
300 ret = 0;
301 break;
302 default:
303 ret = sense_cat;
304 break;
305 }
306 } else {
307 if ((verbose > 2) && (ret > 0)) {
308 pr2ws(" %s: response", cdb_s);
309 if (3 == verbose) {
310 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
311 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
312 -1);
313 } else {
314 pr2ws(":\n");
315 hex2stderr((const uint8_t *)resp, ret, 0);
316 }
317 }
318 ret = 0;
319 }
320 destruct_scsi_pt_obj(ptvp);
321
322 if (resid > 0) {
323 if (resid > mx_resp_len) {
324 pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
325 cdb_s, resid, mx_resp_len);
326 return ret ? ret : SG_LIB_CAT_MALFORMED;
327 }
328 /* zero unfilled section of response buffer */
329 memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid);
330 }
331 return ret;
332 }
333
334 /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
335 * various SG_LIB_CAT_* positive values or -1 -> other errors */
336 int
sg_ll_mode_sense10(int sg_fd,bool llbaa,bool dbd,int pc,int pg_code,int sub_pg_code,void * resp,int mx_resp_len,bool noisy,int verbose)337 sg_ll_mode_sense10(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
338 int sub_pg_code, void * resp, int mx_resp_len,
339 bool noisy, int verbose)
340 {
341 return sg_ll_mode_sense10_v2(sg_fd, llbaa, dbd, pc, pg_code, sub_pg_code,
342 resp, mx_resp_len, 0, NULL, noisy, verbose);
343 }
344
345 /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success,
346 * various SG_LIB_CAT_* positive values or -1 -> other errors.
347 * Adds the ability to set the command abort timeout
348 * and the ability to report the residual count. If timeout_secs is zero
349 * or less the default command abort timeout (60 seconds) is used.
350 * If residp is non-NULL then the residual value is written where residp
351 * points. A residual value of 0 implies mx_resp_len bytes have be written
352 * where resp points. If the residual value equals mx_resp_len then no
353 * bytes have been written. */
354 int
sg_ll_mode_sense10_v2(int sg_fd,bool llbaa,bool dbd,int pc,int pg_code,int sub_pg_code,void * resp,int mx_resp_len,int timeout_secs,int * residp,bool noisy,int verbose)355 sg_ll_mode_sense10_v2(int sg_fd, bool llbaa, bool dbd, int pc, int pg_code,
356 int sub_pg_code, void * resp, int mx_resp_len,
357 int timeout_secs, int * residp, bool noisy, int verbose)
358 {
359 int res, ret, sense_cat, resid;
360 static const char * const cdb_s = "mode sense(10)";
361 struct sg_pt_base * ptvp;
362 uint8_t modes_cdb[MODE_SENSE10_CMDLEN] =
363 {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
364 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
365
366 modes_cdb[1] = (uint8_t)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0));
367 modes_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
368 modes_cdb[3] = (uint8_t)(sub_pg_code & 0xff);
369 sg_put_unaligned_be16((int16_t)mx_resp_len, modes_cdb + 7);
370 if (mx_resp_len > 0xffff) {
371 pr2ws("mx_resp_len too big\n");
372 goto gen_err;
373 }
374 if (verbose) {
375 char b[128];
376
377 pr2ws(" %s cdb: %s\n", cdb_s,
378 sg_get_command_str(modes_cdb, MODE_SENSE10_CMDLEN, false,
379 sizeof(b), b));
380 }
381 if (timeout_secs <= 0)
382 timeout_secs = DEF_PT_TIMEOUT;
383
384 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
385 goto gen_err;
386 set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
387 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
388 set_scsi_pt_data_in(ptvp, (uint8_t *)resp, mx_resp_len);
389 res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
390 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
391 resid = get_scsi_pt_resid(ptvp);
392 if (residp)
393 *residp = resid;
394 if (-1 == ret) {
395 if (get_scsi_pt_transport_err(ptvp))
396 ret = SG_LIB_TRANSPORT_ERROR;
397 else
398 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
399 } else if (-2 == ret) {
400 switch (sense_cat) {
401 case SG_LIB_CAT_RECOVERED:
402 case SG_LIB_CAT_NO_SENSE:
403 ret = 0;
404 break;
405 default:
406 ret = sense_cat;
407 break;
408 }
409 } else {
410 if ((verbose > 2) && (ret > 0)) {
411 pr2ws(" %s: response", cdb_s);
412 if (3 == verbose) {
413 pr2ws("%s:\n", (ret > 256 ? ", first 256 bytes" : ""));
414 hex2stderr((const uint8_t *)resp, (ret > 256 ? 256 : ret),
415 -1);
416 } else {
417 pr2ws(":\n");
418 hex2stderr((const uint8_t *)resp, ret, 0);
419 }
420 }
421 ret = 0;
422 }
423 destruct_scsi_pt_obj(ptvp);
424
425 if (resid > 0) {
426 if (resid > mx_resp_len) {
427 pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
428 cdb_s, resid, mx_resp_len);
429 return ret ? ret : SG_LIB_CAT_MALFORMED;
430 }
431 /* zero unfilled section of response buffer */
432 memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid);
433 }
434 return ret;
435 gen_err:
436 if (residp)
437 *residp = 0;
438 return -1;
439 }
440
441 /* Invokes a SCSI MODE SELECT (6) command. Return of 0 -> success,
442 * various SG_LIB_CAT_* positive values or -1 -> other errors */
443 int
sg_ll_mode_select6_v2(int sg_fd,bool pf,bool rtd,bool sp,void * paramp,int param_len,bool noisy,int verbose)444 sg_ll_mode_select6_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp,
445 int param_len, bool noisy, int verbose)
446 {
447 static const char * const cdb_s = "mode select(6)";
448 int res, ret, sense_cat;
449 uint8_t modes_cdb[MODE_SELECT6_CMDLEN] =
450 {MODE_SELECT6_CMD, 0, 0, 0, 0, 0};
451 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
452 struct sg_pt_base * ptvp;
453
454 modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
455 if (rtd)
456 modes_cdb[1] |= 0x2;
457 modes_cdb[4] = (uint8_t)(param_len & 0xff);
458 if (param_len > 0xff) {
459 pr2ws("%s: param_len too big\n", cdb_s);
460 return -1;
461 }
462 if (verbose) {
463 char b[128];
464
465 pr2ws(" %s cdb: %s\n", cdb_s,
466 sg_get_command_str(modes_cdb, MODE_SELECT6_CMDLEN, false,
467 sizeof(b), b));
468 }
469 if (verbose > 1) {
470 pr2ws(" %s parameter list\n", cdb_s);
471 hex2stderr((const uint8_t *)paramp, param_len, -1);
472 }
473
474 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
475 return -1;
476 set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
477 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
478 set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len);
479 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
480 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
481 if (-1 == ret) {
482 if (get_scsi_pt_transport_err(ptvp))
483 ret = SG_LIB_TRANSPORT_ERROR;
484 else
485 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
486 } else if (-2 == ret) {
487 switch (sense_cat) {
488 case SG_LIB_CAT_RECOVERED:
489 case SG_LIB_CAT_NO_SENSE:
490 ret = 0;
491 break;
492 default:
493 ret = sense_cat;
494 break;
495 }
496 } else
497 ret = 0;
498
499 destruct_scsi_pt_obj(ptvp);
500 return ret;
501 }
502
503 int
sg_ll_mode_select6(int sg_fd,bool pf,bool sp,void * paramp,int param_len,bool noisy,int verbose)504 sg_ll_mode_select6(int sg_fd, bool pf, bool sp, void * paramp, int param_len,
505 bool noisy, int verbose)
506 {
507 return sg_ll_mode_select6_v2(sg_fd, pf, false, sp, paramp, param_len,
508 noisy, verbose);
509 }
510
511 /* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success,
512 * various SG_LIB_CAT_* positive values or -1 -> other errors,
513 * v2 adds rtd (revert to defaults) bit (spc5r11). */
514 int
sg_ll_mode_select10_v2(int sg_fd,bool pf,bool rtd,bool sp,void * paramp,int param_len,bool noisy,int verbose)515 sg_ll_mode_select10_v2(int sg_fd, bool pf, bool rtd, bool sp, void * paramp,
516 int param_len, bool noisy, int verbose)
517 {
518 static const char * const cdb_s = "mode select(10)";
519 int res, ret, sense_cat;
520 uint8_t modes_cdb[MODE_SELECT10_CMDLEN] =
521 {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
522 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
523 struct sg_pt_base * ptvp;
524
525 modes_cdb[1] = (uint8_t)((pf ? 0x10 : 0x0) | (sp ? 0x1 : 0x0));
526 if (rtd)
527 modes_cdb[1] |= 0x2;
528 sg_put_unaligned_be16((int16_t)param_len, modes_cdb + 7);
529 if (param_len > 0xffff) {
530 pr2ws("%s: param_len too big\n", cdb_s);
531 return -1;
532 }
533 if (verbose) {
534 char b[128];
535
536 pr2ws(" %s cdb: %s\n", cdb_s,
537 sg_get_command_str(modes_cdb, MODE_SELECT10_CMDLEN, false,
538 sizeof(b), b));
539 }
540 if (verbose > 1) {
541 pr2ws(" %s parameter list\n", cdb_s);
542 hex2stderr((const uint8_t *)paramp, param_len, -1);
543 }
544
545 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
546 return -1;
547 set_scsi_pt_cdb(ptvp, modes_cdb, sizeof(modes_cdb));
548 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
549 set_scsi_pt_data_out(ptvp, (uint8_t *)paramp, param_len);
550 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
551 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
552 if (-1 == ret) {
553 if (get_scsi_pt_transport_err(ptvp))
554 ret = SG_LIB_TRANSPORT_ERROR;
555 else
556 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
557 } else if (-2 == ret) {
558 switch (sense_cat) {
559 case SG_LIB_CAT_RECOVERED:
560 case SG_LIB_CAT_NO_SENSE:
561 ret = 0;
562 break;
563 default:
564 ret = sense_cat;
565 break;
566 }
567 } else
568 ret = 0;
569
570 destruct_scsi_pt_obj(ptvp);
571 return ret;
572 }
573
574 int
sg_ll_mode_select10(int sg_fd,bool pf,bool sp,void * paramp,int param_len,bool noisy,int verbose)575 sg_ll_mode_select10(int sg_fd, bool pf, bool sp, void * paramp,
576 int param_len, bool noisy, int verbose)
577 {
578 return sg_ll_mode_select10_v2(sg_fd, pf, false, sp, paramp, param_len,
579 noisy, verbose);
580 }
581
582 /* MODE SENSE commands yield a response that has header then zero or more
583 * block descriptors followed by mode pages. In most cases users are
584 * interested in the first mode page. This function returns the (byte)
585 * offset of the start of the first mode page. Set mode_sense_6 to true for
586 * MODE SENSE (6) and false for MODE SENSE (10). Returns >= 0 is successful
587 * or -1 if failure. If there is a failure a message is written to err_buff
588 * if it is non-NULL and err_buff_len > 0. */
589 int
sg_mode_page_offset(const uint8_t * resp,int resp_len,bool mode_sense_6,char * err_buff,int err_buff_len)590 sg_mode_page_offset(const uint8_t * resp, int resp_len,
591 bool mode_sense_6, char * err_buff, int err_buff_len)
592 {
593 int bd_len, calc_len, offset;
594 bool err_buff_ok = ((err_buff_len > 0) && err_buff);
595
596 if ((NULL == resp) || (resp_len < 4))
597 goto too_short;
598 if (mode_sense_6) {
599 calc_len = resp[0] + 1;
600 bd_len = resp[3];
601 offset = bd_len + MODE6_RESP_HDR_LEN;
602 } else { /* Mode sense(10) */
603 if (resp_len < 8)
604 goto too_short;
605 calc_len = sg_get_unaligned_be16(resp) + 2;
606 bd_len = sg_get_unaligned_be16(resp + 6);
607 /* LongLBA doesn't change this calculation */
608 offset = bd_len + MODE10_RESP_HDR_LEN;
609 }
610 if ((offset + 2) > calc_len) {
611 if (err_buff_ok)
612 snprintf(err_buff, err_buff_len, "calculated response "
613 "length too small, offset=%d calc_len=%d bd_len=%d\n",
614 offset, calc_len, bd_len);
615 offset = -1;
616 }
617 return offset;
618 too_short:
619 if (err_buff_ok)
620 snprintf(err_buff, err_buff_len, "given MS(%d) response length (%d) "
621 "too short\n", (mode_sense_6 ? 6 : 10), resp_len);
622 return -1;
623 }
624
625 /* MODE SENSE commands yield a response that has header then zero or more
626 * block descriptors followed by mode pages. This functions returns the
627 * length (in bytes) of those three components. Note that the return value
628 * can exceed resp_len in which case the MODE SENSE command should be
629 * re-issued with a larger response buffer. If bd_lenp is non-NULL and if
630 * successful the block descriptor length (in bytes) is written to *bd_lenp.
631 * Set mode_sense_6 to true for MODE SENSE (6) and false for MODE SENSE (10)
632 * responses. Returns -1 if there is an error (e.g. response too short). */
633 int
sg_msense_calc_length(const uint8_t * resp,int resp_len,bool mode_sense_6,int * bd_lenp)634 sg_msense_calc_length(const uint8_t * resp, int resp_len,
635 bool mode_sense_6, int * bd_lenp)
636 {
637 int calc_len;
638
639 if (NULL == resp)
640 goto an_err;
641 if (mode_sense_6) {
642 if (resp_len < 4)
643 goto an_err;
644 calc_len = resp[0] + 1;
645 } else {
646 if (resp_len < 8)
647 goto an_err;
648 calc_len = sg_get_unaligned_be16(resp + 0) + 2;
649 }
650 if (bd_lenp)
651 *bd_lenp = mode_sense_6 ? resp[3] : sg_get_unaligned_be16(resp + 6);
652 return calc_len;
653 an_err:
654 if (bd_lenp)
655 *bd_lenp = 0;
656 return -1;
657 }
658
659 /* Fetches current, changeable, default and/or saveable modes pages as
660 * indicated by pcontrol_arr for given pg_code and sub_pg_code. If
661 * mode6==false then use MODE SENSE (10) else use MODE SENSE (6). If
662 * flexible set and mode data length seems wrong then try and
663 * fix (compensating hack for bad device or driver). pcontrol_arr
664 * should have 4 elements for output of current, changeable, default
665 * and saved values respectively. Each element should be NULL or
666 * at least mx_mpage_len bytes long.
667 * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or
668 * -1 -> other errors.
669 * If success_mask pointer is not NULL then first zeros it. Then set bits
670 * 0, 1, 2 and/or 3 if the current, changeable, default and saved values
671 * respectively have been fetched. If error on current page
672 * then stops and returns that error; otherwise continues if an error is
673 * detected but returns the first error encountered. */
674 int
sg_get_mode_page_controls(int sg_fd,bool mode6,int pg_code,int sub_pg_code,bool dbd,bool flexible,int mx_mpage_len,int * success_mask,void * pcontrol_arr[],int * reported_lenp,int verbose)675 sg_get_mode_page_controls(int sg_fd, bool mode6, int pg_code, int sub_pg_code,
676 bool dbd, bool flexible, int mx_mpage_len,
677 int * success_mask, void * pcontrol_arr[],
678 int * reported_lenp, int verbose)
679 {
680 bool resp_mode6;
681 int k, n, res, offset, calc_len, xfer_len;
682 int resid = 0;
683 const int msense10_hlen = MODE10_RESP_HDR_LEN;
684 uint8_t buff[MODE_RESP_ARB_LEN];
685 char ebuff[EBUFF_SZ];
686 int first_err = 0;
687
688 if (success_mask)
689 *success_mask = 0;
690 if (reported_lenp)
691 *reported_lenp = 0;
692 if (mx_mpage_len < 4)
693 return 0;
694 memset(ebuff, 0, sizeof(ebuff));
695 /* first try to find length of current page response */
696 memset(buff, 0, msense10_hlen);
697 if (mode6) /* want first 8 bytes just in case */
698 res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code,
699 sub_pg_code, buff, msense10_hlen, true,
700 verbose);
701 else /* MODE SENSE(10) obviously */
702 res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
703 0 /* pc */, pg_code, sub_pg_code, buff,
704 msense10_hlen, 0, &resid, true, verbose);
705 if (0 != res)
706 return res;
707 n = buff[0];
708 if (reported_lenp) {
709 int m;
710
711 m = sg_msense_calc_length(buff, msense10_hlen, mode6, NULL) - resid;
712 if (m < 0) /* Grrr, this should not happen */
713 m = 0;
714 *reported_lenp = m;
715 }
716 resp_mode6 = mode6;
717 if (flexible) {
718 if (mode6 && (n < 3)) {
719 resp_mode6 = false;
720 if (verbose)
721 pr2ws(">>> msense(6) but resp[0]=%d so try msense(10) "
722 "response processing\n", n);
723 }
724 if ((! mode6) && (n > 5)) {
725 if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) &&
726 (0 == buff[5]) && (0 == buff[6])) {
727 buff[1] = n;
728 buff[0] = 0;
729 if (verbose)
730 pr2ws(">>> msense(10) but resp[0]=%d and not msense(6) "
731 "response so fix length\n", n);
732 } else
733 resp_mode6 = true;
734 }
735 }
736 if (verbose && (resp_mode6 != mode6))
737 pr2ws(">>> msense(%d) but resp[0]=%d so switch response "
738 "processing\n", (mode6 ? 6 : 10), buff[0]);
739 calc_len = sg_msense_calc_length(buff, msense10_hlen, resp_mode6, NULL);
740 if (calc_len > MODE_RESP_ARB_LEN)
741 calc_len = MODE_RESP_ARB_LEN;
742 offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ);
743 if (offset < 0) {
744 if (('\0' != ebuff[0]) && (verbose > 0))
745 pr2ws("%s: %s\n", __func__, ebuff);
746 return SG_LIB_CAT_MALFORMED;
747 }
748 xfer_len = calc_len - offset;
749 if (xfer_len > mx_mpage_len)
750 xfer_len = mx_mpage_len;
751
752 for (k = 0; k < 4; ++k) {
753 if (NULL == pcontrol_arr[k])
754 continue;
755 memset(pcontrol_arr[k], 0, mx_mpage_len);
756 resid = 0;
757 if (mode6)
758 res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */,
759 pg_code, sub_pg_code, buff,
760 calc_len, true, verbose);
761 else
762 res = sg_ll_mode_sense10_v2(sg_fd, false /* llbaa */, dbd,
763 k /* pc */, pg_code, sub_pg_code,
764 buff, calc_len, 0, &resid, true,
765 verbose);
766 if (res || resid) {
767 if (0 == first_err) {
768 if (res)
769 first_err = res;
770 else {
771 first_err = -49; /* unexpected resid != 0 */
772 if (verbose)
773 pr2ws("%s: unexpected resid=%d, page=0x%x, "
774 "pcontrol=%d\n", __func__, resid, pg_code, k);
775 }
776 }
777 if (0 == k)
778 break; /* if problem on current page, it won't improve */
779 else
780 continue;
781 }
782 if (xfer_len > 0)
783 memcpy(pcontrol_arr[k], buff + offset, xfer_len);
784 if (success_mask)
785 *success_mask |= (1 << k);
786 }
787 return first_err;
788 }
789
790 /* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
791 * various SG_LIB_CAT_* positive values or -1 -> other errors. */
792 int
sg_ll_log_sense(int sg_fd,bool ppc,bool sp,int pc,int pg_code,int subpg_code,int paramp,uint8_t * resp,int mx_resp_len,bool noisy,int verbose)793 sg_ll_log_sense(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
794 int subpg_code, int paramp, uint8_t * resp,
795 int mx_resp_len, bool noisy, int verbose)
796 {
797 return sg_ll_log_sense_v2(sg_fd, ppc, sp, pc, pg_code, subpg_code,
798 paramp, resp, mx_resp_len, 0, NULL, noisy,
799 verbose);
800 }
801
802 /* Invokes a SCSI LOG SENSE command. Return of 0 -> success,
803 * various SG_LIB_CAT_* positive values or -1 -> other errors.
804 * Adds the ability to set the command abort timeout
805 * and the ability to report the residual count. If timeout_secs is zero
806 * or less the default command abort timeout (60 seconds) is used.
807 * If residp is non-NULL then the residual value is written where residp
808 * points. A residual value of 0 implies mx_resp_len bytes have be written
809 * where resp points. If the residual value equals mx_resp_len then no
810 * bytes have been written. */
811 int
sg_ll_log_sense_v2(int sg_fd,bool ppc,bool sp,int pc,int pg_code,int subpg_code,int paramp,uint8_t * resp,int mx_resp_len,int timeout_secs,int * residp,bool noisy,int verbose)812 sg_ll_log_sense_v2(int sg_fd, bool ppc, bool sp, int pc, int pg_code,
813 int subpg_code, int paramp, uint8_t * resp,
814 int mx_resp_len, int timeout_secs, int * residp,
815 bool noisy, int verbose)
816 {
817 static const char * const cdb_s = "log sense";
818 int res, ret, sense_cat, resid;
819 uint8_t logs_cdb[LOG_SENSE_CMDLEN] =
820 {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
821 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
822 struct sg_pt_base * ptvp;
823
824 if (mx_resp_len > 0xffff) {
825 pr2ws("mx_resp_len too big\n");
826 goto gen_err;
827 }
828 logs_cdb[1] = (uint8_t)((ppc ? 2 : 0) | (sp ? 1 : 0));
829 logs_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
830 logs_cdb[3] = (uint8_t)(subpg_code & 0xff);
831 sg_put_unaligned_be16((int16_t)paramp, logs_cdb + 5);
832 sg_put_unaligned_be16((int16_t)mx_resp_len, logs_cdb + 7);
833 if (verbose) {
834 char b[128];
835
836 pr2ws(" %s cdb: %s\n", cdb_s,
837 sg_get_command_str(logs_cdb, LOG_SENSE_CMDLEN, false,
838 sizeof(b), b));
839 }
840 if (timeout_secs <= 0)
841 timeout_secs = DEF_PT_TIMEOUT;
842
843 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
844 goto gen_err;
845 set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
846 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
847 set_scsi_pt_data_in(ptvp, resp, mx_resp_len);
848 res = do_scsi_pt(ptvp, sg_fd, timeout_secs, verbose);
849 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
850 resid = get_scsi_pt_resid(ptvp);
851 if (residp)
852 *residp = resid;
853 if (-1 == ret) {
854 if (get_scsi_pt_transport_err(ptvp))
855 ret = SG_LIB_TRANSPORT_ERROR;
856 else
857 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
858 } else if (-2 == ret) {
859 switch (sense_cat) {
860 case SG_LIB_CAT_RECOVERED:
861 case SG_LIB_CAT_NO_SENSE:
862 ret = 0;
863 break;
864 default:
865 ret = sense_cat;
866 break;
867 }
868 } else {
869 if ((mx_resp_len > 3) && (ret < 4)) {
870 /* resid indicates LOG SENSE response length bad, so zero it */
871 resp[2] = 0;
872 resp[3] = 0;
873 }
874 ret = 0;
875 }
876 destruct_scsi_pt_obj(ptvp);
877
878 if (resid > 0) {
879 if (resid > mx_resp_len) {
880 pr2ws("%s: resid (%d) should never exceed requested len=%d\n",
881 cdb_s, resid, mx_resp_len);
882 return ret ? ret : SG_LIB_CAT_MALFORMED;
883 }
884 /* zero unfilled section of response buffer */
885 memset((uint8_t *)resp + (mx_resp_len - resid), 0, resid);
886 }
887 return ret;
888 gen_err:
889 if (residp)
890 *residp = 0;
891 return -1;
892 }
893
894 /* Invokes a SCSI LOG SELECT command. Return of 0 -> success,
895 * various SG_LIB_CAT_* positive values or -1 -> other errors */
896 int
sg_ll_log_select(int sg_fd,bool pcr,bool sp,int pc,int pg_code,int subpg_code,uint8_t * paramp,int param_len,bool noisy,int verbose)897 sg_ll_log_select(int sg_fd, bool pcr, bool sp, int pc, int pg_code,
898 int subpg_code, uint8_t * paramp, int param_len,
899 bool noisy, int verbose)
900 {
901 static const char * const cdb_s = "log select";
902 int res, ret, sense_cat;
903 uint8_t logs_cdb[LOG_SELECT_CMDLEN] =
904 {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
905 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
906 struct sg_pt_base * ptvp;
907
908 if (param_len > 0xffff) {
909 pr2ws("%s: param_len too big\n", cdb_s);
910 return -1;
911 }
912 logs_cdb[1] = (uint8_t)((pcr ? 2 : 0) | (sp ? 1 : 0));
913 logs_cdb[2] = (uint8_t)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
914 logs_cdb[3] = (uint8_t)(subpg_code & 0xff);
915 sg_put_unaligned_be16((int16_t)param_len, logs_cdb + 7);
916 if (verbose) {
917 char b[128];
918
919 pr2ws(" %s cdb: %s\n", cdb_s,
920 sg_get_command_str(logs_cdb, LOG_SELECT_CMDLEN, false,
921 sizeof(b), b));
922 }
923 if ((verbose > 1) && (param_len > 0)) {
924 pr2ws(" %s parameter list\n", cdb_s);
925 hex2stderr(paramp, param_len, -1);
926 }
927
928 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
929 return -1;
930 set_scsi_pt_cdb(ptvp, logs_cdb, sizeof(logs_cdb));
931 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
932 set_scsi_pt_data_out(ptvp, paramp, param_len);
933 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
934 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
935 if (-1 == ret) {
936 if (get_scsi_pt_transport_err(ptvp))
937 ret = SG_LIB_TRANSPORT_ERROR;
938 else
939 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
940 } else if (-2 == ret) {
941 switch (sense_cat) {
942 case SG_LIB_CAT_RECOVERED:
943 case SG_LIB_CAT_NO_SENSE:
944 ret = 0;
945 break;
946 default:
947 ret = sense_cat;
948 break;
949 }
950 } else
951 ret = 0;
952
953 destruct_scsi_pt_obj(ptvp);
954 return ret;
955 }
956
957 /* Invokes a SCSI START STOP UNIT command (SBC + MMC).
958 * Return of 0 -> success,
959 * various SG_LIB_CAT_* positive values or -1 -> other errors.
960 * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and
961 * format_layer_number(mmc) fields. They also overlap on the noflush(sbc)
962 * and fl(mmc) one bit field. This is the cause of the awkardly named
963 * pc_mod__fl_num and noflush__fl arguments to this function.
964 * */
965 static int
sg_ll_start_stop_unit_com(struct sg_pt_base * ptvp,int sg_fd,bool immed,int pc_mod__fl_num,int power_cond,bool noflush__fl,bool loej,bool start,bool noisy,int verbose)966 sg_ll_start_stop_unit_com(struct sg_pt_base * ptvp, int sg_fd, bool immed,
967 int pc_mod__fl_num, int power_cond, bool noflush__fl,
968 bool loej, bool start, bool noisy, int verbose)
969 {
970 static const char * const cdb_s = "start stop unit";
971 bool ptvp_given = false;
972 bool local_sense = true;
973 bool local_cdb = true;
974 int res, ret, sense_cat;
975 uint8_t ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0};
976 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
977
978 if (immed)
979 ssuBlk[1] = 0x1;
980 ssuBlk[3] = pc_mod__fl_num & 0xf; /* bits 2 and 3 are reserved in MMC */
981 ssuBlk[4] = ((power_cond & 0xf) << 4);
982 if (noflush__fl)
983 ssuBlk[4] |= 0x4;
984 if (loej)
985 ssuBlk[4] |= 0x2;
986 if (start)
987 ssuBlk[4] |= 0x1;
988 if (verbose) {
989 char b[128];
990
991 pr2ws(" %s cdb: %s\n", cdb_s,
992 sg_get_command_str(ssuBlk, sizeof(ssuBlk), false,
993 sizeof(b), b));
994 }
995 if (ptvp) {
996 ptvp_given = true;
997 partial_clear_scsi_pt_obj(ptvp);
998 if (get_scsi_pt_cdb_buf(ptvp))
999 local_cdb = false; /* N.B. Ignores locally built cdb */
1000 else
1001 set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
1002 if (get_scsi_pt_sense_buf(ptvp))
1003 local_sense = false;
1004 else
1005 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1006 } else {
1007 ptvp = construct_scsi_pt_obj_with_fd(sg_fd, verbose);
1008 if (NULL == ptvp)
1009 return sg_convert_errno(ENOMEM);
1010 set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk));
1011 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1012 }
1013 res = do_scsi_pt(ptvp, -1, START_PT_TIMEOUT, verbose);
1014 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_cat);
1015 if (-1 == ret) {
1016 if (get_scsi_pt_transport_err(ptvp))
1017 ret = SG_LIB_TRANSPORT_ERROR;
1018 else
1019 ret = sg_convert_errno(get_scsi_pt_os_err(ptvp));
1020 } else if (-2 == ret) {
1021 switch (sense_cat) {
1022 case SG_LIB_CAT_RECOVERED:
1023 case SG_LIB_CAT_NO_SENSE:
1024 ret = 0;
1025 break;
1026 default:
1027 ret = sense_cat;
1028 break;
1029 }
1030 } else
1031 ret = 0;
1032 if (ptvp_given) {
1033 if (local_sense) /* stop caller trying to access local sense */
1034 set_scsi_pt_sense(ptvp, NULL, 0);
1035 if (local_cdb)
1036 set_scsi_pt_cdb(ptvp, NULL, 0);
1037 } else {
1038 if (ptvp)
1039 destruct_scsi_pt_obj(ptvp);
1040 }
1041 return ret;
1042 }
1043
1044 int
sg_ll_start_stop_unit(int sg_fd,bool immed,int pc_mod__fl_num,int power_cond,bool noflush__fl,bool loej,bool start,bool noisy,int verbose)1045 sg_ll_start_stop_unit(int sg_fd, bool immed, int pc_mod__fl_num,
1046 int power_cond, bool noflush__fl, bool loej, bool start,
1047 bool noisy, int verbose)
1048 {
1049 return sg_ll_start_stop_unit_com(NULL, sg_fd, immed, pc_mod__fl_num,
1050 power_cond, noflush__fl, loej, start,
1051 noisy, verbose);
1052 }
1053
1054 int
sg_ll_start_stop_unit_pt(struct sg_pt_base * ptvp,bool immed,int pc_mod__fl_num,int power_cond,bool noflush__fl,bool loej,bool start,bool noisy,int verbose)1055 sg_ll_start_stop_unit_pt(struct sg_pt_base * ptvp, bool immed,
1056 int pc_mod__fl_num, int power_cond, bool noflush__fl,
1057 bool loej, bool start, bool noisy, int verbose)
1058 {
1059 return sg_ll_start_stop_unit_com(ptvp, -1, immed, pc_mod__fl_num,
1060 power_cond, noflush__fl, loej, start,
1061 noisy, verbose);
1062 }
1063
1064 /* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command
1065 * [was in SPC-3 but displaced from SPC-4 into SBC-3, MMC-5, SSC-3]
1066 * prevent==0 allows removal, prevent==1 prevents removal ...
1067 * Return of 0 -> success,
1068 * various SG_LIB_CAT_* positive values or -1 -> other errors */
1069 int
sg_ll_prevent_allow(int sg_fd,int prevent,bool noisy,int verbose)1070 sg_ll_prevent_allow(int sg_fd, int prevent, bool noisy, int verbose)
1071 {
1072 static const char * const cdb_s = "prevent allow medium removal";
1073 int res, ret, sense_cat;
1074 uint8_t p_cdb[PREVENT_ALLOW_CMDLEN] =
1075 {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0};
1076 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
1077 struct sg_pt_base * ptvp;
1078
1079 if ((prevent < 0) || (prevent > 3)) {
1080 pr2ws("prevent argument should be 0, 1, 2 or 3\n");
1081 return -1;
1082 }
1083 p_cdb[4] |= (prevent & 0x3);
1084 if (verbose) {
1085 char b[128];
1086
1087 pr2ws(" %s cdb: %s\n", cdb_s,
1088 sg_get_command_str(p_cdb, PREVENT_ALLOW_CMDLEN, false,
1089 sizeof(b), b));
1090 }
1091
1092 if (NULL == ((ptvp = create_pt_obj(cdb_s))))
1093 return -1;
1094 set_scsi_pt_cdb(ptvp, p_cdb, sizeof(p_cdb));
1095 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
1096 res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose);
1097 ret = sg_cmds_process_resp(ptvp, cdb_s, res, noisy, verbose, &sense_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 (sense_cat) {
1105 case SG_LIB_CAT_RECOVERED:
1106 case SG_LIB_CAT_NO_SENSE:
1107 ret = 0;
1108 break;
1109 default:
1110 ret = sense_cat;
1111 break;
1112 }
1113 } else
1114 ret = 0;
1115 destruct_scsi_pt_obj(ptvp);
1116 return ret;
1117 }
1118