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 /* NOTICE: 9 * On 5th October 2004 (v1.00) this file name was changed from sg_err.c 10 * to sg_lib.c and the previous GPL was changed to a FreeBSD license. 11 * The intention is to maintain this file and the related sg_lib.h file 12 * as open source and encourage their unencumbered use. 13 * 14 * CONTRIBUTIONS: 15 * This file started out as a copy of SCSI opcodes, sense keys and 16 * additional sense codes (ASC/ASCQ) kept in the Linux SCSI subsystem 17 * in the kernel source file: drivers/scsi/constant.c . That file 18 * bore this notice: "Copyright (C) 1993, 1994, 1995 Eric Youngdale" 19 * and a GPL notice. 20 * 21 * Much of the data in this file is derived from SCSI draft standards 22 * found at http://www.t10.org with the "SCSI Primary Commands-4" (SPC-4) 23 * being the central point of reference. 24 * 25 * Contributions: 26 * sense key specific field decoding [Trent Piepho 20031116] 27 * 28 */ 29 30 #define _POSIX_C_SOURCE 200809L /* for posix_memalign() */ 31 #define __STDC_FORMAT_MACROS 1 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <stdarg.h> 35 #include <stdbool.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <inttypes.h> 39 #include <errno.h> 40 41 #ifdef HAVE_CONFIG_H 42 #include "config.h" 43 #endif 44 45 #include "sg_lib.h" 46 #include "sg_lib_data.h" 47 #include "sg_unaligned.h" 48 #include "sg_pr2serr.h" 49 50 /* sg_lib_version_str (and datestamp) defined in sg_lib_data.c file */ 51 52 #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */ 53 54 FILE * sg_warnings_strm = NULL; /* would like to default to stderr */ 55 56 #if defined(__GNUC__) || defined(__clang__) 57 static int pr2ws(const char * fmt, ...) 58 __attribute__ ((format (printf, 1, 2))); 59 #else 60 static int pr2ws(const char * fmt, ...); 61 #endif 62 63 64 static int 65 pr2ws(const char * fmt, ...) 66 { 67 va_list args; 68 int n; 69 70 va_start(args, fmt); 71 n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args); 72 va_end(args); 73 return n; 74 } 75 76 #if defined(__GNUC__) || defined(__clang__) 77 static int scnpr(char * cp, int cp_max_len, const char * fmt, ...) 78 __attribute__ ((format (printf, 3, 4))); 79 #else 80 static int scnpr(char * cp, int cp_max_len, const char * fmt, ...); 81 #endif 82 83 /* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of 84 * functions. Returns number of chars placed in cp excluding the 85 * trailing null char. So for cp_max_len > 0 the return value is always 86 * < cp_max_len; for cp_max_len <= 1 the return value is 0 and no chars are 87 * written to cp. Note this means that when cp_max_len = 1, this function 88 * assumes that cp[0] is the null character and does nothing (and returns 89 * 0). Linux kernel has a similar function called scnprintf(). */ 90 static int 91 scnpr(char * cp, int cp_max_len, const char * fmt, ...) 92 { 93 va_list args; 94 int n; 95 96 if (cp_max_len < 2) 97 return 0; 98 va_start(args, fmt); 99 n = vsnprintf(cp, cp_max_len, fmt, args); 100 va_end(args); 101 return (n < cp_max_len) ? n : (cp_max_len - 1); 102 } 103 104 /* Simple ASCII printable (does not use locale), includes space and excludes 105 * DEL (0x7f). */ 106 static inline int my_isprint(int ch) 107 { 108 return ((ch >= ' ') && (ch < 0x7f)); 109 } 110 111 /* Searches 'arr' for match on 'value' then 'peri_type'. If matches 112 'value' but not 'peri_type' then yields first 'value' match entry. 113 Last element of 'arr' has NULL 'name'. If no match returns NULL. */ 114 static const struct sg_lib_value_name_t * 115 get_value_name(const struct sg_lib_value_name_t * arr, int value, 116 int peri_type) 117 { 118 const struct sg_lib_value_name_t * vp = arr; 119 const struct sg_lib_value_name_t * holdp; 120 121 if (peri_type < 0) 122 peri_type = 0; 123 for (; vp->name; ++vp) { 124 if (value == vp->value) { 125 if (peri_type == vp->peri_dev_type) 126 return vp; 127 holdp = vp; 128 while ((vp + 1)->name && (value == (vp + 1)->value)) { 129 ++vp; 130 if (peri_type == vp->peri_dev_type) 131 return vp; 132 } 133 return holdp; 134 } 135 } 136 return NULL; 137 } 138 139 /* If this function is not called, sg_warnings_strm will be NULL and all users 140 * (mainly fprintf() ) need to check and substitute stderr as required */ 141 void 142 sg_set_warnings_strm(FILE * warnings_strm) 143 { 144 sg_warnings_strm = warnings_strm; 145 } 146 147 #define CMD_NAME_LEN 128 148 149 void 150 sg_print_command(const unsigned char * command) 151 { 152 int k, sz; 153 char buff[CMD_NAME_LEN]; 154 155 sg_get_command_name(command, 0, CMD_NAME_LEN, buff); 156 buff[CMD_NAME_LEN - 1] = '\0'; 157 158 pr2ws("%s [", buff); 159 if (SG_VARIABLE_LENGTH_CMD == command[0]) 160 sz = command[7] + 8; 161 else 162 sz = sg_get_command_size(command[0]); 163 for (k = 0; k < sz; ++k) 164 pr2ws("%02x ", command[k]); 165 pr2ws("]\n"); 166 } 167 168 void 169 sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff) 170 { 171 const char * ccp = NULL; 172 bool unknown = false; 173 174 if ((NULL == buff) || (buff_len < 1)) 175 return; 176 else if (1 == buff_len) { 177 buff[0] = '\0'; 178 return; 179 } 180 scsi_status &= 0x7e; /* sanitize as much as possible */ 181 switch (scsi_status) { 182 case 0: ccp = "Good"; break; 183 case 0x2: ccp = "Check Condition"; break; 184 case 0x4: ccp = "Condition Met"; break; 185 case 0x8: ccp = "Busy"; break; 186 case 0x10: ccp = "Intermediate (obsolete)"; break; 187 case 0x14: ccp = "Intermediate-Condition Met (obsolete)"; break; 188 case 0x18: ccp = "Reservation Conflict"; break; 189 case 0x22: ccp = "Command Terminated (obsolete)"; break; 190 case 0x28: ccp = "Task set Full"; break; 191 case 0x30: ccp = "ACA Active"; break; 192 case 0x40: ccp = "Task Aborted"; break; 193 default: 194 unknown = true; 195 break; 196 } 197 if (unknown) 198 scnpr(buff, buff_len, "Unknown status [0x%x]", scsi_status); 199 else 200 scnpr(buff, buff_len, "%s", ccp); 201 } 202 203 void 204 sg_print_scsi_status(int scsi_status) 205 { 206 char buff[128]; 207 208 sg_get_scsi_status_str(scsi_status, sizeof(buff) - 1, buff); 209 buff[sizeof(buff) - 1] = '\0'; 210 pr2ws("%s ", buff); 211 } 212 213 /* Get sense key from sense buffer. If successful returns a sense key value 214 * between 0 and 15. If sense buffer cannot be decode, returns -1 . */ 215 int 216 sg_get_sense_key(const unsigned char * sbp, int sb_len) 217 { 218 if ((NULL == sbp) || (sb_len < 2)) 219 return -1; 220 switch (sbp[0] & 0x7f) { 221 case 0x70: 222 case 0x71: 223 return (sb_len < 3) ? -1 : (sbp[2] & 0xf); 224 case 0x72: 225 case 0x73: 226 return sbp[1] & 0xf; 227 default: 228 return -1; 229 } 230 } 231 232 /* Yield string associated with sense_key value. Returns 'buff'. */ 233 char * 234 sg_get_sense_key_str(int sense_key, int buff_len, char * buff) 235 { 236 if (1 == buff_len) { 237 buff[0] = '\0'; 238 return buff; 239 } 240 if ((sense_key >= 0) && (sense_key < 16)) 241 scnpr(buff, buff_len, "%s", sg_lib_sense_key_desc[sense_key]); 242 else 243 scnpr(buff, buff_len, "invalid value: 0x%x", sense_key); 244 return buff; 245 } 246 247 /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */ 248 char * 249 sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff) 250 { 251 int k, num, rlen; 252 bool found = false; 253 struct sg_lib_asc_ascq_t * eip; 254 struct sg_lib_asc_ascq_range_t * ei2p; 255 256 if (1 == buff_len) { 257 buff[0] = '\0'; 258 return buff; 259 } 260 for (k = 0; sg_lib_asc_ascq_range[k].text; ++k) { 261 ei2p = &sg_lib_asc_ascq_range[k]; 262 if ((ei2p->asc == asc) && 263 (ascq >= ei2p->ascq_min) && 264 (ascq <= ei2p->ascq_max)) { 265 found = true; 266 num = scnpr(buff, buff_len, "Additional sense: "); 267 rlen = buff_len - num; 268 scnpr(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq); 269 } 270 } 271 if (found) 272 return buff; 273 274 for (k = 0; sg_lib_asc_ascq[k].text; ++k) { 275 eip = &sg_lib_asc_ascq[k]; 276 if (eip->asc == asc && 277 eip->ascq == ascq) { 278 found = true; 279 scnpr(buff, buff_len, "Additional sense: %s", eip->text); 280 } 281 } 282 if (! found) { 283 if (asc >= 0x80) 284 scnpr(buff, buff_len, "vendor specific ASC=%02x, ASCQ=%02x " 285 "(hex)", asc, ascq); 286 else if (ascq >= 0x80) 287 scnpr(buff, buff_len, "ASC=%02x, vendor specific qualification " 288 "ASCQ=%02x (hex)", asc, ascq); 289 else 290 scnpr(buff, buff_len, "ASC=%02x, ASCQ=%02x (hex)", asc, ascq); 291 } 292 return buff; 293 } 294 295 /* Attempt to find the first SCSI sense data descriptor that matches the 296 * given 'desc_type'. If found return pointer to start of sense data 297 * descriptor; otherwise (including fixed format sense data) returns NULL. */ 298 const unsigned char * 299 sg_scsi_sense_desc_find(const unsigned char * sbp, int sb_len, 300 int desc_type) 301 { 302 int add_sb_len, add_d_len, desc_len, k; 303 const unsigned char * descp; 304 305 if ((sb_len < 8) || (0 == (add_sb_len = sbp[7]))) 306 return NULL; 307 if ((sbp[0] < 0x72) || (sbp[0] > 0x73)) 308 return NULL; 309 add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8); 310 descp = &sbp[8]; 311 for (desc_len = 0, k = 0; k < add_sb_len; k += desc_len) { 312 descp += desc_len; 313 add_d_len = (k < (add_sb_len - 1)) ? descp[1]: -1; 314 desc_len = add_d_len + 2; 315 if (descp[0] == desc_type) 316 return descp; 317 if (add_d_len < 0) /* short descriptor ?? */ 318 break; 319 } 320 return NULL; 321 } 322 323 /* Returns true if valid bit set, false if valid bit clear. Irrespective the 324 * information field is written out via 'info_outp' (except when it is 325 * NULL). Handles both fixed and descriptor sense formats. */ 326 bool 327 sg_get_sense_info_fld(const unsigned char * sbp, int sb_len, 328 uint64_t * info_outp) 329 { 330 const unsigned char * bp; 331 uint64_t ull; 332 333 if (info_outp) 334 *info_outp = 0; 335 if (sb_len < 7) 336 return false; 337 switch (sbp[0] & 0x7f) { 338 case 0x70: 339 case 0x71: 340 if (info_outp) 341 *info_outp = sg_get_unaligned_be32(sbp + 3); 342 return !!(sbp[0] & 0x80); 343 case 0x72: 344 case 0x73: 345 bp = sg_scsi_sense_desc_find(sbp, sb_len, 0 /* info desc */); 346 if (bp && (0xa == bp[1])) { 347 ull = sg_get_unaligned_be64(bp + 4); 348 if (info_outp) 349 *info_outp = ull; 350 return !!(bp[2] & 0x80); /* since spc3r23 should be set */ 351 } else 352 return false; 353 default: 354 return false; 355 } 356 } 357 358 /* Returns true if fixed format or command specific information descriptor 359 * is found in the descriptor sense; else false. If available the command 360 * specific information field (4 byte integer in fixed format, 8 byte 361 * integer in descriptor format) is written out via 'cmd_spec_outp'. 362 * Handles both fixed and descriptor sense formats. */ 363 bool 364 sg_get_sense_cmd_spec_fld(const unsigned char * sbp, int sb_len, 365 uint64_t * cmd_spec_outp) 366 { 367 const unsigned char * bp; 368 369 if (cmd_spec_outp) 370 *cmd_spec_outp = 0; 371 if (sb_len < 7) 372 return false; 373 switch (sbp[0] & 0x7f) { 374 case 0x70: 375 case 0x71: 376 if (cmd_spec_outp) 377 *cmd_spec_outp = sg_get_unaligned_be32(sbp + 8); 378 return true; 379 case 0x72: 380 case 0x73: 381 bp = sg_scsi_sense_desc_find(sbp, sb_len, 382 1 /* command specific info desc */); 383 if (bp && (0xa == bp[1])) { 384 if (cmd_spec_outp) 385 *cmd_spec_outp = sg_get_unaligned_be64(bp + 4); 386 return true; 387 } else 388 return false; 389 default: 390 return false; 391 } 392 } 393 394 /* Returns true if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set. 395 * In descriptor format if the stream commands descriptor not found 396 * then returns false. Writes true or false corresponding to these bits to 397 * the last three arguments if they are non-NULL. */ 398 bool 399 sg_get_sense_filemark_eom_ili(const unsigned char * sbp, int sb_len, 400 bool * filemark_p, bool * eom_p, bool * ili_p) 401 { 402 const unsigned char * bp; 403 404 if (sb_len < 7) 405 return false; 406 switch (sbp[0] & 0x7f) { 407 case 0x70: 408 case 0x71: 409 if (sbp[2] & 0xe0) { 410 if (filemark_p) 411 *filemark_p = !!(sbp[2] & 0x80); 412 if (eom_p) 413 *eom_p = !!(sbp[2] & 0x40); 414 if (ili_p) 415 *ili_p = !!(sbp[2] & 0x20); 416 return true; 417 } else 418 return false; 419 case 0x72: 420 case 0x73: 421 /* Look for stream commands sense data descriptor */ 422 bp = sg_scsi_sense_desc_find(sbp, sb_len, 4); 423 if (bp && (bp[1] >= 2)) { 424 if (bp[3] & 0xe0) { 425 if (filemark_p) 426 *filemark_p = !!(bp[3] & 0x80); 427 if (eom_p) 428 *eom_p = !!(bp[3] & 0x40); 429 if (ili_p) 430 *ili_p = !!(bp[3] & 0x20); 431 return true; 432 } 433 } 434 return false; 435 default: 436 return false; 437 } 438 } 439 440 /* Returns true if SKSV is set and sense key is NO_SENSE or NOT_READY. Also 441 * returns true if progress indication sense data descriptor found. Places 442 * progress field from sense data where progress_outp points. If progress 443 * field is not available returns false and *progress_outp is unaltered. 444 * Handles both fixed and descriptor sense formats. 445 * Hint: if true is returned *progress_outp may be multiplied by 100 then 446 * divided by 65536 to get the percentage completion. */ 447 bool 448 sg_get_sense_progress_fld(const unsigned char * sbp, int sb_len, 449 int * progress_outp) 450 { 451 const unsigned char * bp; 452 int sk, sk_pr; 453 454 if (sb_len < 7) 455 return false; 456 switch (sbp[0] & 0x7f) { 457 case 0x70: 458 case 0x71: 459 sk = (sbp[2] & 0xf); 460 if ((sb_len < 18) || 461 ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk))) 462 return false; 463 if (sbp[15] & 0x80) { /* SKSV bit set */ 464 if (progress_outp) 465 *progress_outp = sg_get_unaligned_be16(sbp + 16); 466 return true; 467 } else 468 return false; 469 case 0x72: 470 case 0x73: 471 /* sense key specific progress (0x2) or progress descriptor (0xa) */ 472 sk = (sbp[1] & 0xf); 473 sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk); 474 if (sk_pr && ((bp = sg_scsi_sense_desc_find(sbp, sb_len, 2))) && 475 (0x6 == bp[1]) && (0x80 & bp[4])) { 476 if (progress_outp) 477 *progress_outp = sg_get_unaligned_be16(bp + 5); 478 return true; 479 } else if (((bp = sg_scsi_sense_desc_find(sbp, sb_len, 0xa))) && 480 ((0x6 == bp[1]))) { 481 if (progress_outp) 482 *progress_outp = sg_get_unaligned_be16(bp + 6); 483 return true; 484 } else 485 return false; 486 default: 487 return false; 488 } 489 } 490 491 char * 492 sg_get_pdt_str(int pdt, int buff_len, char * buff) 493 { 494 if ((pdt < 0) || (pdt > 31)) 495 scnpr(buff, buff_len, "bad pdt"); 496 else 497 scnpr(buff, buff_len, "%s", sg_lib_pdt_strs[pdt]); 498 return buff; 499 } 500 501 int 502 sg_lib_pdt_decay(int pdt) 503 { 504 if ((pdt < 0) || (pdt > 31)) 505 return 0; 506 return sg_lib_pdt_decay_arr[pdt]; 507 } 508 509 char * 510 sg_get_trans_proto_str(int tpi, int buff_len, char * buff) 511 { 512 if ((tpi < 0) || (tpi > 15)) 513 scnpr(buff, buff_len, "bad tpi"); 514 else 515 scnpr(buff, buff_len, "%s", sg_lib_transport_proto_strs[tpi]); 516 return buff; 517 } 518 519 #define TRANSPORT_ID_MIN_LEN 24 520 521 char * 522 sg_decode_transportid_str(const char * lip, unsigned char * bp, int bplen, 523 bool only_one, int blen, char * b) 524 { 525 int proto_id, num, k, n, normal_len, tpid_format; 526 uint64_t ull; 527 int bump; 528 529 if ((NULL == b) || (blen < 1)) 530 return b; 531 else if (1 == blen) { 532 b[0] = '\0'; 533 return b; 534 } 535 if (NULL == lip) 536 lip = ""; 537 bump = TRANSPORT_ID_MIN_LEN; /* should be overwritten in all loop paths */ 538 for (k = 0, n = 0; bplen > 0; ++k, bp += bump, bplen -= bump) { 539 if ((k > 0) && only_one) 540 break; 541 if ((bplen < 24) || (0 != (bplen % 4))) 542 n += scnpr(b + n, blen - n, "%sTransport Id short or not " 543 "multiple of 4 [length=%d]:\n", lip, blen); 544 else 545 n += scnpr(b + n, blen - n, "%sTransport Id of initiator:\n", 546 lip); 547 tpid_format = ((bp[0] >> 6) & 0x3); 548 proto_id = (bp[0] & 0xf); 549 normal_len = (bplen > TRANSPORT_ID_MIN_LEN) ? 550 TRANSPORT_ID_MIN_LEN : bplen; 551 switch (proto_id) { 552 case TPROTO_FCP: /* Fibre channel */ 553 n += scnpr(b + n, blen - n, "%s FCP-2 World Wide Name:\n", lip); 554 if (0 != tpid_format) 555 n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: " 556 "%d]\n", lip, tpid_format); 557 n += hex2str(bp + 8, 8, lip, 1, blen - n, b + n); 558 bump = TRANSPORT_ID_MIN_LEN; 559 break; 560 case TPROTO_SPI: /* Scsi Parallel Interface, obsolete */ 561 n += scnpr(b + n, blen - n, "%s Parallel SCSI initiator SCSI " 562 "address: 0x%x\n", lip, sg_get_unaligned_be16(bp + 2)); 563 if (0 != tpid_format) 564 n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: " 565 "%d]\n", lip, tpid_format); 566 n += scnpr(b + n, blen - n, "%s relative port number (of " 567 "corresponding target): 0x%x\n", lip, 568 sg_get_unaligned_be16(bp + 6)); 569 bump = TRANSPORT_ID_MIN_LEN; 570 break; 571 case TPROTO_SSA: 572 n += scnpr(b + n, blen - n, "%s SSA (transport id not " 573 "defined):\n", lip); 574 n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip, 575 tpid_format); 576 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 577 bump = TRANSPORT_ID_MIN_LEN; 578 break; 579 case TPROTO_1394: /* IEEE 1394 */ 580 n += scnpr(b + n, blen - n, "%s IEEE 1394 EUI-64 name:\n", lip); 581 if (0 != tpid_format) 582 n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: " 583 "%d]\n", lip, tpid_format); 584 n += hex2str(&bp[8], 8, lip, 1, blen - n, b + n); 585 bump = TRANSPORT_ID_MIN_LEN; 586 break; 587 case TPROTO_SRP: /* SCSI over RDMA */ 588 n += scnpr(b + n, blen - n, "%s RDMA initiator port " 589 "identifier:\n", lip); 590 if (0 != tpid_format) 591 n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: " 592 "%d]\n", lip, tpid_format); 593 n += hex2str(bp + 8, 16, lip, 1, blen - n, b + n); 594 bump = TRANSPORT_ID_MIN_LEN; 595 break; 596 case TPROTO_ISCSI: 597 n += scnpr(b + n, blen - n, "%s iSCSI ", lip); 598 num = sg_get_unaligned_be16(bp + 2); 599 if (0 == tpid_format) 600 n += scnpr(b + n, blen - n, "name: %.*s\n", num, &bp[4]); 601 else if (1 == tpid_format) 602 n += scnpr(b + n, blen - n, "world wide unique port id: " 603 "%.*s\n", num, &bp[4]); 604 else { 605 n += scnpr(b + n, blen - n, " [Unexpected TPID format: " 606 "%d]\n", tpid_format); 607 n += hex2str(bp, num + 4, lip, 0, blen - n, b + n); 608 } 609 bump = (((num + 4) < TRANSPORT_ID_MIN_LEN) ? 610 TRANSPORT_ID_MIN_LEN : num + 4); 611 break; 612 case TPROTO_SAS: 613 ull = sg_get_unaligned_be64(bp + 4); 614 n += scnpr(b + n, blen - n, "%s SAS address: 0x%" PRIx64 "\n", 615 lip, ull); 616 if (0 != tpid_format) 617 n += scnpr(b + n, blen - n, "%s [Unexpected TPID format: " 618 "%d]\n", lip, tpid_format); 619 bump = TRANSPORT_ID_MIN_LEN; 620 break; 621 case TPROTO_ADT: /* no TransportID defined by T10 yet */ 622 n += scnpr(b + n, blen - n, "%s ADT:\n", lip); 623 n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip, 624 tpid_format); 625 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 626 bump = TRANSPORT_ID_MIN_LEN; 627 break; 628 case TPROTO_ATA: /* no TransportID defined by T10 yet */ 629 n += scnpr(b + n, blen - n, "%s ATAPI:\n", lip); 630 n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip, 631 tpid_format); 632 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 633 bump = TRANSPORT_ID_MIN_LEN; 634 break; 635 case TPROTO_UAS: /* no TransportID defined by T10 yet */ 636 n += scnpr(b + n, blen - n, "%s UAS:\n", lip); 637 n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip, 638 tpid_format); 639 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 640 bump = TRANSPORT_ID_MIN_LEN; 641 break; 642 case TPROTO_SOP: 643 n += scnpr(b + n, blen - n, "%s SOP ", lip); 644 num = sg_get_unaligned_be16(bp + 2); 645 if (0 == tpid_format) 646 n += scnpr(b + n, blen - n, "Routing ID: 0x%x\n", num); 647 else { 648 n += scnpr(b + n, blen - n, " [Unexpected TPID format: " 649 "%d]\n", tpid_format); 650 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 651 } 652 bump = TRANSPORT_ID_MIN_LEN; 653 break; 654 case TPROTO_PCIE: /* no TransportID defined by T10 yet */ 655 n += scnpr(b + n, blen - n, "%s PCIE:\n", lip); 656 n += scnpr(b + n, blen - n, "%s TPID format: %d\n", lip, 657 tpid_format); 658 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 659 bump = TRANSPORT_ID_MIN_LEN; 660 break; 661 case TPROTO_NONE: /* no TransportID defined by T10 */ 662 n += scnpr(b + n, blen - n, "%s No specified protocol\n", lip); 663 /* n += hex2str(bp, ((bplen > 24) ? 24 : bplen), 664 * lip, 0, blen - n, b + n); */ 665 bump = TRANSPORT_ID_MIN_LEN; 666 break; 667 default: 668 n += scnpr(b + n, blen - n, "%s unknown protocol id=0x%x " 669 "TPID format=%d\n", lip, proto_id, tpid_format); 670 n += hex2str(bp, normal_len, lip, 1, blen - n, b + n); 671 bump = TRANSPORT_ID_MIN_LEN; 672 break; 673 } 674 } 675 return b; 676 } 677 678 679 static const char * desig_code_set_str_arr[] = 680 { 681 "Reserved [0x0]", 682 "Binary", 683 "ASCII", 684 "UTF-8", 685 "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]", 686 "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]", 687 "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]", 688 }; 689 690 const char * 691 sg_get_desig_code_set_str(int val) 692 { 693 if ((val >= 0) && (val < 16)) 694 return desig_code_set_str_arr[val]; 695 else 696 return NULL; 697 } 698 699 static const char * desig_assoc_str_arr[] = 700 { 701 "Addressed logical unit", 702 "Target port", /* that received request; unless SCSI ports VPD */ 703 "Target device that contains addressed lu", 704 "Reserved [0x3]", 705 }; 706 707 const char * 708 sg_get_desig_assoc_str(int val) 709 { 710 if ((val >= 0) && (val < 4)) 711 return desig_assoc_str_arr[val]; 712 else 713 return NULL; 714 } 715 716 static const char * desig_type_str_arr[] = 717 { 718 "vendor specific [0x0]", 719 "T10 vendor identification", 720 "EUI-64 based", 721 "NAA", 722 "Relative target port", 723 "Target port group", /* spc4r09: _primary_ target port group */ 724 "Logical unit group", 725 "MD5 logical unit identifier", 726 "SCSI name string", 727 "Protocol specific port identifier", /* spc4r36 */ 728 "UUID identifier", /* spc5r08 */ 729 "Reserved [0xb]", 730 "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]", 731 }; 732 733 const char * 734 sg_get_desig_type_str(int val) 735 { 736 if ((val >= 0) && (val < 16)) 737 return desig_type_str_arr[val]; 738 else 739 return NULL; 740 } 741 742 int 743 sg_get_designation_descriptor_str(const char * lip, const unsigned char * ddp, 744 int dd_len, bool print_assoc, bool do_long, 745 int blen, char * b) 746 { 747 int m, p_id, piv, c_set, assoc, desig_type, ci_off, c_id, d_id, naa; 748 int vsi, k, n, dlen; 749 const unsigned char * ip; 750 uint64_t vsei; 751 uint64_t id_ext; 752 char e[64]; 753 const char * cp; 754 755 n = 0; 756 if (NULL == lip) 757 lip = ""; 758 if (dd_len < 4) { 759 n += scnpr(b + n, blen - n, "%sdesignator desc too short: got " 760 "length of %d want 4 or more\n", lip, dd_len); 761 return n; 762 } 763 dlen = ddp[3]; 764 if (dlen > (dd_len - 4)) { 765 n += scnpr(b + n, blen - n, "%sdesignator too long: says it is %d " 766 "bytes, but given %d bytes\n", lip, dlen, dd_len - 4); 767 return n; 768 } 769 ip = ddp + 4; 770 p_id = ((ddp[0] >> 4) & 0xf); 771 c_set = (ddp[0] & 0xf); 772 piv = ((ddp[1] & 0x80) ? 1 : 0); 773 assoc = ((ddp[1] >> 4) & 0x3); 774 desig_type = (ddp[1] & 0xf); 775 if (print_assoc && ((cp = sg_get_desig_assoc_str(assoc)))) 776 n += scnpr(b + n, blen - n, "%s %s:\n", lip, cp); 777 n += scnpr(b + n, blen - n, "%s designator type: ", lip); 778 cp = sg_get_desig_type_str(desig_type); 779 if (cp) 780 n += scnpr(b + n, blen - n, "%s", cp); 781 n += scnpr(b + n, blen - n, ", code set: "); 782 cp = sg_get_desig_code_set_str(c_set); 783 if (cp) 784 n += scnpr(b + n, blen - n, "%s", cp); 785 n += scnpr(b + n, blen - n, "\n"); 786 if (piv && ((1 == assoc) || (2 == assoc))) 787 n += scnpr(b + n, blen - n, "%s transport: %s\n", lip, 788 sg_get_trans_proto_str(p_id, sizeof(e), e)); 789 /* printf(" associated with the %s\n", sdparm_assoc_arr[assoc]); */ 790 switch (desig_type) { 791 case 0: /* vendor specific */ 792 k = 0; 793 if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */ 794 for (k = 0; (k < dlen) && my_isprint(ip[k]); ++k) 795 ; 796 if (k >= dlen) 797 k = 1; 798 } 799 if (k) 800 n += scnpr(b + n, blen - n, "%s vendor specific: %.*s\n", 801 lip, dlen, ip); 802 else { 803 n += scnpr(b + n, blen - n, "%s vendor specific:\n", lip); 804 n += hex2str(ip, dlen, lip, 0, blen - n, b + n); 805 } 806 break; 807 case 1: /* T10 vendor identification */ 808 n += scnpr(b + n, blen - n, "%s vendor id: %.8s\n", lip, ip); 809 if (dlen > 8) { 810 if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ 811 n += scnpr(b + n, blen - n, "%s vendor specific: " 812 "%.*s\n", lip, dlen - 8, ip + 8); 813 } else { 814 n += scnpr(b + n, blen - n, "%s vendor specific: 0x", 815 lip); 816 for (m = 8; m < dlen; ++m) 817 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 818 n += scnpr(b + n, blen - n, "\n"); 819 } 820 } 821 break; 822 case 2: /* EUI-64 based */ 823 if (! do_long) { 824 if ((8 != dlen) && (12 != dlen) && (16 != dlen)) { 825 n += scnpr(b + n, blen - n, "%s << expect 8, 12 and 16 " 826 "byte EUI, got %d >>\n", lip, dlen); 827 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 828 break; 829 } 830 n += scnpr(b + n, blen - n, "%s 0x", lip); 831 for (m = 0; m < dlen; ++m) 832 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 833 n += scnpr(b + n, blen - n, "\n"); 834 break; 835 } 836 n += scnpr(b + n, blen - n, "%s EUI-64 based %d byte " 837 "identifier\n", lip, dlen); 838 if (1 != c_set) { 839 n += scnpr(b + n, blen - n, "%s << expected binary code_set " 840 "(1) >>\n", lip); 841 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 842 break; 843 } 844 ci_off = 0; 845 if (16 == dlen) { 846 ci_off = 8; 847 id_ext = sg_get_unaligned_be64(ip); 848 n += scnpr(b + n, blen - n, "%s Identifier extension: 0x%" 849 PRIx64 "\n", lip, id_ext); 850 } else if ((8 != dlen) && (12 != dlen)) { 851 n += scnpr(b + n, blen - n, "%s << can only decode 8, 12 " 852 "and 16 byte ids >>\n", lip); 853 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 854 break; 855 } 856 c_id = sg_get_unaligned_be24(ip + ci_off); 857 n += scnpr(b + n, blen - n, "%s IEEE Company_id: 0x%x\n", lip, 858 c_id); 859 vsei = 0; 860 for (m = 0; m < 5; ++m) { 861 if (m > 0) 862 vsei <<= 8; 863 vsei |= ip[ci_off + 3 + m]; 864 } 865 n += scnpr(b + n, blen - n, "%s Vendor Specific Extension " 866 "Identifier: 0x%" PRIx64 "\n", lip, vsei); 867 if (12 == dlen) { 868 d_id = sg_get_unaligned_be32(ip + 8); 869 n += scnpr(b + n, blen - n, "%s Directory ID: 0x%x\n", lip, 870 d_id); 871 } 872 break; 873 case 3: /* NAA <n> */ 874 if (1 != c_set) { 875 n += scnpr(b + n, blen - n, "%s << unexpected code set %d " 876 "for NAA >>\n", lip, c_set); 877 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 878 break; 879 } 880 naa = (ip[0] >> 4) & 0xff; 881 switch (naa) { 882 case 2: /* NAA 2: IEEE Extended */ 883 if (8 != dlen) { 884 n += scnpr(b + n, blen - n, "%s << unexpected NAA 2 " 885 "identifier length: 0x%x >>\n", lip, dlen); 886 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 887 break; 888 } 889 d_id = (((ip[0] & 0xf) << 8) | ip[1]); 890 c_id = sg_get_unaligned_be24(ip + 2); 891 vsi = sg_get_unaligned_be24(ip + 5); 892 if (do_long) { 893 n += scnpr(b + n, blen - n, "%s NAA 2, vendor specific " 894 "identifier A: 0x%x\n", lip, d_id); 895 n += scnpr(b + n, blen - n, "%s IEEE Company_id: 0x%x\n", 896 lip, c_id); 897 n += scnpr(b + n, blen - n, "%s vendor specific " 898 "identifier B: 0x%x\n", lip, vsi); 899 n += scnpr(b + n, blen - n, "%s [0x", lip); 900 for (m = 0; m < 8; ++m) 901 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 902 n += scnpr(b + n, blen - n, "]\n"); 903 } 904 n += scnpr(b + n, blen - n, "%s 0x", lip); 905 for (m = 0; m < 8; ++m) 906 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 907 n += scnpr(b + n, blen - n, "\n"); 908 break; 909 case 3: /* NAA 3: Locally assigned */ 910 if (8 != dlen) { 911 n += scnpr(b + n, blen - n, "%s << unexpected NAA 3 " 912 "identifier length: 0x%x >>\n", lip, dlen); 913 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 914 break; 915 } 916 if (do_long) 917 n += scnpr(b + n, blen - n, "%s NAA 3, Locally " 918 "assigned:\n", lip); 919 n += scnpr(b + n, blen - n, "%s 0x", lip); 920 for (m = 0; m < 8; ++m) 921 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 922 n += scnpr(b + n, blen - n, "\n"); 923 break; 924 case 5: /* NAA 5: IEEE Registered */ 925 if (8 != dlen) { 926 n += scnpr(b + n, blen - n, "%s << unexpected NAA 5 " 927 "identifier length: 0x%x >>\n", lip, dlen); 928 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 929 break; 930 } 931 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | 932 (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); 933 vsei = ip[3] & 0xf; 934 for (m = 1; m < 5; ++m) { 935 vsei <<= 8; 936 vsei |= ip[3 + m]; 937 } 938 if (do_long) { 939 n += scnpr(b + n, blen - n, "%s NAA 5, IEEE " 940 "Company_id: 0x%x\n", lip, c_id); 941 n += scnpr(b + n, blen - n, "%s Vendor Specific " 942 "Identifier: 0x%" PRIx64 "\n", lip, vsei); 943 n += scnpr(b + n, blen - n, "%s [0x", lip); 944 for (m = 0; m < 8; ++m) 945 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 946 n += scnpr(b + n, blen - n, "]\n"); 947 } else { 948 n += scnpr(b + n, blen - n, "%s 0x", lip); 949 for (m = 0; m < 8; ++m) 950 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 951 n += scnpr(b + n, blen - n, "\n"); 952 } 953 break; 954 case 6: /* NAA 6: IEEE Registered extended */ 955 if (16 != dlen) { 956 n += scnpr(b + n, blen - n, "%s << unexpected NAA 6 " 957 "identifier length: 0x%x >>\n", lip, dlen); 958 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 959 break; 960 } 961 c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | 962 (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); 963 vsei = ip[3] & 0xf; 964 for (m = 1; m < 5; ++m) { 965 vsei <<= 8; 966 vsei |= ip[3 + m]; 967 } 968 if (do_long) { 969 n += scnpr(b + n, blen - n, "%s NAA 6, IEEE " 970 "Company_id: 0x%x\n", lip, c_id); 971 n += scnpr(b + n, blen - n, "%s Vendor Specific " 972 "Identifier: 0x%" PRIx64 "\n", lip, vsei); 973 vsei = sg_get_unaligned_be64(ip + 8); 974 n += scnpr(b + n, blen - n, "%s Vendor Specific " 975 "Identifier Extension: 0x%" PRIx64 "\n", lip, 976 vsei); 977 n += scnpr(b + n, blen - n, "%s [0x", lip); 978 for (m = 0; m < 16; ++m) 979 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 980 n += scnpr(b + n, blen - n, "]\n"); 981 } else { 982 n += scnpr(b + n, blen - n, "%s 0x", lip); 983 for (m = 0; m < 16; ++m) 984 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[m]); 985 n += scnpr(b + n, blen - n, "\n"); 986 } 987 break; 988 default: 989 n += scnpr(b + n, blen - n, "%s << unexpected NAA [0x%x] " 990 ">>\n", lip, naa); 991 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 992 break; 993 } 994 break; 995 case 4: /* Relative target port */ 996 if ((1 != c_set) || (1 != assoc) || (4 != dlen)) { 997 n += scnpr(b + n, blen - n, "%s << expected binary " 998 "code_set, target port association, length 4 >>\n", 999 lip); 1000 n += hex2str(ip, dlen, "", 1, blen - n, b + n); 1001 break; 1002 } 1003 d_id = sg_get_unaligned_be16(ip + 2); 1004 n += scnpr(b + n, blen - n, "%s Relative target port: 0x%x\n", 1005 lip, d_id); 1006 break; 1007 case 5: /* (primary) Target port group */ 1008 if ((1 != c_set) || (1 != assoc) || (4 != dlen)) { 1009 n += scnpr(b + n, blen - n, "%s << expected binary " 1010 "code_set, target port association, length 4 >>\n", 1011 lip); 1012 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 1013 break; 1014 } 1015 d_id = sg_get_unaligned_be16(ip + 2); 1016 n += scnpr(b + n, blen - n, "%s Target port group: 0x%x\n", lip, 1017 d_id); 1018 break; 1019 case 6: /* Logical unit group */ 1020 if ((1 != c_set) || (0 != assoc) || (4 != dlen)) { 1021 n += scnpr(b + n, blen - n, "%s << expected binary " 1022 "code_set, logical unit association, length 4 >>\n", 1023 lip); 1024 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 1025 break; 1026 } 1027 d_id = sg_get_unaligned_be16(ip + 2); 1028 n += scnpr(b + n, blen - n, "%s Logical unit group: 0x%x\n", lip, 1029 d_id); 1030 break; 1031 case 7: /* MD5 logical unit identifier */ 1032 if ((1 != c_set) || (0 != assoc)) { 1033 n += scnpr(b + n, blen - n, "%s << expected binary " 1034 "code_set, logical unit association >>\n", lip); 1035 n += hex2str(ip, dlen, "", 1, blen - n, b + n); 1036 break; 1037 } 1038 n += scnpr(b + n, blen - n, "%s MD5 logical unit identifier:\n", 1039 lip); 1040 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 1041 break; 1042 case 8: /* SCSI name string */ 1043 if (3 != c_set) { /* accept ASCII as subset of UTF-8 */ 1044 if (2 == c_set) { 1045 if (do_long) 1046 n += scnpr(b + n, blen - n, "%s << expected UTF-8, " 1047 "use ASCII >>\n", lip); 1048 } else { 1049 n += scnpr(b + n, blen - n, "%s << expected UTF-8 " 1050 "code_set >>\n", lip); 1051 n += hex2str(ip, dlen, lip, 0, blen - n, b + n); 1052 break; 1053 } 1054 } 1055 n += scnpr(b + n, blen - n, "%s SCSI name string:\n", lip); 1056 /* does %s print out UTF-8 ok?? 1057 * Seems to depend on the locale. Looks ok here with my 1058 * locale setting: en_AU.UTF-8 1059 */ 1060 n += scnpr(b + n, blen - n, "%s %.*s\n", lip, dlen, 1061 (const char *)ip); 1062 break; 1063 case 9: /* Protocol specific port identifier */ 1064 /* added in spc4r36, PIV must be set, proto_id indicates */ 1065 /* whether UAS (USB) or SOP (PCIe) or ... */ 1066 if (! piv) 1067 n += scnpr(b + n, blen - n, " %s >>>> Protocol specific " 1068 "port identifier expects protocol\n" 1069 "%s identifier to be valid and it is not\n", 1070 lip, lip); 1071 if (TPROTO_UAS == p_id) { 1072 n += scnpr(b + n, blen - n, "%s USB device address: 0x%x\n", 1073 lip, 0x7f & ip[0]); 1074 n += scnpr(b + n, blen - n, "%s USB interface number: " 1075 "0x%x\n", lip, ip[2]); 1076 } else if (TPROTO_SOP == p_id) { 1077 n += scnpr(b + n, blen - n, "%s PCIe routing ID, bus " 1078 "number: 0x%x\n", lip, ip[0]); 1079 n += scnpr(b + n, blen - n, "%s function number: 0x%x\n", 1080 lip, ip[1]); 1081 n += scnpr(b + n, blen - n, "%s [or device number: " 1082 "0x%x, function number: 0x%x]\n", lip, 1083 (0x1f & (ip[1] >> 3)), 0x7 & ip[1]); 1084 } else 1085 n += scnpr(b + n, blen - n, "%s >>>> unexpected protocol " 1086 "indentifier: %s\n%s with Protocol specific " 1087 "port identifier\n", lip, 1088 sg_get_trans_proto_str(p_id, sizeof(e), e), lip); 1089 break; 1090 case 0xa: /* UUID identifier */ 1091 if (1 != c_set) { 1092 n += scnpr(b + n, blen - n, "%s << expected binary " 1093 "code_set >>\n", lip); 1094 n += hex2str(ip, dlen, lip, 0, blen - n, b + n); 1095 break; 1096 } 1097 if ((1 != ((ip[0] >> 4) & 0xf)) || (18 != dlen)) { 1098 n += scnpr(b + n, blen - n, "%s << expected locally " 1099 "assigned UUID, 16 bytes long >>\n", lip); 1100 n += hex2str(ip, dlen, lip, 0, blen - n, b + n); 1101 break; 1102 } 1103 n += scnpr(b + n, blen - n, "%s Locally assigned UUID: ", lip); 1104 for (m = 0; m < 16; ++m) { 1105 if ((4 == m) || (6 == m) || (8 == m) || (10 == m)) 1106 n += scnpr(b + n, blen - n, "-"); 1107 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[2 + m]); 1108 } 1109 n += scnpr(b + n, blen - n, "\n"); 1110 if (do_long) { 1111 n += scnpr(b + n, blen - n, "%s [0x", lip); 1112 for (m = 0; m < 16; ++m) 1113 n += scnpr(b + n, blen - n, "%02x", (unsigned int)ip[2 + m]); 1114 n += scnpr(b + n, blen - n, "]\n"); 1115 } 1116 break; 1117 default: /* reserved */ 1118 n += scnpr(b + n, blen - n, "%s reserved designator=0x%x\n", lip, 1119 desig_type); 1120 n += hex2str(ip, dlen, lip, 1, blen - n, b + n); 1121 break; 1122 } 1123 return n; 1124 } 1125 1126 static int 1127 decode_sks(const char * lip, const unsigned char * descp, int add_d_len, 1128 int sense_key, bool * processedp, int blen, char * b) 1129 { 1130 int progress, pr, rem, n; 1131 1132 n = 0; 1133 if (NULL == lip) 1134 lip = ""; 1135 switch (sense_key) { 1136 case SPC_SK_ILLEGAL_REQUEST: 1137 if (add_d_len < 6) { 1138 n += scnpr(b + n, blen - n, "Field pointer: "); 1139 goto too_short; 1140 } 1141 /* abbreviate to fit on one line */ 1142 n += scnpr(b + n, blen - n, "Field pointer:\n"); 1143 n += scnpr(b + n, blen - n, "%s Error in %s: byte %d", lip, 1144 (descp[4] & 0x40) ? "Command" : 1145 "Data parameters", 1146 sg_get_unaligned_be16(descp + 5)); 1147 if (descp[4] & 0x08) { 1148 n += scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07); 1149 } else 1150 n += scnpr(b + n, blen - n, "\n"); 1151 break; 1152 case SPC_SK_HARDWARE_ERROR: 1153 case SPC_SK_MEDIUM_ERROR: 1154 case SPC_SK_RECOVERED_ERROR: 1155 n += scnpr(b + n, blen - n, "Actual retry count: "); 1156 if (add_d_len < 6) 1157 goto too_short; 1158 n += scnpr(b + n, blen - n,"%u\n", sg_get_unaligned_be16(descp + 5)); 1159 break; 1160 case SPC_SK_NO_SENSE: 1161 case SPC_SK_NOT_READY: 1162 n += scnpr(b + n, blen - n, "Progress indication: "); 1163 if (add_d_len < 6) 1164 goto too_short; 1165 progress = sg_get_unaligned_be16(descp + 5); 1166 pr = (progress * 100) / 65536; 1167 rem = ((progress * 100) % 65536) / 656; 1168 n += scnpr(b + n, blen - n, "%d.%02d%%\n", pr, rem); 1169 break; 1170 case SPC_SK_COPY_ABORTED: 1171 n += scnpr(b + n, blen - n, "Segment pointer:\n"); 1172 if (add_d_len < 6) 1173 goto too_short; 1174 n += scnpr(b + n, blen - n, "%s Relative to start of %s, byte " 1175 "%d", lip, (descp[4] & 0x20) ? "segment descriptor" : 1176 "parameter list", 1177 sg_get_unaligned_be16(descp + 5)); 1178 if (descp[4] & 0x08) 1179 n += scnpr(b + n, blen - n, " bit %d\n", descp[4] & 0x07); 1180 else 1181 n += scnpr(b + n, blen - n, "\n"); 1182 break; 1183 case SPC_SK_UNIT_ATTENTION: 1184 n += scnpr(b + n, blen - n, "Unit attention condition queue:\n"); 1185 n += scnpr(b + n, blen - n, "%s overflow flag is %d\n", lip, 1186 !!(descp[4] & 0x1)); 1187 break; 1188 default: 1189 n += scnpr(b + n, blen - n, "Sense_key: 0x%x unexpected\n", 1190 sense_key); 1191 *processedp = false; 1192 break; 1193 } 1194 return n; 1195 1196 too_short: 1197 n += scnpr(b + n, blen - n, "%s\n", " >> descriptor too short"); 1198 *processedp = false; 1199 return n; 1200 } 1201 1202 #define TPGS_STATE_OPTIMIZED 0x0 1203 #define TPGS_STATE_NONOPTIMIZED 0x1 1204 #define TPGS_STATE_STANDBY 0x2 1205 #define TPGS_STATE_UNAVAILABLE 0x3 1206 #define TPGS_STATE_OFFLINE 0xe 1207 #define TPGS_STATE_TRANSITIONING 0xf 1208 1209 static int 1210 decode_tpgs_state(int st, char * b, int blen) 1211 { 1212 switch (st) { 1213 case TPGS_STATE_OPTIMIZED: 1214 return scnpr(b, blen, "active/optimized"); 1215 case TPGS_STATE_NONOPTIMIZED: 1216 return scnpr(b, blen, "active/non optimized"); 1217 case TPGS_STATE_STANDBY: 1218 return scnpr(b, blen, "standby"); 1219 case TPGS_STATE_UNAVAILABLE: 1220 return scnpr(b, blen, "unavailable"); 1221 case TPGS_STATE_OFFLINE: 1222 return scnpr(b, blen, "offline"); 1223 case TPGS_STATE_TRANSITIONING: 1224 return scnpr(b, blen, "transitioning between states"); 1225 default: 1226 return scnpr(b, blen, "unknown: 0x%x", st); 1227 } 1228 } 1229 1230 static int 1231 uds_referral_descriptor_str(char * b, int blen, const unsigned char * dp, 1232 int alen, const char * lip) 1233 { 1234 int n = 0; 1235 int dlen = alen - 2; 1236 int k, j, g, f, tpgd; 1237 const unsigned char * tp; 1238 uint64_t ull; 1239 char c[40]; 1240 1241 if (NULL == lip) 1242 lip = ""; 1243 n += scnpr(b + n, blen - n, "%s Not all referrals: %d\n", lip, 1244 !!(dp[2] & 0x1)); 1245 dp += 4; 1246 for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) { 1247 tpgd = dp[3]; 1248 g = (tpgd * 4) + 20; 1249 n += scnpr(b + n, blen - n, "%s Descriptor %d\n", lip, f); 1250 if ((k + g) > dlen) { 1251 n += scnpr(b + n, blen - n, "%s truncated descriptor, " 1252 "stop\n", lip); 1253 return n; 1254 } 1255 ull = sg_get_unaligned_be64(dp + 4); 1256 n += scnpr(b + n, blen - n, "%s first uds LBA: 0x%" PRIx64 "\n", 1257 lip, ull); 1258 ull = sg_get_unaligned_be64(dp + 12); 1259 n += scnpr(b + n, blen - n, "%s last uds LBA: 0x%" PRIx64 "\n", 1260 lip, ull); 1261 for (j = 0; j < tpgd; ++j) { 1262 tp = dp + 20 + (j * 4); 1263 decode_tpgs_state(tp[0] & 0xf, c, sizeof(c)); 1264 n += scnpr(b + n, blen - n, "%s tpg: %d state: %s\n", 1265 lip, sg_get_unaligned_be16(tp + 2), c); 1266 } 1267 } 1268 return n; 1269 } 1270 1271 static const char * dd_usage_reason_str_arr[] = { 1272 "Unknown", 1273 "resend this and further commands to:", 1274 "resend this command to:", 1275 "new subsiduary lu added to this administrative lu:", 1276 "administrative lu associated with a preferred binding:", 1277 }; 1278 1279 1280 /* Decode descriptor format sense descriptors (assumes sense buffer is 1281 * in descriptor format) */ 1282 int 1283 sg_get_sense_descriptors_str(const char * lip, const unsigned char * sbp, 1284 int sb_len, int blen, char * b) 1285 { 1286 int add_sb_len, add_d_len, desc_len, k, j, sense_key; 1287 int n, progress, pr, rem; 1288 bool processed; 1289 const unsigned char * descp; 1290 const char * dtsp = " >> descriptor too short"; 1291 const char * eccp = "Extended copy command"; 1292 const char * ddp = "destination device"; 1293 char z[64]; 1294 1295 if ((NULL == b) || (blen <= 0)) 1296 return 0; 1297 b[0] = '\0'; 1298 if (lip) 1299 scnpr(z, sizeof(z), "%.60s ", lip); 1300 else 1301 scnpr(z, sizeof(z), " "); 1302 if ((sb_len < 8) || (0 == (add_sb_len = sbp[7]))) 1303 return 0; 1304 add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8); 1305 sense_key = (sbp[1] & 0xf); 1306 1307 for (descp = (sbp + 8), k = 0, n = 0; 1308 (k < add_sb_len) && (n < blen); 1309 k += desc_len, descp += desc_len) { 1310 add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1; 1311 if ((k + add_d_len + 2) > add_sb_len) 1312 add_d_len = add_sb_len - k - 2; 1313 desc_len = add_d_len + 2; 1314 n += scnpr(b + n, blen - n, "%s Descriptor type: ", lip); 1315 processed = true; 1316 switch (descp[0]) { 1317 case 0: 1318 n += scnpr(b + n, blen - n, "Information: "); 1319 if ((add_d_len >= 10) && (0x80 & descp[2])) { 1320 n += scnpr(b + n, blen - n, "0x"); 1321 for (j = 0; j < 8; ++j) 1322 n += scnpr(b + n, blen - n, "%02x", descp[4 + j]); 1323 n += scnpr(b + n, blen - n, "\n"); 1324 } else { 1325 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1326 processed = false; 1327 } 1328 break; 1329 case 1: 1330 n += scnpr(b + n, blen - n, "Command specific: "); 1331 if (add_d_len >= 10) { 1332 n += scnpr(b + n, blen - n, "0x"); 1333 for (j = 0; j < 8; ++j) 1334 n += scnpr(b + n, blen - n, "%02x", descp[4 + j]); 1335 n += scnpr(b + n, blen - n, "\n"); 1336 } else { 1337 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1338 processed = false; 1339 } 1340 break; 1341 case 2: /* Sense Key Specific */ 1342 n += scnpr(b + n, blen - n, "Sense key specific: "); 1343 n += decode_sks(lip, descp, add_d_len, sense_key, &processed, 1344 blen - n, b + n); 1345 break; 1346 case 3: 1347 n += scnpr(b + n, blen - n, "Field replaceable unit code: "); 1348 if (add_d_len >= 2) 1349 n += scnpr(b + n, blen - n, "0x%x\n", descp[3]); 1350 else { 1351 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1352 processed = false; 1353 } 1354 break; 1355 case 4: 1356 n += scnpr(b + n, blen - n, "Stream commands: "); 1357 if (add_d_len >= 2) { 1358 if (descp[3] & 0x80) 1359 n += scnpr(b + n, blen - n, "FILEMARK"); 1360 if (descp[3] & 0x40) 1361 n += scnpr(b + n, blen - n, "End Of Medium (EOM)"); 1362 if (descp[3] & 0x20) 1363 n += scnpr(b + n, blen - n, "Incorrect Length Indicator " 1364 "(ILI)"); 1365 n += scnpr(b + n, blen - n, "\n"); 1366 } else { 1367 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1368 processed = false; 1369 } 1370 break; 1371 case 5: 1372 n += scnpr(b + n, blen - n, "Block commands: "); 1373 if (add_d_len >= 2) 1374 n += scnpr(b + n, blen - n, "Incorrect Length Indicator " 1375 "(ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear"); 1376 else { 1377 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1378 processed = false; 1379 } 1380 break; 1381 case 6: 1382 n += scnpr(b + n, blen - n, "OSD object identification\n"); 1383 processed = false; 1384 break; 1385 case 7: 1386 n += scnpr(b + n, blen - n, "OSD response integrity check " 1387 "value\n"); 1388 processed = false; 1389 break; 1390 case 8: 1391 n += scnpr(b + n, blen - n, "OSD attribute identification\n"); 1392 processed = false; 1393 break; 1394 case 9: /* this is defined in SAT (SAT-2) */ 1395 n += scnpr(b + n, blen - n, "ATA Status Return: "); 1396 if (add_d_len >= 12) { 1397 int extend, count; 1398 1399 extend = descp[2] & 1; 1400 count = descp[5] + (extend ? (descp[4] << 8) : 0); 1401 n += scnpr(b + n, blen - n, "extend=%d error=0x%x \n%s" 1402 " count=0x%x ", extend, descp[3], lip, 1403 count); 1404 if (extend) 1405 n += scnpr(b + n, blen - n, 1406 "lba=0x%02x%02x%02x%02x%02x%02x ", 1407 descp[10], descp[8], descp[6], descp[11], 1408 descp[9], descp[7]); 1409 else 1410 n += scnpr(b + n, blen - n, "lba=0x%02x%02x%02x ", 1411 descp[11], descp[9], descp[7]); 1412 n += scnpr(b + n, blen - n, "device=0x%x status=0x%x\n", 1413 descp[12], descp[13]); 1414 } else { 1415 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1416 processed = false; 1417 } 1418 break; 1419 case 0xa: 1420 /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */ 1421 n += scnpr(b + n, blen - n, "Another progress indication: "); 1422 if (add_d_len < 6) { 1423 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1424 processed = false; 1425 break; 1426 } 1427 progress = sg_get_unaligned_be16(descp + 6); 1428 pr = (progress * 100) / 65536; 1429 rem = ((progress * 100) % 65536) / 656; 1430 n += scnpr(b + n, blen - n, "%d.02%d%%\n", pr, rem); 1431 n += scnpr(b + n, blen - n, "%s [sense_key=0x%x " 1432 "asc,ascq=0x%x,0x%x]\n", lip, descp[2], descp[3], 1433 descp[4]); 1434 break; 1435 case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */ 1436 n += scnpr(b + n, blen - n, "User data segment referral: "); 1437 if (add_d_len < 2) { 1438 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1439 processed = false; 1440 break; 1441 } 1442 n += scnpr(b + n, blen - n, "\n"); 1443 n += uds_referral_descriptor_str(b + n, blen - n, descp, 1444 add_d_len, lip); 1445 break; 1446 case 0xc: /* Added in SPC-4 rev 28 */ 1447 n += scnpr(b + n, blen - n, "Forwarded sense data\n"); 1448 if (add_d_len < 2) { 1449 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1450 processed = false; 1451 break; 1452 } 1453 n += scnpr(b + n, blen - n, "%s FSDT: %s\n", lip, 1454 (descp[2] & 0x80) ? "set" : "clear"); 1455 j = descp[2] & 0xf; 1456 n += scnpr(b + n, blen - n, "%s Sense data source: ", lip); 1457 switch (j) { 1458 case 0: 1459 n += scnpr(b + n, blen - n, "%s source device\n", eccp); 1460 break; 1461 case 1: 1462 case 2: 1463 case 3: 1464 case 4: 1465 case 5: 1466 case 6: 1467 case 7: 1468 n += scnpr(b + n, blen - n, "%s %s %d\n", eccp, ddp, j - 1); 1469 break; 1470 default: 1471 n += scnpr(b + n, blen - n, "unknown [%d]\n", j); 1472 } 1473 { 1474 char c[480]; 1475 1476 sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c); 1477 c[sizeof(c) - 1] = '\0'; 1478 n += scnpr(b + n, blen - n, "%s Forwarded status: %s\n", 1479 lip, c); 1480 if (add_d_len > 2) { 1481 /* recursing; hope not to get carried away */ 1482 n += scnpr(b + n, blen - n, "%s vvvvvvvvvvvvvvvv\n", lip); 1483 sg_get_sense_str(lip, descp + 4, add_d_len - 2, false, 1484 sizeof(c), c); 1485 n += scnpr(b + n, blen - n, "%s", c); 1486 n += scnpr(b + n, blen - n, "%s ^^^^^^^^^^^^^^^^\n", lip); 1487 } 1488 } 1489 break; 1490 case 0xd: /* Added in SBC-3 rev 36d */ 1491 /* this descriptor combines descriptors 0, 1, 2 and 3 */ 1492 n += scnpr(b + n, blen - n, "Direct-access block device\n"); 1493 if (add_d_len < 28) { 1494 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1495 processed = false; 1496 break; 1497 } 1498 if (0x20 & descp[2]) 1499 n += scnpr(b + n, blen - n, "%s ILI (incorrect length " 1500 "indication) set\n", lip); 1501 if (0x80 & descp[4]) { 1502 n += scnpr(b + n, blen - n, "%s Sense key specific: ", 1503 lip); 1504 n += decode_sks(lip, descp, add_d_len, sense_key, &processed, 1505 blen - n, b + n); 1506 } 1507 n += scnpr(b + n, blen - n, "%s Field replaceable unit code: " 1508 "0x%x\n", lip, descp[7]); 1509 if (0x80 & descp[2]) { 1510 n += scnpr(b + n, blen - n, "%s Information: 0x", lip); 1511 for (j = 0; j < 8; ++j) 1512 n += scnpr(b + n, blen - n, "%02x", descp[8 + j]); 1513 n += scnpr(b + n, blen - n, "\n"); 1514 } 1515 n += scnpr(b + n, blen - n, "%s Command specific: 0x", lip); 1516 for (j = 0; j < 8; ++j) 1517 n += scnpr(b + n, blen - n, "%02x", descp[16 + j]); 1518 n += scnpr(b + n, blen - n, "\n"); 1519 break; 1520 case 0xe: /* Added in SPC-5 rev 6 (for Bind/Unbind) */ 1521 n += scnpr(b + n, blen - n, "Device designation\n"); 1522 j = (int)(sizeof(dd_usage_reason_str_arr) / 1523 sizeof(dd_usage_reason_str_arr[0])); 1524 if (descp[3] < j) 1525 n += scnpr(b + n, blen - n, "%s Usage reason: %s\n", lip, 1526 dd_usage_reason_str_arr[descp[3]]); 1527 else 1528 n += scnpr(b + n, blen - n, "%s Usage reason: " 1529 "reserved[%d]\n", lip, descp[3]); 1530 n += sg_get_designation_descriptor_str(z, descp + 4, descp[1] - 2, 1531 true, false, blen - n, 1532 b + n); 1533 break; 1534 case 0xf: /* Added in SPC-5 rev 10 (for Write buffer) */ 1535 n += scnpr(b + n, blen - n, "Microcode activation "); 1536 if (add_d_len < 6) { 1537 n += scnpr(b + n, blen - n, "%s\n", dtsp); 1538 processed = false; 1539 break; 1540 } 1541 progress = sg_get_unaligned_be16(descp + 6); 1542 n += scnpr(b + n, blen - n, "time: "); 1543 if (0 == progress) 1544 n += scnpr(b + n, blen - n, "unknown\n"); 1545 else 1546 n += scnpr(b + n, blen - n, "%d seconds\n", progress); 1547 break; 1548 default: 1549 if (descp[0] >= 0x80) 1550 n += scnpr(b + n, blen - n, "Vendor specific [0x%x]\n", 1551 descp[0]); 1552 else 1553 n += scnpr(b + n, blen - n, "Unknown [0x%x]\n", descp[0]); 1554 processed = false; 1555 break; 1556 } 1557 if (! processed) { 1558 if (add_d_len > 0) { 1559 n += scnpr(b + n, blen - n, "%s ", lip); 1560 for (j = 0; j < add_d_len; ++j) { 1561 if ((j > 0) && (0 == (j % 24))) 1562 n += scnpr(b + n, blen - n, "\n%s ", lip); 1563 n += scnpr(b + n, blen - n, "%02x ", descp[j + 2]); 1564 } 1565 n += scnpr(b + n, blen - n, "\n"); 1566 } 1567 } 1568 if (add_d_len < 0) 1569 n += scnpr(b + n, blen - n, "%s short descriptor\n", lip); 1570 } 1571 return n; 1572 } 1573 1574 /* Decode SAT ATA PASS-THROUGH fixed format sense. Shows "+" after 'count' 1575 * and/or 'lba' values to indicate that not all data in those fields is shown. 1576 * That extra field information may be available in the ATA pass-through 1577 * results log page parameter with the corresponding 'log_index'. */ 1578 static int 1579 sg_get_sense_sat_pt_fixed_str(const char * lip, const unsigned char * sp, 1580 int slen, int blen, char * b) 1581 { 1582 int n = 0; 1583 bool extend, count_upper_nz, lba_upper_nz; 1584 1585 if ((blen < 1) || (slen < 12)) 1586 return n; 1587 if (NULL == lip) 1588 lip = ""; 1589 if (SPC_SK_RECOVERED_ERROR != (0xf & sp[2])) 1590 n += scnpr(b + n, blen - n, "%s >> expected Sense key: Recovered " 1591 "Error ??\n", lip); 1592 /* Fixed sense command-specific information field starts at sp + 8 */ 1593 extend = !!(0x80 & sp[8]); 1594 count_upper_nz = !!(0x40 & sp[8]); 1595 lba_upper_nz = !!(0x20 & sp[8]); 1596 /* Fixed sense information field starts at sp + 3 */ 1597 n += scnpr(b + n, blen - n, "%s error=0x%x, status=0x%x, device=0x%x, " 1598 "count(7:0)=0x%x%c\n", lip, sp[3], sp[4], sp[5], sp[6], 1599 (count_upper_nz ? '+' : ' ')); 1600 n += scnpr(b + n, blen - n, "%s extend=%d, log_index=0x%x, " 1601 "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", lip, (int)extend, 1602 (0xf & sp[8]), sp[9], sp[10], sp[11], 1603 (lba_upper_nz ? '+' : ' ')); 1604 return n; 1605 } 1606 1607 /* Fetch sense information */ 1608 int 1609 sg_get_sense_str(const char * lip, const unsigned char * sbp, int sb_len, 1610 bool raw_sinfo, int cblen, char * cbp) 1611 { 1612 bool descriptor_format = false; 1613 bool sdat_ovfl = false; 1614 bool valid; 1615 int len, progress, n, r, pr, rem, blen; 1616 unsigned int info; 1617 uint8_t resp_code; 1618 const char * ebp = NULL; 1619 char ebuff[64]; 1620 char b[256]; 1621 struct sg_scsi_sense_hdr ssh; 1622 1623 if ((NULL == cbp) || (cblen <= 0)) 1624 return 0; 1625 else if (1 == cblen) { 1626 cbp[0] = '\0'; 1627 return 0; 1628 } 1629 blen = sizeof(b); 1630 n = 0; 1631 if (NULL == lip) 1632 lip = ""; 1633 if ((NULL == sbp) || (sb_len < 1)) { 1634 n += scnpr(cbp, cblen, "%s >>> sense buffer empty\n", lip); 1635 return n; 1636 } 1637 resp_code = 0x7f & sbp[0]; 1638 valid = !!(sbp[0] & 0x80); 1639 len = sb_len; 1640 if (sg_scsi_normalize_sense(sbp, sb_len, &ssh)) { 1641 switch (ssh.response_code) { 1642 case 0x70: /* fixed, current */ 1643 ebp = "Fixed format, current"; 1644 len = (sb_len > 7) ? (sbp[7] + 8) : sb_len; 1645 len = (len > sb_len) ? sb_len : len; 1646 sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false; 1647 break; 1648 case 0x71: /* fixed, deferred */ 1649 /* error related to a previous command */ 1650 ebp = "Fixed format, <<<deferred>>>"; 1651 len = (sb_len > 7) ? (sbp[7] + 8) : sb_len; 1652 len = (len > sb_len) ? sb_len : len; 1653 sdat_ovfl = (len > 2) ? !!(sbp[2] & 0x10) : false; 1654 break; 1655 case 0x72: /* descriptor, current */ 1656 descriptor_format = true; 1657 ebp = "Descriptor format, current"; 1658 sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false; 1659 break; 1660 case 0x73: /* descriptor, deferred */ 1661 descriptor_format = true; 1662 ebp = "Descriptor format, <<<deferred>>>"; 1663 sdat_ovfl = (sb_len > 4) ? !!(sbp[4] & 0x80) : false; 1664 break; 1665 case 0x0: 1666 ebp = "Response code: 0x0 (?)"; 1667 break; 1668 default: 1669 scnpr(ebuff, sizeof(ebuff), "Unknown response code: 0x%x", 1670 ssh.response_code); 1671 ebp = ebuff; 1672 break; 1673 } 1674 n += scnpr(cbp + n, cblen - n, "%s%s; Sense key: %s\n", lip, ebp, 1675 sg_lib_sense_key_desc[ssh.sense_key]); 1676 if (sdat_ovfl) 1677 n += scnpr(cbp + n, cblen - n, "%s<<<Sense data overflow>>>\n", 1678 lip); 1679 if (descriptor_format) { 1680 n += scnpr(cbp + n, cblen - n, "%s%s\n", lip, 1681 sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b)); 1682 n += sg_get_sense_descriptors_str(lip, sbp, len, 1683 cblen - n, cbp + n); 1684 } else if ((len > 12) && (0 == ssh.asc) && 1685 (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { 1686 /* SAT ATA PASS-THROUGH fixed format */ 1687 n += scnpr(cbp + n, cblen - n, "%s%s\n", lip, 1688 sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b)); 1689 n += sg_get_sense_sat_pt_fixed_str(lip, sbp, len, 1690 cblen - n, cbp + n); 1691 } else if (len > 2) { /* fixed format */ 1692 if (len > 12) 1693 n += scnpr(cbp + n, cblen - n, "%s%s\n", lip, 1694 sg_get_asc_ascq_str(ssh.asc, ssh.ascq, blen, b)); 1695 r = 0; 1696 if (strlen(lip) > 0) 1697 r += scnpr(b + r, blen - r, "%s", lip); 1698 if (len > 6) { 1699 info = sg_get_unaligned_be32(sbp + 3); 1700 if (valid) 1701 r += scnpr(b + r, blen - r, " Info fld=0x%x [%u] ", 1702 info, info); 1703 else if (info > 0) 1704 r += scnpr(b + r, blen - r, " Valid=0, Info fld=0x%x " 1705 "[%u] ", info, info); 1706 } else 1707 info = 0; 1708 if (sbp[2] & 0xe0) { 1709 if (sbp[2] & 0x80) 1710 r += scnpr(b + r, blen - r, " FMK"); 1711 /* current command has read a filemark */ 1712 if (sbp[2] & 0x40) 1713 r += scnpr(b + r, blen - r, " EOM"); 1714 /* end-of-medium condition exists */ 1715 if (sbp[2] & 0x20) 1716 r += scnpr(b + r, blen - r, " ILI"); 1717 /* incorrect block length requested */ 1718 r += scnpr(b + r, blen - r, "\n"); 1719 } else if (valid || (info > 0)) 1720 r += scnpr(b + r, blen - r, "\n"); 1721 if ((len >= 14) && sbp[14]) 1722 r += scnpr(b + r, blen - r, "%s Field replaceable unit " 1723 "code: %d\n", lip, sbp[14]); 1724 if ((len >= 18) && (sbp[15] & 0x80)) { 1725 /* sense key specific decoding */ 1726 switch (ssh.sense_key) { 1727 case SPC_SK_ILLEGAL_REQUEST: 1728 r += scnpr(b + r, blen - r, "%s Sense Key Specific: " 1729 "Error in %s: byte %d", lip, 1730 ((sbp[15] & 0x40) ? "Command" : 1731 "Data parameters"), 1732 sg_get_unaligned_be16(sbp + 16)); 1733 if (sbp[15] & 0x08) 1734 r += scnpr(b + r, blen - r, " bit %d\n", 1735 sbp[15] & 0x07); 1736 else 1737 r += scnpr(b + r, blen - r, "\n"); 1738 break; 1739 case SPC_SK_NO_SENSE: 1740 case SPC_SK_NOT_READY: 1741 progress = sg_get_unaligned_be16(sbp + 16); 1742 pr = (progress * 100) / 65536; 1743 rem = ((progress * 100) % 65536) / 656; 1744 r += scnpr(b + r, blen - r, "%s Progress indication: " 1745 "%d.%02d%%\n", lip, pr, rem); 1746 break; 1747 case SPC_SK_HARDWARE_ERROR: 1748 case SPC_SK_MEDIUM_ERROR: 1749 case SPC_SK_RECOVERED_ERROR: 1750 r += scnpr(b + r, blen - r, "%s Actual retry count: " 1751 "0x%02x%02x\n", lip, sbp[16], sbp[17]); 1752 break; 1753 case SPC_SK_COPY_ABORTED: 1754 r += scnpr(b + r, blen - r, "%s Segment pointer: ", lip); 1755 r += scnpr(b + r, blen - r, "Relative to start of %s, " 1756 "byte %d", ((sbp[15] & 0x20) ? 1757 "segment descriptor" : "parameter list"), 1758 sg_get_unaligned_be16(sbp + 16)); 1759 if (sbp[15] & 0x08) 1760 r += scnpr(b + r, blen - r, " bit %d\n", 1761 sbp[15] & 0x07); 1762 else 1763 r += scnpr(b + r, blen - r, "\n"); 1764 break; 1765 case SPC_SK_UNIT_ATTENTION: 1766 r += scnpr(b + r, blen - r, "%s Unit attention " 1767 "condition queue: ", lip); 1768 r += scnpr(b + r, blen - r, "overflow flag is %d\n", 1769 !!(sbp[15] & 0x1)); 1770 break; 1771 default: 1772 r += scnpr(b + r, blen - r, "%s Sense_key: 0x%x " 1773 "unexpected\n", lip, ssh.sense_key); 1774 break; 1775 } 1776 } 1777 if (r > 0) 1778 n += scnpr(cbp + n, cblen - n, "%s", b); 1779 } else 1780 n += scnpr(cbp + n, cblen - n, "%s fixed descriptor length " 1781 "too short, len=%d\n", lip, len); 1782 } else { /* unable to normalise sense buffer, something irregular */ 1783 if (sb_len < 4) { /* Too short */ 1784 n += scnpr(cbp + n, cblen - n, "%ssense buffer too short (4 " 1785 "byte minimum)\n", lip); 1786 goto check_raw; 1787 } 1788 if (0x7f == resp_code) { /* Vendor specific */ 1789 n += scnpr(cbp + n, cblen - n, "%sVendor specific sense buffer, " 1790 "in hex:\n", lip); 1791 n += hex2str(sbp, sb_len, lip, -1, cblen - n, cbp + n); 1792 return n; /* no need to check raw, just output in hex */ 1793 } 1794 /* non-extended SCSI-1 sense data ?? */ 1795 r = 0; 1796 if (strlen(lip) > 0) 1797 r += scnpr(b + r, blen - r, "%s", lip); 1798 r += scnpr(b + r, blen - r, "Probably uninitialized data.\n%s Try " 1799 "to view as SCSI-1 non-extended sense:\n", lip); 1800 r += scnpr(b + r, blen - r, " AdValid=%d Error class=%d Error " 1801 "code=%d\n", valid, ((sbp[0] >> 4) & 0x7), 1802 (sbp[0] & 0xf)); 1803 if (valid) 1804 scnpr(b + r, blen - r, "%s lba=0x%x\n", lip, 1805 sg_get_unaligned_be24(sbp + 1) & 0x1fffff); 1806 n += scnpr(cbp + n, cblen - n, "%s\n", b); 1807 len = sb_len; 1808 if (len > 32) 1809 len = 32; /* trim in case there is a lot of rubbish */ 1810 } 1811 check_raw: 1812 if (raw_sinfo) { 1813 char z[64]; 1814 1815 n += scnpr(cbp + n, cblen - n, "%s Raw sense data (in hex):\n", 1816 lip); 1817 if (n >= (cblen - 1)) 1818 return n; 1819 scnpr(z, sizeof(z), "%.50s ", lip); 1820 n += hex2str(sbp, len, z, -1, cblen - n, cbp + n); 1821 } 1822 return n; 1823 } 1824 1825 /* Print sense information */ 1826 void 1827 sg_print_sense(const char * leadin, const unsigned char * sbp, int sb_len, 1828 bool raw_sinfo) 1829 { 1830 uint32_t pg_sz = sg_get_page_size(); 1831 char *cp; 1832 uint8_t *free_cp; 1833 1834 cp = (char *)sg_memalign(pg_sz, pg_sz, &free_cp, 0); 1835 if (NULL == cp) 1836 return; 1837 sg_get_sense_str(leadin, sbp, sb_len, raw_sinfo, pg_sz, cp); 1838 pr2ws("%s", cp); 1839 free(free_cp); 1840 } 1841 1842 /* Following examines exit_status and outputs a clear error message to 1843 * warnings_strm (usually stderr) if one is known and returns true. 1844 * Otherwise it doesn't print anything and returns false. Note that 1845 * if exit_status==0 then returns true but prints nothing and if 1846 * exit_status<0 ("some error occurred") false is returned. If leadin is 1847 * non-NULL then it is printed before the error message. */ 1848 bool 1849 sg_if_can2stderr(const char * leadin, int exit_status) 1850 { 1851 const char * s = leadin ? leadin : ""; 1852 1853 if (exit_status < 0) 1854 return false; 1855 else if (0 == exit_status) 1856 return true; 1857 1858 switch (exit_status) { 1859 case SG_LIB_CAT_NOT_READY: /* 2 */ 1860 pr2ws("%sDevice not ready\n", s); 1861 return true; 1862 case SG_LIB_CAT_MEDIUM_HARD: /* 3 */ 1863 pr2ws("%sMedium or hardware error\n", s); /* 3 sense keys: Medium, */ 1864 return true; /* hardware error or 'Blank check' for tapes */ 1865 case SG_LIB_CAT_UNIT_ATTENTION: /* 6 */ 1866 pr2ws("%sDevice reported 'Unit attention'\n", s); 1867 return true; 1868 case SG_LIB_CAT_DATA_PROTECT: /* 7 */ 1869 pr2ws("%sDevice reported 'Data protect', read-only?\n", s); 1870 return true; 1871 case SG_LIB_CAT_COPY_ABORTED: /* 10 */ 1872 pr2ws("%sCopy aborted\n", s); 1873 return true; 1874 case SG_LIB_CAT_ABORTED_COMMAND: /* 11 */ 1875 pr2ws("%sCommand aborted\n", s); 1876 return true; 1877 case SG_LIB_CAT_MISCOMPARE: /* 14 */ 1878 pr2ws("%sMiscompare\n", s); 1879 return true; 1880 case SG_LIB_CAT_RES_CONFLICT: /* 24 */ 1881 pr2ws("%sReservation conflict\n", s); 1882 return true; 1883 case SG_LIB_CAT_BUSY: /* 26 */ 1884 pr2ws("%sDevice is busy, try again\n", s); 1885 return true; 1886 case SG_LIB_CAT_TASK_ABORTED: /* 29 */ 1887 pr2ws("%sTask aborted\n", s); 1888 return true; 1889 case SG_LIB_CAT_TIMEOUT: /* 33 */ 1890 pr2ws("%sTime out\n", s); 1891 return true; 1892 case SG_LIB_CAT_PROTECTION: /* 40 */ 1893 pr2ws("%sProtection error\n", s); 1894 return true; 1895 case SG_LIB_NVME_STATUS: /* 48 */ 1896 pr2ws("%sNVMe error (non-zero status)\n", s); 1897 return true; 1898 case SG_LIB_OS_BASE_ERR + EACCES: /* 50 + */ 1899 pr2ws("%sPermission denied\n", s); 1900 return true; 1901 case SG_LIB_OS_BASE_ERR + ENOMEM: 1902 pr2ws("%sUtility unable to allocate memory\n", s); 1903 return true; 1904 case SG_LIB_OS_BASE_ERR + ENOTTY: 1905 pr2ws("%sInappropriate I/O control operation\n", s); 1906 return true; 1907 case SG_LIB_OS_BASE_ERR + EPERM: 1908 pr2ws("%sNot permitted\n", s); 1909 return true; 1910 case SG_LIB_OS_BASE_ERR + EINTR: 1911 pr2ws("%sInterrupted system call\n", s); 1912 return true; 1913 case SG_LIB_OS_BASE_ERR + EIO: 1914 pr2ws("%sInput/output error\n", s); 1915 return true; 1916 case SG_LIB_OS_BASE_ERR + ENODEV: 1917 pr2ws("%sNo such device\n", s); 1918 return true; 1919 case SG_LIB_OS_BASE_ERR + ENOENT: 1920 pr2ws("%sNo such file or directory\n", s); 1921 return true; 1922 default: 1923 return false; 1924 } 1925 return false; 1926 } 1927 1928 /* If os_err_num is within bounds then the returned value is 'os_err_num + 1929 * SG_LIB_OS_BASE_ERR' otherwise -1 is returned. If os_err_num is 0 then 0 1930 * is returned. */ 1931 int 1932 sg_convert_errno(int os_err_num) 1933 { 1934 if (os_err_num <= 0) { 1935 if (os_err_num < -1) 1936 return -1; 1937 return os_err_num; 1938 } 1939 if (os_err_num < (SG_LIB_CAT_MALFORMED - SG_LIB_OS_BASE_ERR)) 1940 return SG_LIB_OS_BASE_ERR + os_err_num; 1941 return -1; 1942 } 1943 1944 /* See description in sg_lib.h header file */ 1945 bool 1946 sg_scsi_normalize_sense(const unsigned char * sbp, int sb_len, 1947 struct sg_scsi_sense_hdr * sshp) 1948 { 1949 uint8_t resp_code; 1950 if (sshp) 1951 memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr)); 1952 if ((NULL == sbp) || (sb_len < 1)) 1953 return false; 1954 resp_code = 0x7f & sbp[0]; 1955 if ((resp_code < 0x70) || (resp_code > 0x73)) 1956 return false; 1957 if (sshp) { 1958 sshp->response_code = resp_code; 1959 if (sshp->response_code >= 0x72) { /* descriptor format */ 1960 if (sb_len > 1) 1961 sshp->sense_key = (0xf & sbp[1]); 1962 if (sb_len > 2) 1963 sshp->asc = sbp[2]; 1964 if (sb_len > 3) 1965 sshp->ascq = sbp[3]; 1966 if (sb_len > 7) 1967 sshp->additional_length = sbp[7]; 1968 } else { /* fixed format */ 1969 if (sb_len > 2) 1970 sshp->sense_key = (0xf & sbp[2]); 1971 if (sb_len > 7) { 1972 sb_len = (sb_len < (sbp[7] + 8)) ? sb_len : (sbp[7] + 8); 1973 if (sb_len > 12) 1974 sshp->asc = sbp[12]; 1975 if (sb_len > 13) 1976 sshp->ascq = sbp[13]; 1977 } 1978 } 1979 } 1980 return true; 1981 } 1982 1983 /* Returns a SG_LIB_CAT_* value. If cannot decode sense buffer (sbp) or a 1984 * less common sense key then return SG_LIB_CAT_SENSE .*/ 1985 int 1986 sg_err_category_sense(const unsigned char * sbp, int sb_len) 1987 { 1988 struct sg_scsi_sense_hdr ssh; 1989 1990 if ((sbp && (sb_len > 2)) && 1991 (sg_scsi_normalize_sense(sbp, sb_len, &ssh))) { 1992 switch (ssh.sense_key) { /* 0 to 0x1f */ 1993 case SPC_SK_NO_SENSE: 1994 return SG_LIB_CAT_NO_SENSE; 1995 case SPC_SK_RECOVERED_ERROR: 1996 return SG_LIB_CAT_RECOVERED; 1997 case SPC_SK_NOT_READY: 1998 return SG_LIB_CAT_NOT_READY; 1999 case SPC_SK_MEDIUM_ERROR: 2000 case SPC_SK_HARDWARE_ERROR: 2001 case SPC_SK_BLANK_CHECK: 2002 return SG_LIB_CAT_MEDIUM_HARD; 2003 case SPC_SK_UNIT_ATTENTION: 2004 return SG_LIB_CAT_UNIT_ATTENTION; 2005 /* used to return SG_LIB_CAT_MEDIA_CHANGED when ssh.asc==0x28 */ 2006 case SPC_SK_ILLEGAL_REQUEST: 2007 if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) 2008 return SG_LIB_CAT_INVALID_OP; 2009 else 2010 return SG_LIB_CAT_ILLEGAL_REQ; 2011 break; 2012 case SPC_SK_ABORTED_COMMAND: 2013 if (0x10 == ssh.asc) 2014 return SG_LIB_CAT_PROTECTION; 2015 else 2016 return SG_LIB_CAT_ABORTED_COMMAND; 2017 case SPC_SK_MISCOMPARE: 2018 return SG_LIB_CAT_MISCOMPARE; 2019 case SPC_SK_DATA_PROTECT: 2020 return SG_LIB_CAT_DATA_PROTECT; 2021 case SPC_SK_COPY_ABORTED: 2022 return SG_LIB_CAT_COPY_ABORTED; 2023 case SPC_SK_COMPLETED: 2024 case SPC_SK_VOLUME_OVERFLOW: 2025 return SG_LIB_CAT_SENSE; 2026 default: 2027 ; /* reserved and vendor specific sense keys fall through */ 2028 } 2029 } 2030 return SG_LIB_CAT_SENSE; 2031 } 2032 2033 /* Beware: gives wrong answer for variable length command (opcode=0x7f) */ 2034 int 2035 sg_get_command_size(unsigned char opcode) 2036 { 2037 switch ((opcode >> 5) & 0x7) { 2038 case 0: 2039 return 6; 2040 case 1: case 2: case 6: case 7: 2041 return 10; 2042 case 3: case 5: 2043 return 12; 2044 break; 2045 case 4: 2046 return 16; 2047 default: 2048 return 10; 2049 } 2050 } 2051 2052 void 2053 sg_get_command_name(const unsigned char * cmdp, int peri_type, int buff_len, 2054 char * buff) 2055 { 2056 int service_action; 2057 2058 if ((NULL == buff) || (buff_len < 1)) 2059 return; 2060 else if (1 == buff_len) { 2061 buff[0] = '\0'; 2062 return; 2063 } 2064 if (NULL == cmdp) { 2065 scnpr(buff, buff_len, "%s", "<null> command pointer"); 2066 return; 2067 } 2068 service_action = (SG_VARIABLE_LENGTH_CMD == cmdp[0]) ? 2069 sg_get_unaligned_be16(cmdp + 8) : (cmdp[1] & 0x1f); 2070 sg_get_opcode_sa_name(cmdp[0], service_action, peri_type, buff_len, buff); 2071 } 2072 2073 struct op_code2sa_t { 2074 int op_code; 2075 int pdt_match; /* -1->all; 0->disk,ZBC,RCB, 1->tape+adc+smc */ 2076 struct sg_lib_value_name_t * arr; 2077 const char * prefix; 2078 }; 2079 2080 static struct op_code2sa_t op_code2sa_arr[] = { 2081 {SG_VARIABLE_LENGTH_CMD, -1, sg_lib_variable_length_arr, NULL}, 2082 {SG_MAINTENANCE_IN, -1, sg_lib_maint_in_arr, NULL}, 2083 {SG_MAINTENANCE_OUT, -1, sg_lib_maint_out_arr, NULL}, 2084 {SG_SERVICE_ACTION_IN_12, -1, sg_lib_serv_in12_arr, NULL}, 2085 {SG_SERVICE_ACTION_OUT_12, -1, sg_lib_serv_out12_arr, NULL}, 2086 {SG_SERVICE_ACTION_IN_16, -1, sg_lib_serv_in16_arr, NULL}, 2087 {SG_SERVICE_ACTION_OUT_16, -1, sg_lib_serv_out16_arr, NULL}, 2088 {SG_SERVICE_ACTION_BIDI, -1, sg_lib_serv_bidi_arr, NULL}, 2089 {SG_PERSISTENT_RESERVE_IN, -1, sg_lib_pr_in_arr, "Persistent reserve in"}, 2090 {SG_PERSISTENT_RESERVE_OUT, -1, sg_lib_pr_out_arr, 2091 "Persistent reserve out"}, 2092 {SG_3PARTY_COPY_OUT, -1, sg_lib_xcopy_sa_arr, NULL}, 2093 {SG_3PARTY_COPY_IN, -1, sg_lib_rec_copy_sa_arr, NULL}, 2094 {SG_READ_BUFFER, -1, sg_lib_read_buff_arr, "Read buffer(10)"}, 2095 {SG_READ_BUFFER_16, -1, sg_lib_read_buff_arr, "Read buffer(16)"}, 2096 {SG_READ_ATTRIBUTE, -1, sg_lib_read_attr_arr, "Read attribute"}, 2097 {SG_READ_POSITION, 1, sg_lib_read_pos_arr, "Read position"}, 2098 {SG_SANITIZE, 0, sg_lib_sanitize_sa_arr, "Sanitize"}, 2099 {SG_WRITE_BUFFER, -1, sg_lib_write_buff_arr, "Write buffer"}, 2100 {SG_ZONING_IN, 0, sg_lib_zoning_in_arr, NULL}, 2101 {SG_ZONING_OUT, 0, sg_lib_zoning_out_arr, NULL}, 2102 {0xffff, -1, NULL, NULL}, 2103 }; 2104 2105 void 2106 sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action, 2107 int peri_type, int buff_len, char * buff) 2108 { 2109 int d_pdt; 2110 const struct sg_lib_value_name_t * vnp; 2111 const struct op_code2sa_t * osp; 2112 char b[80]; 2113 2114 if ((NULL == buff) || (buff_len < 1)) 2115 return; 2116 else if (1 == buff_len) { 2117 buff[0] = '\0'; 2118 return; 2119 } 2120 2121 if (peri_type < 0) 2122 peri_type = 0; 2123 d_pdt = sg_lib_pdt_decay(peri_type); 2124 for (osp = op_code2sa_arr; osp->arr; ++osp) { 2125 if ((int)cmd_byte0 == osp->op_code) { 2126 if ((osp->pdt_match < 0) || (d_pdt == osp->pdt_match)) { 2127 vnp = get_value_name(osp->arr, service_action, peri_type); 2128 if (vnp) { 2129 if (osp->prefix) 2130 scnpr(buff, buff_len, "%s, %s", osp->prefix, 2131 vnp->name); 2132 else 2133 scnpr(buff, buff_len, "%s", vnp->name); 2134 } else { 2135 sg_get_opcode_name(cmd_byte0, peri_type, sizeof(b), b); 2136 scnpr(buff, buff_len, "%s service action=0x%x", b, 2137 service_action); 2138 } 2139 } else 2140 sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff); 2141 return; 2142 } 2143 } 2144 sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff); 2145 } 2146 2147 void 2148 sg_get_opcode_name(unsigned char cmd_byte0, int peri_type, int buff_len, 2149 char * buff) 2150 { 2151 const struct sg_lib_value_name_t * vnp; 2152 int grp; 2153 2154 if ((NULL == buff) || (buff_len < 1)) 2155 return; 2156 else if (1 == buff_len) { 2157 buff[0] = '\0'; 2158 return; 2159 } 2160 if (SG_VARIABLE_LENGTH_CMD == cmd_byte0) { 2161 scnpr(buff, buff_len, "%s", "Variable length"); 2162 return; 2163 } 2164 grp = (cmd_byte0 >> 5) & 0x7; 2165 switch (grp) { 2166 case 0: 2167 case 1: 2168 case 2: 2169 case 4: 2170 case 5: 2171 vnp = get_value_name(sg_lib_normal_opcodes, cmd_byte0, peri_type); 2172 if (vnp) 2173 scnpr(buff, buff_len, "%s", vnp->name); 2174 else 2175 scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0); 2176 break; 2177 case 3: 2178 scnpr(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0); 2179 break; 2180 case 6: 2181 case 7: 2182 scnpr(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0); 2183 break; 2184 default: 2185 scnpr(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0); 2186 break; 2187 } 2188 } 2189 2190 /* Iterates to next designation descriptor in the device identification 2191 * VPD page. The 'initial_desig_desc' should point to start of first 2192 * descriptor with 'page_len' being the number of valid bytes in that 2193 * and following descriptors. To start, 'off' should point to a negative 2194 * value, thereafter it should point to the value yielded by the previous 2195 * call. If 0 returned then 'initial_desig_desc + *off' should be a valid 2196 * descriptor; returns -1 if normal end condition and -2 for an abnormal 2197 * termination. Matches association, designator_type and/or code_set when 2198 * any of those values are greater than or equal to zero. */ 2199 int 2200 sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len, 2201 int * off, int m_assoc, int m_desig_type, int m_code_set) 2202 { 2203 bool fltr = ((m_assoc >= 0) || (m_desig_type >= 0) || (m_code_set >= 0)); 2204 int k = *off; 2205 const unsigned char * bp = initial_desig_desc; 2206 2207 while ((k + 3) < page_len) { 2208 k = (k < 0) ? 0 : (k + bp[k + 3] + 4); 2209 if ((k + 4) > page_len) 2210 break; 2211 if (fltr) { 2212 if (m_code_set >= 0) { 2213 if ((bp[k] & 0xf) != m_code_set) 2214 continue; 2215 } 2216 if (m_assoc >= 0) { 2217 if (((bp[k + 1] >> 4) & 0x3) != m_assoc) 2218 continue; 2219 } 2220 if (m_desig_type >= 0) { 2221 if ((bp[k + 1] & 0xf) != m_desig_type) 2222 continue; 2223 } 2224 } 2225 *off = k; 2226 return 0; 2227 } 2228 return (k == page_len) ? -1 : -2; 2229 } 2230 2231 static const char * const bad_sense_cat = "Bad sense category"; 2232 2233 /* Yield string associated with sense category. Returns 'buff' (or pointer 2234 * to "Bad sense category" if 'buff' is NULL). If sense_cat unknown then 2235 * yield "Sense category: <sense_cat>" string. */ 2236 const char * 2237 sg_get_category_sense_str(int sense_cat, int buff_len, char * buff, 2238 int verbose) 2239 { 2240 int n; 2241 2242 if (NULL == buff) 2243 return bad_sense_cat; 2244 if (buff_len <= 0) 2245 return buff; 2246 switch (sense_cat) { 2247 case SG_LIB_CAT_CLEAN: /* 0 */ 2248 scnpr(buff, buff_len, "No errors"); 2249 break; 2250 case SG_LIB_SYNTAX_ERROR: /* 1 */ 2251 scnpr(buff, buff_len, "Syntax error"); 2252 break; 2253 case SG_LIB_CAT_NOT_READY: /* 2 */ 2254 n = scnpr(buff, buff_len, "Not ready"); 2255 if (verbose && (n < (buff_len - 1))) 2256 scnpr(buff + n, buff_len - n, " sense key"); 2257 break; 2258 case SG_LIB_CAT_MEDIUM_HARD: /* 3 */ 2259 n = scnpr(buff, buff_len, "Medium or hardware error"); 2260 if (verbose && (n < (buff_len - 1))) 2261 scnpr(buff + n, buff_len - n, " sense key (plus blank check)"); 2262 break; 2263 case SG_LIB_CAT_ILLEGAL_REQ: /* 5 */ 2264 n = scnpr(buff, buff_len, "Illegal request"); 2265 if (verbose && (n < (buff_len - 1))) 2266 scnpr(buff + n, buff_len - n, " sense key, apart from Invalid " 2267 "opcode"); 2268 break; 2269 case SG_LIB_CAT_UNIT_ATTENTION: /* 6 */ 2270 n = scnpr(buff, buff_len, "Unit attention"); 2271 if (verbose && (n < (buff_len - 1))) 2272 scnpr(buff + n, buff_len - n, " sense key"); 2273 break; 2274 case SG_LIB_CAT_DATA_PROTECT: /* 7 */ 2275 n = scnpr(buff, buff_len, "Data protect"); 2276 if (verbose && (n < (buff_len - 1))) 2277 scnpr(buff + n, buff_len - n, " sense key, write protected " 2278 "media?"); 2279 break; 2280 case SG_LIB_CAT_INVALID_OP: /* 9 */ 2281 n = scnpr(buff, buff_len, "Illegal request, invalid opcode"); 2282 if (verbose && (n < (buff_len - 1))) 2283 scnpr(buff + n, buff_len - n, " sense key"); 2284 break; 2285 case SG_LIB_CAT_COPY_ABORTED: /* 10 */ 2286 n = scnpr(buff, buff_len, "Copy aborted"); 2287 if (verbose && (n < (buff_len - 1))) 2288 scnpr(buff + n, buff_len - n, " sense key"); 2289 break; 2290 case SG_LIB_CAT_ABORTED_COMMAND: /* 11 */ 2291 n = scnpr(buff, buff_len, "Aborted command"); 2292 if (verbose && (n < (buff_len - 1))) 2293 scnpr(buff + n, buff_len - n, " sense key, other than " 2294 "protection related (asc=0x10)"); 2295 break; 2296 case SG_LIB_CAT_MISCOMPARE: /* 14 */ 2297 n = scnpr(buff, buff_len, "Miscompare"); 2298 if (verbose && (n < (buff_len - 1))) 2299 scnpr(buff + n, buff_len - n, " sense key"); 2300 break; 2301 case SG_LIB_FILE_ERROR: /* 15 */ 2302 scnpr(buff, buff_len, "File error"); 2303 break; 2304 case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: /* 17 */ 2305 scnpr(buff, buff_len, "Illegal request with info"); 2306 break; 2307 case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: /* 18 */ 2308 scnpr(buff, buff_len, "Medium or hardware error with info"); 2309 break; 2310 case SG_LIB_CAT_NO_SENSE: /* 20 */ 2311 n = scnpr(buff, buff_len, "No sense key"); 2312 if (verbose && (n < (buff_len - 1))) 2313 scnpr(buff + n, buff_len - n, " probably additional sense " 2314 "information"); 2315 break; 2316 case SG_LIB_CAT_RECOVERED: /* 21 */ 2317 n = scnpr(buff, buff_len, "Recovered error"); 2318 if (verbose && (n < (buff_len - 1))) 2319 scnpr(buff + n, buff_len - n, " sense key"); 2320 break; 2321 case SG_LIB_CAT_RES_CONFLICT: /* 24 */ 2322 n = scnpr(buff, buff_len, "Reservation conflict"); 2323 if (verbose && (n < (buff_len - 1))) 2324 scnpr(buff + n, buff_len - n, " SCSI status"); 2325 break; 2326 case SG_LIB_CAT_CONDITION_MET: /* 25 */ 2327 n = scnpr(buff, buff_len, "Condition met"); 2328 if (verbose && (n < (buff_len - 1))) 2329 scnpr(buff + n, buff_len - n, " SCSI status"); 2330 break; 2331 case SG_LIB_CAT_BUSY: /* 26 */ 2332 n = scnpr(buff, buff_len, "Busy"); 2333 if (verbose && (n < (buff_len - 1))) 2334 scnpr(buff + n, buff_len - n, " SCSI status"); 2335 break; 2336 case SG_LIB_CAT_TS_FULL: /* 27 */ 2337 n = scnpr(buff, buff_len, "Task set full"); 2338 if (verbose && (n < (buff_len - 1))) 2339 scnpr(buff + n, buff_len - n, " SCSI status"); 2340 break; 2341 case SG_LIB_CAT_ACA_ACTIVE: /* 28 */ 2342 n = scnpr(buff, buff_len, "ACA active"); 2343 if (verbose && (n < (buff_len - 1))) 2344 scnpr(buff + n, buff_len - n, " SCSI status"); 2345 break; 2346 case SG_LIB_CAT_TASK_ABORTED: /* 29 */ 2347 n = scnpr(buff, buff_len, "Task aborted"); 2348 if (verbose && (n < (buff_len - 1))) 2349 scnpr(buff + n, buff_len - n, " SCSI status"); 2350 break; 2351 case SG_LIB_CAT_TIMEOUT: /* 33 */ 2352 scnpr(buff, buff_len, "SCSI command timeout"); 2353 break; 2354 case SG_LIB_CAT_PROTECTION: /* 40 */ 2355 n = scnpr(buff, buff_len, "Aborted command, protection"); 2356 if (verbose && (n < (buff_len - 1))) 2357 scnpr(buff + n, buff_len - n, " information (PI) problem"); 2358 break; 2359 case SG_LIB_CAT_PROTECTION_WITH_INFO: /* 41 */ 2360 n = scnpr(buff, buff_len, "Aborted command with info, protection"); 2361 if (verbose && (n < (buff_len - 1))) 2362 scnpr(buff + n, buff_len - n, " information (PI) problem"); 2363 break; 2364 case SG_LIB_CAT_MALFORMED: /* 97 */ 2365 n = scnpr(buff, buff_len, "Malformed response"); 2366 if (verbose && (n < (buff_len - 1))) 2367 scnpr(buff + n, buff_len - n, " to SCSI command"); 2368 break; 2369 case SG_LIB_CAT_SENSE: /* 98 */ 2370 n = scnpr(buff, buff_len, "Some other sense data problem"); 2371 if (verbose && (n < (buff_len - 1))) 2372 scnpr(buff + n, buff_len - n, ", try '-v' option for more " 2373 "information"); 2374 break; 2375 case SG_LIB_CAT_OTHER: /* 99 */ 2376 n = scnpr(buff, buff_len, "Some other error/warning has occurred"); 2377 if ((0 == verbose) && (n < (buff_len - 1))) 2378 scnpr(buff + n, buff_len - n, ", possible transport of driver " 2379 "issue"); 2380 break; 2381 default: 2382 if ((sense_cat > SG_LIB_OS_BASE_ERR) && 2383 (sense_cat < (SG_LIB_OS_BASE_ERR + 47))) { 2384 int k = sense_cat - SG_LIB_OS_BASE_ERR; 2385 2386 n = scnpr(buff, buff_len, "OS error: %s [%d]", safe_strerror(k), 2387 k); 2388 } else { 2389 n = scnpr(buff, buff_len, "Sense category: %d", sense_cat); 2390 if ((0 == verbose) && (n < (buff_len - 1))) 2391 scnpr(buff + n, buff_len - n, ", try '-v' option for more " 2392 "information"); 2393 } 2394 break; 2395 } 2396 return buff; 2397 } 2398 2399 static const char * sg_sfs_spc_reserved = "SPC Reserved"; 2400 static const char * sg_sfs_sbc_reserved = "SBC Reserved"; 2401 static const char * sg_sfs_ssc_reserved = "SSC Reserved"; 2402 static const char * sg_sfs_zbc_reserved = "ZBC Reserved"; 2403 static const char * sg_sfs_reserved = "Reserved"; 2404 2405 /* Yield SCSI Feature Set (sfs) string. When 'peri_type' is < -1 (or > 31) 2406 * returns pointer to string (same as 'buff') associated with 'sfs_code'. 2407 * When 'peri_type' is between -1 (for SPC) and 31 (inclusive) then a match 2408 * on both 'sfs_code' and 'peri_type' is required. If 'foundp' is not NULL 2409 * then where it points is set to true if a match is found else it is set to 2410 * false. If 'buff' is not NULL then in the case of a match a descriptive 2411 * string is written to 'buff' while if there is not a not then a string 2412 * ending in "Reserved" is written (and may be prefixed with SPC, SBC, SSC 2413 * or ZBC). Returns 'buff' (i.e. a pointer value) even if it is NULL. 2414 * Example: 2415 * char b[64]; 2416 * ... 2417 * printf("%s\n", sg_get_sfs_str(sfs_code, -2, sizeof(b), b, NULL, 0)); 2418 */ 2419 const char * 2420 sg_get_sfs_str(uint16_t sfs_code, int peri_type, int buff_len, char * buff, 2421 bool * foundp, int verbose) 2422 { 2423 const struct sg_lib_value_name_t * vnp = NULL; 2424 int n = 0; 2425 int my_pdt; 2426 2427 if ((NULL == buff) || (buff_len < 1)) { 2428 if (foundp) 2429 *foundp = false; 2430 return NULL; 2431 } else if (1 == buff_len) { 2432 buff[0] = '\0'; 2433 if (foundp) 2434 *foundp = false; 2435 return NULL; 2436 } 2437 my_pdt = ((peri_type < -1) || (peri_type > 0x1f)) ? -2 : peri_type; 2438 vnp = get_value_name(sg_lib_scsi_feature_sets, sfs_code, my_pdt); 2439 if (vnp && (-2 != my_pdt)) { 2440 if (peri_type != vnp->peri_dev_type) 2441 vnp = NULL; /* shouldn't really happen */ 2442 } 2443 if (foundp) 2444 *foundp = vnp ? true : false; 2445 if (sfs_code < 0x100) { /* SPC Feature Sets */ 2446 if (vnp) { 2447 if (verbose) 2448 n += scnpr(buff, buff_len, "SPC %s", vnp->name); 2449 else 2450 n += scnpr(buff, buff_len, "%s", vnp->name); 2451 } else 2452 n += scnpr(buff, buff_len, "%s", sg_sfs_spc_reserved); 2453 } else if (sfs_code < 0x200) { /* SBC Feature Sets */ 2454 if (vnp) { 2455 if (verbose) 2456 n += scnpr(buff, buff_len, "SBC %s", vnp->name); 2457 else 2458 n += scnpr(buff, buff_len, "%s", vnp->name); 2459 } else 2460 n += scnpr(buff, buff_len, "%s", sg_sfs_sbc_reserved); 2461 } else if (sfs_code < 0x300) { /* SSC Feature Sets */ 2462 if (vnp) { 2463 if (verbose) 2464 n += scnpr(buff, buff_len, "SSC %s", vnp->name); 2465 else 2466 n += scnpr(buff, buff_len, "%s", vnp->name); 2467 } else 2468 n += scnpr(buff, buff_len, "%s", sg_sfs_ssc_reserved); 2469 } else if (sfs_code < 0x400) { /* ZBC Feature Sets */ 2470 if (vnp) { 2471 if (verbose) 2472 n += scnpr(buff, buff_len, "ZBC %s", vnp->name); 2473 else 2474 n += scnpr(buff, buff_len, "%s", vnp->name); 2475 } else 2476 n += scnpr(buff, buff_len, "%s", sg_sfs_zbc_reserved); 2477 } else { /* Other SCSI Feature Sets */ 2478 if (vnp) { 2479 if (verbose) 2480 n += scnpr(buff, buff_len, "[unrecognized PDT] %s", 2481 vnp->name); 2482 else 2483 n += scnpr(buff, buff_len, "%s", vnp->name); 2484 } else 2485 n += scnpr(buff, buff_len, "%s", sg_sfs_reserved); 2486 2487 } 2488 if (verbose > 4) 2489 pr2serr("%s: length of returned string (n) %d\n", __func__, n); 2490 return buff; 2491 } 2492 2493 /* This is a heuristic that takes into account the command bytes and length 2494 * to decide whether the presented unstructured sequence of bytes could be 2495 * a SCSI command. If so it returns true otherwise false. Vendor specific 2496 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed 2497 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The 2498 * only SCSI commands considered above 16 bytes of length are the Variable 2499 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e). 2500 * Both have an inbuilt length field which can be cross checked with clen. 2501 * No NVMe commands (64 bytes long plus some extra added by some OSes) have 2502 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS 2503 * structures that are sent across the wire. The FIS register structure is 2504 * used to move a command from a SATA host to device, but the ATA 'command' 2505 * is not the first byte. So it is harder to say what will happen if a 2506 * FIS structure is presented as a SCSI command, hopfully there is a low 2507 * probability this function will yield true in that case. */ 2508 bool 2509 sg_is_scsi_cdb(const uint8_t * cdbp, int clen) 2510 { 2511 int ilen, sa; 2512 uint8_t opcode; 2513 uint8_t top3bits; 2514 2515 if (clen < 6) 2516 return false; 2517 opcode = cdbp[0]; 2518 top3bits = opcode >> 5; 2519 if (0x3 == top3bits) { 2520 if ((clen < 12) || (clen % 4)) 2521 return false; /* must be modulo 4 and 12 or more bytes */ 2522 switch (opcode) { 2523 case 0x7e: /* Extended cdb (XCDB) */ 2524 ilen = 4 + sg_get_unaligned_be16(cdbp + 2); 2525 return (ilen == clen); 2526 case 0x7f: /* Variable Length cdb */ 2527 ilen = 8 + cdbp[7]; 2528 sa = sg_get_unaligned_be16(cdbp + 8); 2529 /* service action (sa) 0x0 is reserved */ 2530 return ((ilen == clen) && sa); 2531 default: 2532 return false; 2533 } 2534 } else if (clen <= 16) { 2535 switch (clen) { 2536 case 6: 2537 if (top3bits > 0x5) /* vendor */ 2538 return true; 2539 return (0x0 == top3bits); /* 6 byte cdb */ 2540 case 10: 2541 if (top3bits > 0x5) /* vendor */ 2542 return true; 2543 return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */ 2544 case 16: 2545 if (top3bits > 0x5) /* vendor */ 2546 return true; 2547 return (0x4 == top3bits); /* 16 byte cdb */ 2548 case 12: 2549 if (top3bits > 0x5) /* vendor */ 2550 return true; 2551 return (0x5 == top3bits); /* 12 byte cdb */ 2552 default: 2553 return false; 2554 } 2555 } 2556 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or 2557 * opcode > 0x7f). */ 2558 return false; 2559 } 2560 2561 /* Yield string associated with NVMe command status value in sct_sc. It 2562 * expects to decode DW3 bits 27:17 from the completion queue. Bits 27:25 2563 * are the Status Code Type (SCT) and bits 24:17 are the Status Code (SC). 2564 * Bit 17 in DW3 should be bit 0 in sct_sc. If no status string is found 2565 * a string of the form "Reserved [0x<sct_sc_in_hex>]" is generated. 2566 * Returns 'buff'. Does nothing if buff_len<=0 or if buff is NULL.*/ 2567 char * 2568 sg_get_nvme_cmd_status_str(uint16_t sct_sc, int b_len, char * b) 2569 { 2570 int k; 2571 uint16_t s = 0x3ff & sct_sc; 2572 const struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr; 2573 2574 if ((b_len <= 0) || (NULL == b)) 2575 return b; 2576 else if (1 == b_len) { 2577 b[0] = '\0'; 2578 return b; 2579 } 2580 for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) { 2581 if (s == (uint16_t)vp->value) { 2582 strncpy(b, vp->name, b_len); 2583 b[b_len - 1] = '\0'; 2584 return b; 2585 } 2586 } 2587 if (k >= 1000) 2588 pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n", 2589 __func__); 2590 snprintf(b, b_len, "Reserved [0x%x]", sct_sc); 2591 return b; 2592 } 2593 2594 /* Attempts to map NVMe status value ((SCT << 8) | SC) to SCSI status, 2595 * sense_key, asc and ascq tuple. If successful returns true and writes to 2596 * non-NULL pointer arguments; otherwise returns false. */ 2597 bool 2598 sg_nvme_status2scsi(uint16_t sct_sc, uint8_t * status_p, uint8_t * sk_p, 2599 uint8_t * asc_p, uint8_t * ascq_p) 2600 { 2601 int k, ind; 2602 uint16_t s = 0x3ff & sct_sc; 2603 struct sg_lib_value_name_t * vp = sg_lib_nvme_cmd_status_arr; 2604 struct sg_lib_4tuple_u8 * mp = sg_lib_scsi_status_sense_arr; 2605 2606 for (k = 0; (vp->name && (k < 1000)); ++k, ++vp) { 2607 if (s == (uint16_t)vp->value) 2608 break; 2609 } 2610 if (k >= 1000) { 2611 pr2ws("%s: where is sentinel for sg_lib_nvme_cmd_status_arr ??\n", 2612 __func__); 2613 return false; 2614 } 2615 if (NULL == vp->name) 2616 return false; 2617 ind = vp->peri_dev_type; 2618 2619 2620 for (k = 0; (0xff != mp->t2) && k < 1000; ++k, ++mp) 2621 ; /* count entries for valid index range */ 2622 if (k >= 1000) { 2623 pr2ws("%s: where is sentinel for sg_lib_scsi_status_sense_arr ??\n", 2624 __func__); 2625 return false; 2626 } else if (ind >= k) 2627 return false; 2628 mp = sg_lib_scsi_status_sense_arr + ind; 2629 if (status_p) 2630 *status_p = mp->t1; 2631 if (sk_p) 2632 *sk_p = mp->t2; 2633 if (asc_p) 2634 *asc_p = mp->t3; 2635 if (ascq_p) 2636 *ascq_p = mp->t4; 2637 return true; 2638 } 2639 2640 /* safe_strerror() contributed by Clayton Weaver <cgweav at email dot com> 2641 * Allows for situation in which strerror() is given a wild value (or the 2642 * C library is incomplete) and returns NULL. Still not thread safe. 2643 */ 2644 2645 static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 2646 'e', 'r', 'r', 'n', 'o', ':', ' ', 0}; 2647 2648 char * 2649 safe_strerror(int errnum) 2650 { 2651 size_t len; 2652 char * errstr; 2653 2654 if (errnum < 0) 2655 errnum = -errnum; 2656 errstr = strerror(errnum); 2657 if (NULL == errstr) { 2658 len = strlen(safe_errbuf); 2659 scnpr(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum); 2660 return safe_errbuf; 2661 } 2662 return errstr; 2663 } 2664 2665 static void 2666 trimTrailingSpaces(char * b) 2667 { 2668 int k; 2669 2670 for (k = ((int)strlen(b) - 1); k >= 0; --k) { 2671 if (' ' != b[k]) 2672 break; 2673 } 2674 if ('\0' != b[k + 1]) 2675 b[k + 1] = '\0'; 2676 } 2677 2678 /* Note the ASCII-hex output goes to stdout. [Most other output from functions 2679 * in this file go to sg_warnings_strm (default stderr).] 2680 * 'no_ascii' allows for 3 output types: 2681 * > 0 each line has address then up to 16 ASCII-hex bytes 2682 * = 0 in addition, the bytes are listed in ASCII to the right 2683 * < 0 only the ASCII-hex bytes are listed (i.e. without address) */ 2684 static void 2685 dStrHexFp(const char* str, int len, int no_ascii, FILE * fp) 2686 { 2687 const char * p = str; 2688 const char * formatstr; 2689 unsigned char c; 2690 char buff[82]; 2691 int a = 0; 2692 int bpstart = 5; 2693 const int cpstart = 60; 2694 int cpos = cpstart; 2695 int bpos = bpstart; 2696 int i, k, blen; 2697 2698 if (len <= 0) 2699 return; 2700 blen = (int)sizeof(buff); 2701 if (0 == no_ascii) /* address at left and ASCII at right */ 2702 formatstr = "%.76s\n"; 2703 else /* previously when > 0 str was "%.58s\n" */ 2704 formatstr = "%s\n"; /* when < 0 str was: "%.48s\n" */ 2705 memset(buff, ' ', 80); 2706 buff[80] = '\0'; 2707 if (no_ascii < 0) { 2708 bpstart = 0; 2709 bpos = bpstart; 2710 for (k = 0; k < len; k++) { 2711 c = *p++; 2712 if (bpos == (bpstart + (8 * 3))) 2713 bpos++; 2714 scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c); 2715 buff[bpos + 2] = ' '; 2716 if ((k > 0) && (0 == ((k + 1) % 16))) { 2717 trimTrailingSpaces(buff); 2718 fprintf(fp, formatstr, buff); 2719 bpos = bpstart; 2720 memset(buff, ' ', 80); 2721 } else 2722 bpos += 3; 2723 } 2724 if (bpos > bpstart) { 2725 buff[bpos + 2] = '\0'; 2726 trimTrailingSpaces(buff); 2727 fprintf(fp, "%s\n", buff); 2728 } 2729 return; 2730 } 2731 /* no_ascii>=0, start each line with address (offset) */ 2732 k = scnpr(buff + 1, blen - 1, "%.2x", a); 2733 buff[k + 1] = ' '; 2734 2735 for (i = 0; i < len; i++) { 2736 c = *p++; 2737 bpos += 3; 2738 if (bpos == (bpstart + (9 * 3))) 2739 bpos++; 2740 scnpr(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c); 2741 buff[bpos + 2] = ' '; 2742 if (no_ascii) 2743 buff[cpos++] = ' '; 2744 else { 2745 if (! my_isprint(c)) 2746 c = '.'; 2747 buff[cpos++] = c; 2748 } 2749 if (cpos > (cpstart + 15)) { 2750 if (no_ascii) 2751 trimTrailingSpaces(buff); 2752 fprintf(fp, formatstr, buff); 2753 bpos = bpstart; 2754 cpos = cpstart; 2755 a += 16; 2756 memset(buff, ' ', 80); 2757 k = scnpr(buff + 1, blen - 1, "%.2x", a); 2758 buff[k + 1] = ' '; 2759 } 2760 } 2761 if (cpos > cpstart) { 2762 buff[cpos] = '\0'; 2763 if (no_ascii) 2764 trimTrailingSpaces(buff); 2765 fprintf(fp, "%s\n", buff); 2766 } 2767 } 2768 2769 void 2770 dStrHex(const char* str, int len, int no_ascii) 2771 { 2772 dStrHexFp(str, len, no_ascii, stdout); 2773 } 2774 2775 void 2776 dStrHexErr(const char* str, int len, int no_ascii) 2777 { 2778 dStrHexFp(str, len, no_ascii, 2779 (sg_warnings_strm ? sg_warnings_strm : stderr)); 2780 } 2781 2782 #define DSHS_LINE_BLEN 160 2783 #define DSHS_BPL 16 2784 2785 /* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space 2786 * separated) to 'b' not to exceed 'b_len' characters. Each line 2787 * starts with 'leadin' (NULL for no leadin) and there are 16 bytes 2788 * per line with an extra space between the 8th and 9th bytes. 'format' 2789 * is 0 for repeat in printable ASCII ('.' for non printable) to 2790 * right of each line; 1 don't (so just output ASCII hex). Returns 2791 * number of bytes written to 'b' excluding the trailing '\0'. */ 2792 int 2793 dStrHexStr(const char * str, int len, const char * leadin, int format, 2794 int b_len, char * b) 2795 { 2796 unsigned char c; 2797 int bpstart, bpos, k, n, prior_ascii_len; 2798 bool want_ascii; 2799 char buff[DSHS_LINE_BLEN + 2]; 2800 char a[DSHS_BPL + 1]; 2801 const char * p = str; 2802 2803 if (len <= 0) { 2804 if (b_len > 0) 2805 b[0] = '\0'; 2806 return 0; 2807 } 2808 if (b_len <= 0) 2809 return 0; 2810 want_ascii = !format; 2811 if (want_ascii) { 2812 memset(a, ' ', DSHS_BPL); 2813 a[DSHS_BPL] = '\0'; 2814 } 2815 if (leadin) { 2816 bpstart = strlen(leadin); 2817 /* Cap leadin at (DSHS_LINE_BLEN - 70) characters */ 2818 if (bpstart > (DSHS_LINE_BLEN - 70)) 2819 bpstart = DSHS_LINE_BLEN - 70; 2820 } else 2821 bpstart = 0; 2822 bpos = bpstart; 2823 prior_ascii_len = bpstart + (DSHS_BPL * 3) + 1; 2824 n = 0; 2825 memset(buff, ' ', DSHS_LINE_BLEN); 2826 buff[DSHS_LINE_BLEN] = '\0'; 2827 if (bpstart > 0) 2828 memcpy(buff, leadin, bpstart); 2829 for (k = 0; k < len; k++) { 2830 c = *p++; 2831 if (bpos == (bpstart + ((DSHS_BPL / 2) * 3))) 2832 bpos++; /* for extra space in middle of each line's hex */ 2833 scnpr(buff + bpos, (int)sizeof(buff) - bpos, "%.2x", 2834 (int)(unsigned char)c); 2835 buff[bpos + 2] = ' '; 2836 if (want_ascii) 2837 a[k % DSHS_BPL] = my_isprint(c) ? c : '.'; 2838 if ((k > 0) && (0 == ((k + 1) % DSHS_BPL))) { 2839 trimTrailingSpaces(buff); 2840 if (want_ascii) { 2841 n += scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len, 2842 buff, a); 2843 memset(a, ' ', DSHS_BPL); 2844 } else 2845 n += scnpr(b + n, b_len - n, "%s\n", buff); 2846 if (n >= (b_len - 1)) 2847 return n; 2848 memset(buff, ' ', DSHS_LINE_BLEN); 2849 bpos = bpstart; 2850 if (bpstart > 0) 2851 memcpy(buff, leadin, bpstart); 2852 } else 2853 bpos += 3; 2854 } 2855 if (bpos > bpstart) { 2856 trimTrailingSpaces(buff); 2857 if (want_ascii) 2858 n += scnpr(b + n, b_len - n, "%-*s %s\n", prior_ascii_len, 2859 buff, a); 2860 else 2861 n += scnpr(b + n, b_len - n, "%s\n", buff); 2862 } 2863 return n; 2864 } 2865 2866 void 2867 hex2stdout(const uint8_t * b_str, int len, int no_ascii) 2868 { 2869 dStrHex((const char *)b_str, len, no_ascii); 2870 } 2871 2872 void 2873 hex2stderr(const uint8_t * b_str, int len, int no_ascii) 2874 { 2875 dStrHexErr((const char *)b_str, len, no_ascii); 2876 } 2877 2878 int 2879 hex2str(const uint8_t * b_str, int len, const char * leadin, int format, 2880 int b_len, char * b) 2881 { 2882 return dStrHexStr((const char *)b_str, len, leadin, format, b_len, b); 2883 } 2884 2885 /* Returns true when executed on big endian machine; else returns false. 2886 * Useful for displaying ATA identify words (which need swapping on a 2887 * big endian machine). */ 2888 bool 2889 sg_is_big_endian() 2890 { 2891 union u_t { 2892 uint16_t s; 2893 unsigned char c[sizeof(uint16_t)]; 2894 } u; 2895 2896 u.s = 0x0102; 2897 return (u.c[0] == 0x01); /* The lowest address contains 2898 the most significant byte */ 2899 } 2900 2901 bool 2902 sg_all_zeros(const uint8_t * bp, int b_len) 2903 { 2904 if ((NULL == bp) || (b_len <= 0)) 2905 return false; 2906 for (--b_len; b_len >= 0; --b_len) { 2907 if (0x0 != bp[b_len]) 2908 return false; 2909 } 2910 return true; 2911 } 2912 2913 bool 2914 sg_all_ffs(const uint8_t * bp, int b_len) 2915 { 2916 if ((NULL == bp) || (b_len <= 0)) 2917 return false; 2918 for (--b_len; b_len >= 0; --b_len) { 2919 if (0xff != bp[b_len]) 2920 return false; 2921 } 2922 return true; 2923 } 2924 2925 static uint16_t 2926 swapb_uint16(uint16_t u) 2927 { 2928 uint16_t r; 2929 2930 r = (u >> 8) & 0xff; 2931 r |= ((u & 0xff) << 8); 2932 return r; 2933 } 2934 2935 /* Note the ASCII-hex output goes to stdout. [Most other output from functions 2936 * in this file go to sg_warnings_strm (default stderr).] 2937 * 'no_ascii' allows for 3 output types: 2938 * > 0 each line has address then up to 8 ASCII-hex 16 bit words 2939 * = 0 in addition, the ASCI bytes pairs are listed to the right 2940 * = -1 only the ASCII-hex words are listed (i.e. without address) 2941 * = -2 only the ASCII-hex words, formatted for "hdparm --Istdin" 2942 * < -2 same as -1 2943 * If 'swapb' is true then bytes in each word swapped. Needs to be set 2944 * for ATA IDENTIFY DEVICE response on big-endian machines. */ 2945 void 2946 dWordHex(const uint16_t* words, int num, int no_ascii, bool swapb) 2947 { 2948 const uint16_t * p = words; 2949 uint16_t c; 2950 char buff[82]; 2951 unsigned char upp, low; 2952 int a = 0; 2953 const int bpstart = 3; 2954 const int cpstart = 52; 2955 int cpos = cpstart; 2956 int bpos = bpstart; 2957 int i, k, blen; 2958 2959 if (num <= 0) 2960 return; 2961 blen = (int)sizeof(buff); 2962 memset(buff, ' ', 80); 2963 buff[80] = '\0'; 2964 if (no_ascii < 0) { 2965 for (k = 0; k < num; k++) { 2966 c = *p++; 2967 if (swapb) 2968 c = swapb_uint16(c); 2969 bpos += 5; 2970 scnpr(buff + bpos, blen - bpos, "%.4x", (unsigned int)c); 2971 buff[bpos + 4] = ' '; 2972 if ((k > 0) && (0 == ((k + 1) % 8))) { 2973 if (-2 == no_ascii) 2974 printf("%.39s\n", buff +8); 2975 else 2976 printf("%.47s\n", buff); 2977 bpos = bpstart; 2978 memset(buff, ' ', 80); 2979 } 2980 } 2981 if (bpos > bpstart) { 2982 if (-2 == no_ascii) 2983 printf("%.39s\n", buff +8); 2984 else 2985 printf("%.47s\n", buff); 2986 } 2987 return; 2988 } 2989 /* no_ascii>=0, start each line with address (offset) */ 2990 k = scnpr(buff + 1, blen - 1, "%.2x", a); 2991 buff[k + 1] = ' '; 2992 2993 for (i = 0; i < num; i++) { 2994 c = *p++; 2995 if (swapb) 2996 c = swapb_uint16(c); 2997 bpos += 5; 2998 scnpr(buff + bpos, blen - bpos, "%.4x", (unsigned int)c); 2999 buff[bpos + 4] = ' '; 3000 if (no_ascii) { 3001 buff[cpos++] = ' '; 3002 buff[cpos++] = ' '; 3003 buff[cpos++] = ' '; 3004 } else { 3005 upp = (c >> 8) & 0xff; 3006 low = c & 0xff; 3007 if (! my_isprint(upp)) 3008 upp = '.'; 3009 buff[cpos++] = upp; 3010 if (! my_isprint(low)) 3011 low = '.'; 3012 buff[cpos++] = low; 3013 buff[cpos++] = ' '; 3014 } 3015 if (cpos > (cpstart + 23)) { 3016 printf("%.76s\n", buff); 3017 bpos = bpstart; 3018 cpos = cpstart; 3019 a += 8; 3020 memset(buff, ' ', 80); 3021 k = scnpr(buff + 1, blen - 1, "%.2x", a); 3022 buff[k + 1] = ' '; 3023 } 3024 } 3025 if (cpos > cpstart) 3026 printf("%.76s\n", buff); 3027 } 3028 3029 /* If the number in 'buf' can be decoded or the multiplier is unknown 3030 * then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal 3031 * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)). 3032 * Main (SI) multipliers supported: K, M, G. Ignore leading spaces and 3033 * tabs; accept comma, hyphen, space, tab and hash as terminator. */ 3034 int 3035 sg_get_num(const char * buf) 3036 { 3037 int res, num, n, len; 3038 unsigned int unum; 3039 char * cp; 3040 const char * b; 3041 char c = 'c'; 3042 char c2 = '\0'; /* keep static checker happy */ 3043 char c3 = '\0'; /* keep static checker happy */ 3044 char lb[16]; 3045 3046 if ((NULL == buf) || ('\0' == buf[0])) 3047 return -1; 3048 len = strlen(buf); 3049 n = strspn(buf, " \t"); 3050 if (n > 0) { 3051 if (n == len) 3052 return -1; 3053 buf += n; 3054 len -= n; 3055 } 3056 /* following hack to keep C++ happy */ 3057 cp = strpbrk((char *)buf, " \t,#-"); 3058 if (cp) { 3059 len = cp - buf; 3060 n = (int)sizeof(lb) - 1; 3061 len = (len < n) ? len : n; 3062 memcpy(lb, buf, len); 3063 lb[len] = '\0'; 3064 b = lb; 3065 } else 3066 b = buf; 3067 if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { 3068 res = sscanf(b + 2, "%x", &unum); 3069 num = unum; 3070 } else if ('H' == toupper((int)b[len - 1])) { 3071 res = sscanf(b, "%x", &unum); 3072 num = unum; 3073 } else 3074 res = sscanf(b, "%d%c%c%c", &num, &c, &c2, &c3); 3075 if (res < 1) 3076 return -1LL; 3077 else if (1 == res) 3078 return num; 3079 else { 3080 if (res > 2) 3081 c2 = toupper((int)c2); 3082 if (res > 3) 3083 c3 = toupper((int)c3); 3084 switch (toupper((int)c)) { 3085 case 'C': 3086 return num; 3087 case 'W': 3088 return num * 2; 3089 case 'B': 3090 return num * 512; 3091 case 'K': 3092 if (2 == res) 3093 return num * 1024; 3094 if (('B' == c2) || ('D' == c2)) 3095 return num * 1000; 3096 if (('I' == c2) && (4 == res) && ('B' == c3)) 3097 return num * 1024; 3098 return -1; 3099 case 'M': 3100 if (2 == res) 3101 return num * 1048576; 3102 if (('B' == c2) || ('D' == c2)) 3103 return num * 1000000; 3104 if (('I' == c2) && (4 == res) && ('B' == c3)) 3105 return num * 1048576; 3106 return -1; 3107 case 'G': 3108 if (2 == res) 3109 return num * 1073741824; 3110 if (('B' == c2) || ('D' == c2)) 3111 return num * 1000000000; 3112 if (('I' == c2) && (4 == res) && ('B' == c3)) 3113 return num * 1073741824; 3114 return -1; 3115 case 'X': 3116 cp = (char *)strchr(b, 'x'); 3117 if (NULL == cp) 3118 cp = (char *)strchr(b, 'X'); 3119 if (cp) { 3120 n = sg_get_num(cp + 1); 3121 if (-1 != n) 3122 return num * n; 3123 } 3124 return -1; 3125 default: 3126 pr2ws("unrecognized multiplier\n"); 3127 return -1; 3128 } 3129 } 3130 } 3131 3132 /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a 3133 * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is 3134 * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"), 3135 * a whitespace or newline as terminator. */ 3136 int 3137 sg_get_num_nomult(const char * buf) 3138 { 3139 int res, len, num; 3140 unsigned int unum; 3141 char * commap; 3142 3143 if ((NULL == buf) || ('\0' == buf[0])) 3144 return -1; 3145 len = strlen(buf); 3146 commap = (char *)strchr(buf + 1, ','); 3147 if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { 3148 res = sscanf(buf + 2, "%x", &unum); 3149 num = unum; 3150 } else if (commap && ('H' == toupper((int)*(commap - 1)))) { 3151 res = sscanf(buf, "%x", &unum); 3152 num = unum; 3153 } else if ((NULL == commap) && ('H' == toupper((int)buf[len - 1]))) { 3154 res = sscanf(buf, "%x", &unum); 3155 num = unum; 3156 } else 3157 res = sscanf(buf, "%d", &num); 3158 if (1 == res) 3159 return num; 3160 else 3161 return -1; 3162 } 3163 3164 /* If the number in 'buf' can be decoded or the multiplier is unknown 3165 * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal 3166 * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)). 3167 * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces 3168 * and tabs; accept comma, hyphen, space, tab and hash as terminator. */ 3169 int64_t 3170 sg_get_llnum(const char * buf) 3171 { 3172 int res, len, n; 3173 int64_t num, ll; 3174 uint64_t unum; 3175 char * cp; 3176 const char * b; 3177 char c = 'c'; 3178 char c2 = '\0'; /* keep static checker happy */ 3179 char c3 = '\0'; /* keep static checker happy */ 3180 char lb[32]; 3181 3182 if ((NULL == buf) || ('\0' == buf[0])) 3183 return -1LL; 3184 len = strlen(buf); 3185 n = strspn(buf, " \t"); 3186 if (n > 0) { 3187 if (n == len) 3188 return -1LL; 3189 buf += n; 3190 len -= n; 3191 } 3192 /* following hack to keep C++ happy */ 3193 cp = strpbrk((char *)buf, " \t,#-"); 3194 if (cp) { 3195 len = cp - buf; 3196 n = (int)sizeof(lb) - 1; 3197 len = (len < n) ? len : n; 3198 memcpy(lb, buf, len); 3199 lb[len] = '\0'; 3200 b = lb; 3201 } else 3202 b = buf; 3203 if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { 3204 res = sscanf(b + 2, "%" SCNx64 , &unum); 3205 num = unum; 3206 } else if ('H' == toupper((int)b[len - 1])) { 3207 res = sscanf(b, "%" SCNx64 , &unum); 3208 num = unum; 3209 } else 3210 res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3); 3211 if (res < 1) 3212 return -1LL; 3213 else if (1 == res) 3214 return num; 3215 else { 3216 if (res > 2) 3217 c2 = toupper((int)c2); 3218 if (res > 3) 3219 c3 = toupper((int)c3); 3220 switch (toupper((int)c)) { 3221 case 'C': 3222 return num; 3223 case 'W': 3224 return num * 2; 3225 case 'B': 3226 return num * 512; 3227 case 'K': 3228 if (2 == res) 3229 return num * 1024; 3230 if (('B' == c2) || ('D' == c2)) 3231 return num * 1000; 3232 if (('I' == c2) && (4 == res) && ('B' == c3)) 3233 return num * 1024; 3234 return -1LL; 3235 case 'M': 3236 if (2 == res) 3237 return num * 1048576; 3238 if (('B' == c2) || ('D' == c2)) 3239 return num * 1000000; 3240 if (('I' == c2) && (4 == res) && ('B' == c3)) 3241 return num * 1048576; 3242 return -1LL; 3243 case 'G': 3244 if (2 == res) 3245 return num * 1073741824; 3246 if (('B' == c2) || ('D' == c2)) 3247 return num * 1000000000; 3248 if (('I' == c2) && (4 == res) && ('B' == c3)) 3249 return num * 1073741824; 3250 return -1LL; 3251 case 'T': 3252 if (2 == res) 3253 return num * 1099511627776LL; 3254 if (('B' == c2) || ('D' == c2)) 3255 return num * 1000000000000LL; 3256 if (('I' == c2) && (4 == res) && ('B' == c3)) 3257 return num * 1099511627776LL; 3258 return -1LL; 3259 case 'P': 3260 if (2 == res) 3261 return num * 1099511627776LL * 1024; 3262 if (('B' == c2) || ('D' == c2)) 3263 return num * 1000000000000LL * 1000; 3264 if (('I' == c2) && (4 == res) && ('B' == c3)) 3265 return num * 1099511627776LL * 1024; 3266 return -1LL; 3267 case 'X': 3268 cp = (char *)strchr(b, 'x'); 3269 if (NULL == cp) 3270 cp = (char *)strchr(b, 'X'); 3271 if (cp) { 3272 ll = sg_get_llnum(cp + 1); 3273 if (-1LL != ll) 3274 return num * ll; 3275 } 3276 return -1LL; 3277 default: 3278 pr2ws("unrecognized multiplier\n"); 3279 return -1LL; 3280 } 3281 } 3282 } 3283 3284 /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a 3285 * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is 3286 * assumed. Does not accept multipliers. Accept a comma (","), hyphen ("-"), 3287 * a whitespace or newline as terminator. Only decimal numbers can represent 3288 * negative numbers and '-1' must be treated separately. */ 3289 int64_t 3290 sg_get_llnum_nomult(const char * buf) 3291 { 3292 int res, len; 3293 int64_t num; 3294 uint64_t unum; 3295 3296 if ((NULL == buf) || ('\0' == buf[0])) 3297 return -1; 3298 len = strlen(buf); 3299 if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { 3300 res = sscanf(buf + 2, "%" SCNx64 "", &unum); 3301 num = unum; 3302 } else if ('H' == toupper(buf[len - 1])) { 3303 res = sscanf(buf, "%" SCNx64 "", &unum); 3304 num = unum; 3305 } else 3306 res = sscanf(buf, "%" SCNd64 "", &num); 3307 return (1 == res) ? num : -1; 3308 } 3309 3310 /* Extract character sequence from ATA words as in the model string 3311 * in a IDENTIFY DEVICE response. Returns number of characters 3312 * written to 'ochars' before 0 character is found or 'num' words 3313 * are processed. */ 3314 int 3315 sg_ata_get_chars(const uint16_t * word_arr, int start_word, 3316 int num_words, bool is_big_endian, char * ochars) 3317 { 3318 int k; 3319 uint16_t s; 3320 char a, b; 3321 char * op = ochars; 3322 3323 for (k = start_word; k < (start_word + num_words); ++k) { 3324 s = word_arr[k]; 3325 if (is_big_endian) { 3326 a = s & 0xff; 3327 b = (s >> 8) & 0xff; 3328 } else { 3329 a = (s >> 8) & 0xff; 3330 b = s & 0xff; 3331 } 3332 if (a == 0) 3333 break; 3334 *op++ = a; 3335 if (b == 0) 3336 break; 3337 *op++ = b; 3338 } 3339 return op - ochars; 3340 } 3341 3342 int 3343 pr2serr(const char * fmt, ...) 3344 { 3345 va_list args; 3346 int n; 3347 3348 va_start(args, fmt); 3349 n = vfprintf(stderr, fmt, args); 3350 va_end(args); 3351 return n; 3352 } 3353 3354 #ifdef SG_LIB_FREEBSD 3355 #include <sys/param.h> 3356 #elif defined(SG_LIB_WIN32) 3357 #include <windows.h> 3358 3359 static bool got_page_size = false; 3360 static uint32_t win_page_size; 3361 #endif 3362 3363 uint32_t 3364 sg_get_page_size(void) 3365 { 3366 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) 3367 return sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ 3368 #elif defined(SG_LIB_WIN32) 3369 if (! got_page_size) { 3370 SYSTEM_INFO si; 3371 3372 GetSystemInfo(&si); 3373 win_page_size = si.dwPageSize; 3374 got_page_size = true; 3375 } 3376 return win_page_size; 3377 #elif defined(SG_LIB_FREEBSD) 3378 return PAGE_SIZE; 3379 #else 3380 return 4096; /* give up, pick likely figure */ 3381 #endif 3382 } 3383 3384 /* Returns pointer to heap (or NULL) that is aligned to a align_to byte 3385 * boundary. Sends back *buff_to_free pointer in third argument that may be 3386 * different from the return value. If it is different then the *buff_to_free 3387 * pointer should be freed (rather than the returned value) when the heap is 3388 * no longer needed. If align_to is 0 then aligns to OS's page size. Sets all 3389 * returned heap to zeros. If num_bytes is 0 then set to page size. */ 3390 uint8_t * 3391 sg_memalign(uint32_t num_bytes, uint32_t align_to, uint8_t ** buff_to_free, 3392 bool vb) 3393 { 3394 size_t psz; 3395 uint8_t * res; 3396 3397 if (buff_to_free) /* make sure buff_to_free is NULL if alloc fails */ 3398 *buff_to_free = NULL; 3399 psz = (align_to > 0) ? align_to : sg_get_page_size(); 3400 if (0 == num_bytes) 3401 num_bytes = psz; /* ugly to handle otherwise */ 3402 3403 #ifdef HAVE_POSIX_MEMALIGN 3404 { 3405 int err; 3406 void * wp = NULL; 3407 3408 err = posix_memalign(&wp, psz, num_bytes); 3409 if (err || (NULL == wp)) { 3410 pr2ws("%s: posix_memalign: error [%d], out of memory?\n", 3411 __func__, err); 3412 return NULL; 3413 } 3414 memset(wp, 0, num_bytes); 3415 if (buff_to_free) 3416 *buff_to_free = (uint8_t *)wp; 3417 res = (uint8_t *)wp; 3418 if (vb) { 3419 pr2ws("%s: posix_ma, len=%d, ", __func__, num_bytes); 3420 if (buff_to_free) 3421 pr2ws("wrkBuffp=%p, ", (void *)res); 3422 pr2ws("psz=%u, rp=%p\n", (unsigned int)psz, (void *)res); 3423 } 3424 return res; 3425 } 3426 #else 3427 { 3428 void * wrkBuff; 3429 sg_uintptr_t align_1 = psz - 1; 3430 3431 wrkBuff = (uint8_t *)calloc(num_bytes + psz, 1); 3432 if (NULL == wrkBuff) { 3433 if (buff_to_free) 3434 *buff_to_free = NULL; 3435 return NULL; 3436 } else if (buff_to_free) 3437 *buff_to_free = (uint8_t *)wrkBuff; 3438 res = (uint8_t *)(void *) 3439 (((sg_uintptr_t)wrkBuff + align_1) & (~align_1)); 3440 if (vb) { 3441 pr2ws("%s: hack, len=%d, ", __func__, num_bytes); 3442 if (buff_to_free) 3443 pr2ws("buff_to_free=%p, ", wrkBuff); 3444 pr2ws("align_1=%lu, rp=%p\n", (unsigned long)align_1, (void *)res); 3445 } 3446 return res; 3447 } 3448 #endif 3449 } 3450 3451 const char * 3452 sg_lib_version() 3453 { 3454 return sg_lib_version_str; 3455 } 3456 3457 3458 #ifdef SG_LIB_MINGW 3459 /* Non Unix OSes distinguish between text and binary files. 3460 Set text mode on fd. Does nothing in Unix. Returns negative number on 3461 failure. */ 3462 3463 #include <unistd.h> 3464 #include <fcntl.h> 3465 3466 int 3467 sg_set_text_mode(int fd) 3468 { 3469 return setmode(fd, O_TEXT); 3470 } 3471 3472 /* Set binary mode on fd. Does nothing in Unix. Returns negative number on 3473 failure. */ 3474 int 3475 sg_set_binary_mode(int fd) 3476 { 3477 return setmode(fd, O_BINARY); 3478 } 3479 3480 #else 3481 /* For Unix the following functions are dummies. */ 3482 int 3483 sg_set_text_mode(int fd) 3484 { 3485 return fd; /* fd should be >= 0 */ 3486 } 3487 3488 int 3489 sg_set_binary_mode(int fd) 3490 { 3491 return fd; 3492 } 3493 3494 #endif 3495