utils.c (21549B)
1/* 2 * SCSI helpers 3 * 4 * Copyright 2017 Red Hat, Inc. 5 * 6 * Authors: 7 * Fam Zheng <famz@redhat.com> 8 * Paolo Bonzini <pbonzini@redhat.com> 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the Free 12 * Software Foundation; either version 2 of the License, or (at your option) 13 * any later version. 14 */ 15 16#include "qemu/osdep.h" 17#include "scsi/constants.h" 18#include "scsi/utils.h" 19#include "qemu/bswap.h" 20 21uint32_t scsi_data_cdb_xfer(uint8_t *buf) 22{ 23 if ((buf[0] >> 5) == 0 && buf[4] == 0) { 24 return 256; 25 } else { 26 return scsi_cdb_xfer(buf); 27 } 28} 29 30uint32_t scsi_cdb_xfer(uint8_t *buf) 31{ 32 switch (buf[0] >> 5) { 33 case 0: 34 return buf[4]; 35 case 1: 36 case 2: 37 return lduw_be_p(&buf[7]); 38 case 4: 39 return ldl_be_p(&buf[10]) & 0xffffffffULL; 40 case 5: 41 return ldl_be_p(&buf[6]) & 0xffffffffULL; 42 default: 43 return -1; 44 } 45} 46 47uint64_t scsi_cmd_lba(SCSICommand *cmd) 48{ 49 uint8_t *buf = cmd->buf; 50 uint64_t lba; 51 52 switch (buf[0] >> 5) { 53 case 0: 54 lba = ldl_be_p(&buf[0]) & 0x1fffff; 55 break; 56 case 1: 57 case 2: 58 case 5: 59 lba = ldl_be_p(&buf[2]) & 0xffffffffULL; 60 break; 61 case 4: 62 lba = ldq_be_p(&buf[2]); 63 break; 64 default: 65 lba = -1; 66 67 } 68 return lba; 69} 70 71int scsi_cdb_length(uint8_t *buf) 72{ 73 int cdb_len; 74 75 switch (buf[0] >> 5) { 76 case 0: 77 cdb_len = 6; 78 break; 79 case 1: 80 case 2: 81 cdb_len = 10; 82 break; 83 case 4: 84 cdb_len = 16; 85 break; 86 case 5: 87 cdb_len = 12; 88 break; 89 default: 90 cdb_len = -1; 91 } 92 return cdb_len; 93} 94 95SCSISense scsi_parse_sense_buf(const uint8_t *in_buf, int in_len) 96{ 97 bool fixed_in; 98 SCSISense sense; 99 100 assert(in_len > 0); 101 fixed_in = (in_buf[0] & 2) == 0; 102 if (fixed_in) { 103 if (in_len < 14) { 104 return SENSE_CODE(IO_ERROR); 105 } 106 sense.key = in_buf[2]; 107 sense.asc = in_buf[12]; 108 sense.ascq = in_buf[13]; 109 } else { 110 if (in_len < 4) { 111 return SENSE_CODE(IO_ERROR); 112 } 113 sense.key = in_buf[1]; 114 sense.asc = in_buf[2]; 115 sense.ascq = in_buf[3]; 116 } 117 118 return sense; 119} 120 121int scsi_build_sense_buf(uint8_t *out_buf, size_t size, SCSISense sense, 122 bool fixed_sense) 123{ 124 int len; 125 uint8_t buf[SCSI_SENSE_LEN] = { 0 }; 126 127 if (fixed_sense) { 128 buf[0] = 0x70; 129 buf[2] = sense.key; 130 buf[7] = 10; 131 buf[12] = sense.asc; 132 buf[13] = sense.ascq; 133 len = 18; 134 } else { 135 buf[0] = 0x72; 136 buf[1] = sense.key; 137 buf[2] = sense.asc; 138 buf[3] = sense.ascq; 139 len = 8; 140 } 141 len = MIN(len, size); 142 memcpy(out_buf, buf, len); 143 return len; 144} 145 146int scsi_build_sense(uint8_t *buf, SCSISense sense) 147{ 148 return scsi_build_sense_buf(buf, SCSI_SENSE_LEN, sense, true); 149} 150 151/* 152 * Predefined sense codes 153 */ 154 155/* No sense data available */ 156const struct SCSISense sense_code_NO_SENSE = { 157 .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00 158}; 159 160/* LUN not ready, Manual intervention required */ 161const struct SCSISense sense_code_LUN_NOT_READY = { 162 .key = NOT_READY, .asc = 0x04, .ascq = 0x03 163}; 164 165/* LUN not ready, Medium not present */ 166const struct SCSISense sense_code_NO_MEDIUM = { 167 .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 168}; 169 170/* LUN not ready, medium removal prevented */ 171const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { 172 .key = NOT_READY, .asc = 0x53, .ascq = 0x02 173}; 174 175/* Hardware error, internal target failure */ 176const struct SCSISense sense_code_TARGET_FAILURE = { 177 .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 178}; 179 180/* Illegal request, invalid command operation code */ 181const struct SCSISense sense_code_INVALID_OPCODE = { 182 .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00 183}; 184 185/* Illegal request, LBA out of range */ 186const struct SCSISense sense_code_LBA_OUT_OF_RANGE = { 187 .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00 188}; 189 190/* Illegal request, Invalid field in CDB */ 191const struct SCSISense sense_code_INVALID_FIELD = { 192 .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00 193}; 194 195/* Illegal request, Invalid field in parameter list */ 196const struct SCSISense sense_code_INVALID_PARAM = { 197 .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00 198}; 199 200/* Illegal request, Invalid value in parameter list */ 201const struct SCSISense sense_code_INVALID_PARAM_VALUE = { 202 .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x01 203}; 204 205/* Illegal request, Parameter list length error */ 206const struct SCSISense sense_code_INVALID_PARAM_LEN = { 207 .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00 208}; 209 210/* Illegal request, LUN not supported */ 211const struct SCSISense sense_code_LUN_NOT_SUPPORTED = { 212 .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00 213}; 214 215/* Illegal request, Saving parameters not supported */ 216const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = { 217 .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00 218}; 219 220/* Illegal request, Incompatible medium installed */ 221const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = { 222 .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 223}; 224 225/* Illegal request, medium removal prevented */ 226const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { 227 .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02 228}; 229 230/* Illegal request, Invalid Transfer Tag */ 231const struct SCSISense sense_code_INVALID_TAG = { 232 .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 233}; 234 235/* Command aborted, I/O process terminated */ 236const struct SCSISense sense_code_IO_ERROR = { 237 .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 238}; 239 240/* Command aborted, I_T Nexus loss occurred */ 241const struct SCSISense sense_code_I_T_NEXUS_LOSS = { 242 .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07 243}; 244 245/* Command aborted, Logical Unit failure */ 246const struct SCSISense sense_code_LUN_FAILURE = { 247 .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 248}; 249 250/* Command aborted, Overlapped Commands Attempted */ 251const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { 252 .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 253}; 254 255/* Command aborted, LUN Communication Failure */ 256const struct SCSISense sense_code_LUN_COMM_FAILURE = { 257 .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00 258}; 259 260/* Command aborted, LUN does not respond to selection */ 261const struct SCSISense sense_code_LUN_NOT_RESPONDING = { 262 .key = ABORTED_COMMAND, .asc = 0x05, .ascq = 0x00 263}; 264 265/* Command aborted, Command Timeout during processing */ 266const struct SCSISense sense_code_COMMAND_TIMEOUT = { 267 .key = ABORTED_COMMAND, .asc = 0x2e, .ascq = 0x02 268}; 269 270/* Command aborted, Commands cleared by device server */ 271const struct SCSISense sense_code_COMMAND_ABORTED = { 272 .key = ABORTED_COMMAND, .asc = 0x2f, .ascq = 0x02 273}; 274 275/* Medium Error, Unrecovered read error */ 276const struct SCSISense sense_code_READ_ERROR = { 277 .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00 278}; 279 280/* Not ready, Cause not reportable */ 281const struct SCSISense sense_code_NOT_READY = { 282 .key = NOT_READY, .asc = 0x04, .ascq = 0x00 283}; 284 285/* Unit attention, Capacity data has changed */ 286const struct SCSISense sense_code_CAPACITY_CHANGED = { 287 .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 288}; 289 290/* Unit attention, Power on, reset or bus device reset occurred */ 291const struct SCSISense sense_code_RESET = { 292 .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 293}; 294 295/* Unit attention, SCSI bus reset */ 296const struct SCSISense sense_code_SCSI_BUS_RESET = { 297 .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x02 298}; 299 300/* Unit attention, No medium */ 301const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { 302 .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 303}; 304 305/* Unit attention, Medium may have changed */ 306const struct SCSISense sense_code_MEDIUM_CHANGED = { 307 .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 308}; 309 310/* Unit attention, Reported LUNs data has changed */ 311const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = { 312 .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e 313}; 314 315/* Unit attention, Device internal reset */ 316const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = { 317 .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04 318}; 319 320/* Data Protection, Write Protected */ 321const struct SCSISense sense_code_WRITE_PROTECTED = { 322 .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00 323}; 324 325/* Data Protection, Space Allocation Failed Write Protect */ 326const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { 327 .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07 328}; 329 330/* 331 * scsi_convert_sense 332 * 333 * Convert between fixed and descriptor sense buffers 334 */ 335int scsi_convert_sense(uint8_t *in_buf, int in_len, 336 uint8_t *buf, int len, bool fixed) 337{ 338 SCSISense sense; 339 bool fixed_in; 340 341 if (in_len == 0) { 342 return scsi_build_sense_buf(buf, len, SENSE_CODE(NO_SENSE), fixed); 343 } 344 345 fixed_in = (in_buf[0] & 2) == 0; 346 if (fixed == fixed_in) { 347 memcpy(buf, in_buf, MIN(len, in_len)); 348 return MIN(len, in_len); 349 } else { 350 sense = scsi_parse_sense_buf(in_buf, in_len); 351 return scsi_build_sense_buf(buf, len, sense, fixed); 352 } 353} 354 355static bool scsi_sense_is_guest_recoverable(int key, int asc, int ascq) 356{ 357 switch (key) { 358 case NO_SENSE: 359 case RECOVERED_ERROR: 360 case UNIT_ATTENTION: 361 case ABORTED_COMMAND: 362 return true; 363 case NOT_READY: 364 case ILLEGAL_REQUEST: 365 case DATA_PROTECT: 366 /* Parse ASCQ */ 367 break; 368 default: 369 return false; 370 } 371 372 switch ((asc << 8) | ascq) { 373 case 0x1a00: /* PARAMETER LIST LENGTH ERROR */ 374 case 0x2000: /* INVALID OPERATION CODE */ 375 case 0x2400: /* INVALID FIELD IN CDB */ 376 case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ 377 case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ 378 379 case 0x2104: /* UNALIGNED WRITE COMMAND */ 380 case 0x2105: /* WRITE BOUNDARY VIOLATION */ 381 case 0x2106: /* ATTEMPT TO READ INVALID DATA */ 382 case 0x550e: /* INSUFFICIENT ZONE RESOURCES */ 383 384 case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */ 385 case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */ 386 return true; 387 default: 388 return false; 389 } 390} 391 392int scsi_sense_to_errno(int key, int asc, int ascq) 393{ 394 switch (key) { 395 case NO_SENSE: 396 case RECOVERED_ERROR: 397 case UNIT_ATTENTION: 398 return EAGAIN; 399 case ABORTED_COMMAND: /* COMMAND ABORTED */ 400 return ECANCELED; 401 case NOT_READY: 402 case ILLEGAL_REQUEST: 403 case DATA_PROTECT: 404 /* Parse ASCQ */ 405 break; 406 default: 407 return EIO; 408 } 409 switch ((asc << 8) | ascq) { 410 case 0x1a00: /* PARAMETER LIST LENGTH ERROR */ 411 case 0x2000: /* INVALID OPERATION CODE */ 412 case 0x2400: /* INVALID FIELD IN CDB */ 413 case 0x2600: /* INVALID FIELD IN PARAMETER LIST */ 414 return EINVAL; 415 case 0x2100: /* LBA OUT OF RANGE */ 416 case 0x2707: /* SPACE ALLOC FAILED */ 417 return ENOSPC; 418 case 0x2500: /* LOGICAL UNIT NOT SUPPORTED */ 419 return ENOTSUP; 420 case 0x3a00: /* MEDIUM NOT PRESENT */ 421 case 0x3a01: /* MEDIUM NOT PRESENT TRAY CLOSED */ 422 case 0x3a02: /* MEDIUM NOT PRESENT TRAY OPEN */ 423 return ENOMEDIUM; 424 case 0x2700: /* WRITE PROTECTED */ 425 return EACCES; 426 case 0x0401: /* NOT READY, IN PROGRESS OF BECOMING READY */ 427 return EINPROGRESS; 428 case 0x0402: /* NOT READY, INITIALIZING COMMAND REQUIRED */ 429 return ENOTCONN; 430 default: 431 return EIO; 432 } 433} 434 435int scsi_sense_buf_to_errno(const uint8_t *in_buf, size_t in_len) 436{ 437 SCSISense sense; 438 if (in_len < 1) { 439 return EIO; 440 } 441 442 sense = scsi_parse_sense_buf(in_buf, in_len); 443 return scsi_sense_to_errno(sense.key, sense.asc, sense.ascq); 444} 445 446bool scsi_sense_buf_is_guest_recoverable(const uint8_t *in_buf, size_t in_len) 447{ 448 SCSISense sense; 449 if (in_len < 1) { 450 return false; 451 } 452 453 sense = scsi_parse_sense_buf(in_buf, in_len); 454 return scsi_sense_is_guest_recoverable(sense.key, sense.asc, sense.ascq); 455} 456 457const char *scsi_command_name(uint8_t cmd) 458{ 459 static const char *names[] = { 460 [ TEST_UNIT_READY ] = "TEST_UNIT_READY", 461 [ REWIND ] = "REWIND", 462 [ REQUEST_SENSE ] = "REQUEST_SENSE", 463 [ FORMAT_UNIT ] = "FORMAT_UNIT", 464 [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS", 465 [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS", 466 /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */ 467 [ READ_6 ] = "READ_6", 468 [ WRITE_6 ] = "WRITE_6", 469 [ SET_CAPACITY ] = "SET_CAPACITY", 470 [ READ_REVERSE ] = "READ_REVERSE", 471 [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", 472 [ SPACE ] = "SPACE", 473 [ INQUIRY ] = "INQUIRY", 474 [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA", 475 [ MAINTENANCE_IN ] = "MAINTENANCE_IN", 476 [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT", 477 [ MODE_SELECT ] = "MODE_SELECT", 478 [ RESERVE ] = "RESERVE", 479 [ RELEASE ] = "RELEASE", 480 [ COPY ] = "COPY", 481 [ ERASE ] = "ERASE", 482 [ MODE_SENSE ] = "MODE_SENSE", 483 [ START_STOP ] = "START_STOP/LOAD_UNLOAD", 484 /* LOAD_UNLOAD and START_STOP use the same operation code */ 485 [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC", 486 [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC", 487 [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL", 488 [ READ_CAPACITY_10 ] = "READ_CAPACITY_10", 489 [ READ_10 ] = "READ_10", 490 [ WRITE_10 ] = "WRITE_10", 491 [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT", 492 /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */ 493 [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10", 494 [ VERIFY_10 ] = "VERIFY_10", 495 [ SEARCH_HIGH ] = "SEARCH_HIGH", 496 [ SEARCH_EQUAL ] = "SEARCH_EQUAL", 497 [ SEARCH_LOW ] = "SEARCH_LOW", 498 [ SET_LIMITS ] = "SET_LIMITS", 499 [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION", 500 /* READ_POSITION and PRE_FETCH use the same operation code */ 501 [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", 502 [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", 503 [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE", 504 /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */ 505 [ MEDIUM_SCAN ] = "MEDIUM_SCAN", 506 [ COMPARE ] = "COMPARE", 507 [ COPY_VERIFY ] = "COPY_VERIFY", 508 [ WRITE_BUFFER ] = "WRITE_BUFFER", 509 [ READ_BUFFER ] = "READ_BUFFER", 510 [ UPDATE_BLOCK ] = "UPDATE_BLOCK", 511 [ READ_LONG_10 ] = "READ_LONG_10", 512 [ WRITE_LONG_10 ] = "WRITE_LONG_10", 513 [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION", 514 [ WRITE_SAME_10 ] = "WRITE_SAME_10", 515 [ UNMAP ] = "UNMAP", 516 [ READ_TOC ] = "READ_TOC", 517 [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT", 518 [ SANITIZE ] = "SANITIZE", 519 [ GET_CONFIGURATION ] = "GET_CONFIGURATION", 520 [ LOG_SELECT ] = "LOG_SELECT", 521 [ LOG_SENSE ] = "LOG_SENSE", 522 [ MODE_SELECT_10 ] = "MODE_SELECT_10", 523 [ RESERVE_10 ] = "RESERVE_10", 524 [ RELEASE_10 ] = "RELEASE_10", 525 [ MODE_SENSE_10 ] = "MODE_SENSE_10", 526 [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN", 527 [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT", 528 [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16", 529 [ EXTENDED_COPY ] = "EXTENDED_COPY", 530 [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16", 531 [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN", 532 [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT", 533 [ READ_16 ] = "READ_16", 534 [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE", 535 [ WRITE_16 ] = "WRITE_16", 536 [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", 537 [ VERIFY_16 ] = "VERIFY_16", 538 [ PRE_FETCH_16 ] = "PRE_FETCH_16", 539 [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", 540 /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ 541 [ LOCATE_16 ] = "LOCATE_16", 542 [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16", 543 /* ERASE_16 and WRITE_SAME_16 use the same operation code */ 544 [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", 545 [ WRITE_LONG_16 ] = "WRITE_LONG_16", 546 [ REPORT_LUNS ] = "REPORT_LUNS", 547 [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12", 548 [ MOVE_MEDIUM ] = "MOVE_MEDIUM", 549 [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM", 550 [ READ_12 ] = "READ_12", 551 [ WRITE_12 ] = "WRITE_12", 552 [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE", 553 /* ERASE_12 and GET_PERFORMANCE use the same operation code */ 554 [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12", 555 [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", 556 [ VERIFY_12 ] = "VERIFY_12", 557 [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12", 558 [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", 559 [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", 560 [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", 561 [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING", 562 /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ 563 [ READ_CD ] = "READ_CD", 564 [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12", 565 [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE", 566 [ RESERVE_TRACK ] = "RESERVE_TRACK", 567 [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET", 568 [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE", 569 [ SET_CD_SPEED ] = "SET_CD_SPEED", 570 [ SET_READ_AHEAD ] = "SET_READ_AHEAD", 571 [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE", 572 [ MECHANISM_STATUS ] = "MECHANISM_STATUS", 573 [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION", 574 [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION", 575 }; 576 577 if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) { 578 return "*UNKNOWN*"; 579 } 580 return names[cmd]; 581} 582 583int scsi_sense_from_errno(int errno_value, SCSISense *sense) 584{ 585 switch (errno_value) { 586 case 0: 587 return GOOD; 588 case EDOM: 589 return TASK_SET_FULL; 590#ifdef CONFIG_LINUX 591 /* These errno mapping are specific to Linux. For more information: 592 * - scsi_check_sense and scsi_decide_disposition in drivers/scsi/scsi_error.c 593 * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c 594 * - blk_errors[] in block/blk-core.c 595 */ 596 case EBADE: 597 return RESERVATION_CONFLICT; 598 case ENODATA: 599 *sense = SENSE_CODE(READ_ERROR); 600 return CHECK_CONDITION; 601 case EREMOTEIO: 602 *sense = SENSE_CODE(TARGET_FAILURE); 603 return CHECK_CONDITION; 604#endif 605 case ENOMEDIUM: 606 *sense = SENSE_CODE(NO_MEDIUM); 607 return CHECK_CONDITION; 608 case ENOMEM: 609 *sense = SENSE_CODE(TARGET_FAILURE); 610 return CHECK_CONDITION; 611 case EINVAL: 612 *sense = SENSE_CODE(INVALID_FIELD); 613 return CHECK_CONDITION; 614 case ENOSPC: 615 *sense = SENSE_CODE(SPACE_ALLOC_FAILED); 616 return CHECK_CONDITION; 617 default: 618 *sense = SENSE_CODE(IO_ERROR); 619 return CHECK_CONDITION; 620 } 621} 622 623int scsi_sense_from_host_status(uint8_t host_status, 624 SCSISense *sense) 625{ 626 switch (host_status) { 627 case SCSI_HOST_NO_LUN: 628 *sense = SENSE_CODE(LUN_NOT_RESPONDING); 629 return CHECK_CONDITION; 630 case SCSI_HOST_BUSY: 631 return BUSY; 632 case SCSI_HOST_TIME_OUT: 633 *sense = SENSE_CODE(COMMAND_TIMEOUT); 634 return CHECK_CONDITION; 635 case SCSI_HOST_BAD_RESPONSE: 636 *sense = SENSE_CODE(LUN_COMM_FAILURE); 637 return CHECK_CONDITION; 638 case SCSI_HOST_ABORTED: 639 *sense = SENSE_CODE(COMMAND_ABORTED); 640 return CHECK_CONDITION; 641 case SCSI_HOST_RESET: 642 *sense = SENSE_CODE(RESET); 643 return CHECK_CONDITION; 644 case SCSI_HOST_TRANSPORT_DISRUPTED: 645 *sense = SENSE_CODE(I_T_NEXUS_LOSS); 646 return CHECK_CONDITION; 647 case SCSI_HOST_TARGET_FAILURE: 648 *sense = SENSE_CODE(TARGET_FAILURE); 649 return CHECK_CONDITION; 650 case SCSI_HOST_RESERVATION_ERROR: 651 return RESERVATION_CONFLICT; 652 case SCSI_HOST_ALLOCATION_FAILURE: 653 *sense = SENSE_CODE(SPACE_ALLOC_FAILED); 654 return CHECK_CONDITION; 655 case SCSI_HOST_MEDIUM_ERROR: 656 *sense = SENSE_CODE(READ_ERROR); 657 return CHECK_CONDITION; 658 } 659 return GOOD; 660}