/* * Copyright 2004-2010, Haiku, Inc. All RightsReserved. * Copyright 2002/03, Thomas Kurschel. All rights reserved. * * Distributed under the terms of the MIT License. */ #ifndef _SCSI_CMDS_H #define _SCSI_CMDS_H //! SCSI commands and their data structures and constants #include // Always keep in mind that SCSI is big-endian! #define SCSI_STD_TIMEOUT 10 // SCSI device status (as the result of a command) #define SCSI_STATUS_GOOD (0 << 1) #define SCSI_STATUS_CHECK_CONDITION (1 << 1) // error occured #define SCSI_STATUS_CONDITION_MET (2 << 1) // "found" for SEARCH DATA and PREFETCH #define SCSI_STATUS_BUSY (4 << 1) // try again later (??? == QUEUE_FULL ???) #define SCSI_STATUS_INTERMEDIATE (8 << 1) // used by linked command only #define SCSI_STATUS_INTERMEDIATE_COND_MET (10 << 1) // ditto #define SCSI_STATUS_RESERVATION_CONFLICT (12 << 1) // only if RESERVE/RELEASE is used #define SCSI_STATUS_COMMAND_TERMINATED (17 << 1) // aborted by TERMINATE I/O PROCESS #define SCSI_STATUS_QUEUE_FULL (20 << 1) // queue full #define SCSI_STATUS_MASK 0xfe // SCSI sense key #define SCSIS_KEY_NO_SENSE 0 #define SCSIS_KEY_RECOVERED_ERROR 1 #define SCSIS_KEY_NOT_READY 2 // operator intervention may be required #define SCSIS_KEY_MEDIUM_ERROR 3 // can be set if source could be hardware error #define SCSIS_KEY_HARDWARE_ERROR 4 #define SCSIS_KEY_ILLEGAL_REQUEST 5 // invalid command #define SCSIS_KEY_UNIT_ATTENTION 6 // medium changed or target reset #define SCSIS_KEY_DATA_PROTECT 7 // data access forbidden #define SCSIS_KEY_BLANK_CHECK 8 // tried to read blank or to write non-blank medium #define SCSIS_KEY_VENDOR_SPECIFIC 9 #define SCSIS_KEY_COPY_ABORTED 10 // error in COPY or COMPARE command #define SCSIS_KEY_ABORTED_COMMAND 11 // aborted by target, retry *may* help #define SCSIS_KEY_EQUAL 12 // during SEARCH: data found #define SCSIS_KEY_VOLUME_OVERFLOW 13 // tried to write buffered data beyond end of medium #define SCSIS_KEY_MISCOMPARE 14 #define SCSIS_KEY_RESERVED 15 // SCSI ASC and ASCQ data - (ASC << 8) | ASCQ // all codes with bit 7 of ASC or ASCQ set are vendor-specific #define SCSIS_ASC_NO_SENSE 0x0000 #define SCSIS_ASC_IO_PROC_TERMINATED 0x0006 #define SCSIS_ASC_AUDIO_PLAYING 0x0011 #define SCSIS_ASC_AUDIO_PAUSED 0x0012 #define SCSIS_ASC_AUDIO_COMPLETED 0x0013 #define SCSIS_ASC_AUDIO_ERROR 0x0014 // playing has stopped due to error #define SCSIS_ASC_AUDIO_NO_STATUS 0x0015 #define SCSIS_ASC_NO_INDEX 0x0100 // no index/sector signal #define SCSIS_ASC_NO_SEEK_CMP 0x0200 // ??? #define SCSIS_ASC_WRITE_FAULT 0x0300 #define SCSIS_ASC_LUN_NOT_READY 0x0400 // LUN not ready, cause not reportable #define SCSIS_ASC_LUN_BECOMING_READY 0x0401 // LUN in progress of becoming ready #define SCSIS_ASC_LUN_NEED_INIT 0x0402 // LUN need initializing command #define SCSIS_ASC_LUN_NEED_MANUAL_HELP 0x0403 // LUN needs manual intervention #define SCSIS_ASC_LUN_FORMATTING 0x0404 // LUN format in progress #define SCSIS_ASC_LUN_SEL_FAILED 0x0500 // LUN doesn't respond to selection #define SCSIS_ASC_LUN_COM_FAILURE 0x0800 // LUN communication failure #define SCSIS_ASC_LUN_TIMEOUT 0x0801 // LUN communication time-out #define SCSIS_ASC_LUN_COM_PARITY 0x0802 // LUN communication parity failure #define SCSIS_ASC_LUN_COM_CRC 0x0803 // LUN communication CRC failure (SCSI-3) #define SCSIS_ASC_WRITE_ERR_AUTOREALLOC 0x0c01 // recovered by auto-reallocation #define SCSIS_ASC_WRITE_ERR_AUTOREALLOC_FAILED 0x0c02 #define SCSIS_ASC_ECC_ERROR 0x1000 #define SCSIS_ASC_UNREC_READ_ERR 0x1100 // unrecovered read error #define SCSIS_ASC_READ_RETRIES_EXH 0x1101 // read retries exhausted #define SCSIS_ASC_UNREC_READ_ERR_AUTOREALLOC_FAILED 0x1104 // above + auto-reallocate failed #define SCSIS_ASC_RECORD_NOT_FOUND 0x1401 #define SCSIS_ASC_RANDOM_POS_ERROR 0x1500 // random positioning error #define SCSIS_ASC_POSITIONING_ERR 0x1501 // mechanical positioning error #define SCSIS_ASC_POS_ERR_ON_READ 0x1502 // positioning error detected by reading #define SCSIS_ASC_DATA_RECOV_NO_ERR_CORR 0x1700 // recovered with no error correction applied #define SCSIS_ASC_DATA_RECOV_WITH_RETRIES 0x1701 #define SCSIS_ASC_DATA_RECOV_POS_HEAD_OFS 0x1702 // ?recovered with positive head offset #define SCSIS_ASC_DATA_RECOV_NEG_HEAD_OFS 0x1703 // ?recovered with negative head offset #define SCSIS_ASC_DATA_RECOV_WITH_RETRIES_CIRC 0x1704 // recovered with retries/CIRC #define SCSIS_ASC_DATA_RECOV_PREV_SECT_ID 0x1705 // recovered using previous sector ID #define SCSIS_ASC_DATA_RECOV_NO_ECC_AUTOREALLOC 0x1706 #define SCSIS_ASC_DATA_RECOV_NO_ECC_REASSIGN 0x1707 // reassign recommended #define SCSIS_ASC_DATA_RECOV_NO_ECC_REWRITE 0x1708 // rewrite recommended #define SCSIS_ASC_DATA_RECOV_WITH_CORR 0x1800 // recovered using error correction #define SCSIS_ASC_DATA_RECOV_WITH_CORR_RETRIES 0x1801 // used error correction and retries #define SCSIS_ASC_DATA_RECOV_AUTOREALLOC 0x1802 #define SCSIS_ASC_DATA_RECOV_CIRC 0x1803 // recovered using CIRC #define SCSIS_ASC_DATA_RECOV_LEC 0x1804 // recovered using LEC #define SCSIS_ASC_DATA_RECOV_REASSIGN 0x1805 // reassign recommended #define SCSIS_ASC_DATA_RECOV_REWRITE 0x1806 // rewrite recommended #define SCSIS_ASC_PARAM_LIST_LENGTH_ERR 0x1a00 // parameter list too short #define SCSIS_ASC_ID_RECOV 0x1e00 // recoved ID with ECC #define SCSIS_ASC_INV_OPCODE 0x2000 #define SCSIS_ASC_LBA_OOR 0x2100 // LBA out of range #define SCSIS_ASC_ILL_FUNCTION 0x2200 // better use 0x2000/0x2400/0x2600 instead #define SCSIS_ASC_INV_CDB_FIELD 0x2400 #define SCSIS_ASC_LUN_NOT_SUPPORTED 0x2500 #define SCSIS_ASC_INV_PARAM_LIST_FIELD 0x2600 #define SCSIS_ASC_PARAM_NOT_SUPPORTED 0x2601 #define SCSIS_ASC_PARAM_VALUE_INV 0x2602 #define SCSIS_ASC_WRITE_PROTECTED 0x2700 #define SCSIS_ASC_MEDIUM_CHANGED 0x2800 #define SCSIS_ASC_WAS_RESET 0x2900 // reset by power-on/bus reset/device reset #define SCSIS_ASC_PARAMS_CHANGED 0x2a00 #define SCSIS_ASC_MEDIUM_FORMAT_CORRUPTED 0x3100 #define SCSIS_ASC_ROUNDED_PARAM 0x3700 // parameter got rounded #define SCSIS_ASC_NO_MEDIUM 0x3a00 // medium not present #define SCSIS_ASC_INTERNAL_FAILURE 0x4400 #define SCSIS_ASC_SEL_FAILURE 0x4500 // select/reselect failure #define SCSIS_ASC_UNSUCC_SOFT_RESET 0x4600 // unsuccessful soft reset #define SCSIS_ASC_SCSI_PARITY_ERR 0x4700 // SCSI parity error #define SCSIS_ASC_LOAD_EJECT_FAILED 0x5300 // media load or eject failed #define SCSIS_ASC_REMOVAL_PREVENTED 0x5302 // medium removal prevented #define SCSIS_ASC_REMOVAL_REQUESTED 0x5a01 // operator requests medium removal // some scsi op-codes #define SCSI_OP_TEST_UNIT_READY 0x00 #define SCSI_OP_REQUEST_SENSE 0x03 #define SCSI_OP_FORMAT 0x04 #define SCSI_OP_READ_6 0x08 #define SCSI_OP_WRITE_6 0x0a #define SCSI_OP_INQUIRY 0x12 #define SCSI_OP_MODE_SELECT_6 0x15 #define SCSI_OP_RESERVE 0x16 #define SCSI_OP_RELEASE 0x17 #define SCSI_OP_MODE_SENSE_6 0x1a #define SCSI_OP_START_STOP 0x1b #define SCSI_OP_RECEIVE_DIAGNOSTIC 0x1c #define SCSI_OP_SEND_DIAGNOSTIC 0x1d #define SCSI_OP_PREVENT_ALLOW 0x1e #define SCSI_OP_READ_CAPACITY 0x25 #define SCSI_OP_READ_10 0x28 #define SCSI_OP_WRITE_10 0x2a #define SCSI_OP_POSITION_TO_ELEMENT 0x2b #define SCSI_OP_VERIFY 0x2f #define SCSI_OP_SYNCHRONIZE_CACHE 0x35 #define SCSI_OP_WRITE_BUFFER 0x3b #define SCSI_OP_READ_BUFFER 0x3c #define SCSI_OP_CHANGE_DEFINITION 0x40 #define SCSI_OP_READ_SUB_CHANNEL 0x42 #define SCSI_OP_READ_TOC 0x43 #define SCSI_OP_PLAY_MSF 0x47 #define SCSI_OP_PLAY_AUDIO_TRACK_INDEX 0x48 // obsolete, spec missing #define SCSI_OP_PAUSE_RESUME 0x4b #define SCSI_OP_STOP_PLAY 0x4e #define SCSI_OP_MODE_SELECT_10 0x55 #define SCSI_OP_MODE_SENSE_10 0x5A #define SCSI_OP_READ_16 0x88 #define SCSI_OP_WRITE_16 0x8a #define SCSI_OP_SERVICE_ACTION_IN 0x9e #define SCSI_OP_SERVICE_ACTION_OUT 0x9f #define SCSI_OP_MOVE_MEDIUM 0xa5 #define SCSI_OP_READ_12 0xa8 #define SCSI_OP_WRITE_12 0xaa #define SCSI_OP_READ_ELEMENT_STATUS 0xb8 #define SCSI_OP_SCAN 0xba #define SCSI_OP_READ_CD 0xbe // Service-Action-In defines #define SCSI_SAI_READ_CAPACITY_16 0x10 // INQUIRY typedef struct scsi_cmd_inquiry { uint8 opcode; LBITFIELD8_3( evpd : 1, // enhanced vital product data _res1_1 : 4, lun : 3 ); uint8 page_code; uint8 _res3; uint8 allocation_length; uint8 control; } _PACKED scsi_cmd_inquiry; typedef struct scsi_res_inquiry { LBITFIELD8_2( device_type : 5, device_qualifier : 3 ); LBITFIELD8_2( device_type_modifier : 7, // obsolete, normally set to zero removable_medium : 1 ); LBITFIELD8_3( // 0 always means "not conforming" ansi_version : 3, // 1 for SCSI-1, 2 for SCSI-2 etc. ecma_version : 3, iso_version : 2 ); LBITFIELD8_4( response_data_format : 4, // 2 = SCSI/2 compliant _res3_4 : 2, term_iop : 1, // 1 = supports TERMINATE I/O PROCESS async_enc : 1 // processor devices only : // Asynchronous Event Notification Capable ); uint8 additional_length; // total (whished) length = this + 4 uint8 _res5; uint8 _res6; LBITFIELD8_8( soft_reset : 1, // 0 = soft reset leads to hard reset cmd_queue : 1, // 1 = supports tagged command queuing _res7_2 : 1, linked : 1, // 1 = supports linked commands sync : 1, // 1 = supports synchronous transfers write_bus16 : 1, // 1 = supports 16 bit transfers write_bus32 : 1, // 1 = supports 32 bit transfers relative_address : 1 // 1 = supports relative addr. for linking ); char vendor_ident[8]; char product_ident[16]; char product_rev[4]; // XPT doesn't return following data on XPT_GDEV_TYPE uint8 vendor_spec[20]; uint8 _res56[2]; uint16 version_descriptor[8]; // array of supported standards, big endian uint8 _res74[22]; /* additional vendor specific data */ } _PACKED scsi_res_inquiry; enum scsi_peripheral_qualifier { scsi_periph_qual_connected = 0, scsi_periph_qual_not_connected = 2, scsi_periph_qual_not_connectable = 3 // value 1 is reserved, values of 4 and above are vendor-specific }; enum scsi_device_type { scsi_dev_direct_access = 0, scsi_dev_sequential_access = 1, scsi_dev_printer = 2, scsi_dev_processor = 3, scsi_dev_WORM = 4, scsi_dev_CDROM = 5, scsi_dev_scanner = 6, scsi_dev_optical = 7, scsi_dev_medium_changer = 8, scsi_dev_communication = 9, // 0xa - 0xb are graphics arts pre-press devices // 0xc - 0x1e reserved scsi_dev_storage_array = 0xc, scsi_dev_enclosure_services = 0xd, scsi_dev_simplified_direct_access = 0xe, scsi_dev_optical_card = 0xf, scsi_dev_unknown = 0x1f // used for scsi_periph_qual_not_connectable }; // vital product data: unit serial number page #define SCSI_PAGE_USN 0x80 typedef struct scsi_page_usn { LBITFIELD8_2( device_type : 5, device_qualifier : 3 ); uint8 page_code; uint8 _res2; uint8 _page_length; // total size = this + 3 char psn[1]; // size according to page_length } _PACKED scsi_page_usn; // READ CAPACITY typedef struct scsi_cmd_read_capacity { uint8 opcode; LBITFIELD8_3( relative_address : 1, // relative address _res1_1 : 4, lun : 3 ); uint32 lba; uint8 _res6[2]; LBITFIELD8_2( pmi : 1, // partial medium indicator _res8_1 : 7 ); uint8 control; } _PACKED scsi_cmd_read_capacity; typedef struct scsi_res_read_capacity { uint32 lba; // big endian uint32 block_size; // in bytes } _PACKED scsi_res_read_capacity; // READ (6), WRITE (6) typedef struct scsi_cmd_rw_6 { uint8 opcode; LBITFIELD8_2( high_lba : 5, lun : 3 ); uint8 mid_lba; uint8 low_lba; uint8 length; // 0 = 256 blocks uint8 control; } _PACKED scsi_cmd_rw_6; // READ (10), WRITE (10) typedef struct scsi_cmd_rw_10 { uint8 opcode; LBITFIELD8_5( relative_address : 1, // relative address _res1_1 : 2, force_unit_access : 1, // force unit access (1 = safe, cacheless access) disable_page_out : 1, // disable page out (1 = not worth caching) lun : 3 ); uint32 lba; // big endian uint8 _res6; uint16 length; // 0 = no block uint8 control; } _PACKED scsi_cmd_rw_10; // READ (12), WRITE (12) typedef struct scsi_cmd_rw_12 { uint8 opcode; LBITFIELD8_5( relative_address : 1, // relative address _res1_1 : 2, force_unit_access : 1, // force unit access (1 = safe, cacheless access) disable_page_out : 1, // disable page out (1 = not worth caching) lun : 3 ); uint32 lba; // big endian uint32 length; // 0 = no block uint8 _res10; uint8 control; } _PACKED scsi_cmd_rw_12; // REQUEST SENSE typedef struct scsi_cmd_request_sense { uint8 opcode; LBITFIELD8_2( _res1_0 : 5, lun : 3 ); uint8 _res2[2]; uint8 allocation_length; uint8 control; } _PACKED scsi_cmd_request_sense; // sense data structures #define SCSIS_CURR_ERROR 0x70 #define SCSIS_DEFERRED_ERROR 0x71 typedef struct scsi_sense { LBITFIELD8_2( error_code : 7, valid : 1 // 0 = not conforming to standard ); uint8 segment_number; // for COPY/COPY AND VERIFY/COMPARE LBITFIELD8_5( sense_key : 4, res2_4 : 1, ILI : 1, // incorrect length indicator - req. block // length doesn't match physical block length EOM : 1, // serial devices only Filemark : 1 // optional for random access ); uint8 highest_inf; // device-type or command specific uint8 high_inf; // device-type 0, 4, 5, 7: block address uint8 mid_inf; // device-type 1, 2, 3: req length - act. length uint8 low_inf; // (and others for sequential dev. and COPY cmds uint8 add_sense_length; // total length = this + 7 uint8 highest_cmd_inf; uint8 high_cmd_inf; uint8 mid_cmd_inf; uint8 low_cmd_inf; uint8 asc; uint8 ascq; // this can be zero if unsupported uint8 unit_code; // != 0 to specify internal device unit union { struct { LBITFIELD8_2( high_key_spec : 7, SKSV : 1 // 1 = sense key specific (byte 15-17) valid ); uint8 mid_key_spec; uint8 low_key_spec; } raw; // ILLEGAL REQUEST struct { LBITFIELD8_5( bit_pointer : 3, // points to (highest) invalid bit of parameter BPV : 1, // 1 = bit_pointer is valid res15_4 : 2, c_d : 2, // 1 = error command, 0 = error in data SKSV : 1 // s.a. ); uint8 high_field_pointer; // points to (highest) invalid byte of parameter uint8 low_field_pointer; // (!using big endian, this means the first byte!) } ill_request; // access error (RECOVERED, HARDWARE or MEDIUM ERROR) struct { LBITFIELD8_2( res15_0 : 7, SKSV : 1 ); uint8 high_retry_cnt; uint8 low_retry_cnt; } acc_error; // format progress (if sense key = NOT READY) struct { LBITFIELD8_2( res15_0 : 7, SKSV : 1 ); uint16 progress; // 0 = start, 0xffff = almost finished } format_progress; } sense_key_spec; // starting with offset 18 there are additional sense byte } _PACKED scsi_sense; // PREVENT ALLOW typedef struct scsi_cmd_prevent_allow { uint8 opcode; LBITFIELD8_2( _res1_0 : 5, lun : 3 ); uint8 _res2[2]; LBITFIELD8_2( prevent : 1, // 1 - prevent medium removal, 0 - allow removal _res4_1 : 7 ); uint8 control; } _PACKED scsi_cmd_prevent_allow; // START STOP UNIT typedef struct scsi_cmd_ssu { uint8 opcode; LBITFIELD8_3( immediately : 1, // 1 - return immediately, 0 - return on completion _res1_1 : 4, lun : 3 ); uint8 res2[2]; LBITFIELD8_3( start : 1, // 1 - load+start, i.e. allow, 0 - eject+stop, i.e. deny load_eject : 1, // 1 - include loading/ejecting, 0 - only to allow/deny _res4_2 : 6 ); uint8 control; } _PACKED scsi_cmd_ssu; // MODE SELECT (6) typedef struct scsi_cmd_mode_select_6 { uint8 opcode; LBITFIELD8_4( save_pages : 1, // 1 = save pages to non-volatile memory _res1_1 : 3, pf : 1, // 0 = old SCSI-1; 1 = new SCSI-2 format lun : 3 ); uint8 _res2[2]; uint8 param_list_length; // data size uint8 control; } _PACKED scsi_cmd_mode_select_6; // MODE SENSE (6) typedef struct scsi_cmd_mode_sense_6 { uint8 opcode; LBITFIELD8_4( _res1_0 : 3, disable_block_desc : 1, // disable block descriptors _res1_4 : 1, lun : 3 ); LBITFIELD8_2( page_code : 6, page_control : 2 // page control field ); uint8 _res3; uint8 allocation_length; // maximum amount of data uint8 control; } _PACKED scsi_cmd_mode_sense_6; // MODE SELECT (10) typedef struct scsi_cmd_mode_select_10 { uint8 opcode; LBITFIELD8_4( save_pages : 1, // 1 = save pages to non-volatile memory _res1_1 : 3, pf : 1, // 0 = old SCSI-1; 1 = new SCSI-2 format lun : 3 ); uint8 _res2[5]; uint16 param_list_length; // data size, big endian uint8 control; } _PACKED scsi_cmd_mode_select_10; // MODE SENSE (10) typedef struct scsi_cmd_mode_sense_10 { uint8 opcode; LBITFIELD8_4( _res1_0 : 3, disable_block_desc : 1, // disable block descriptors _res1_4 : 1, lun : 3 ); LBITFIELD8_2( page_code : 6, page_control : 2 // page control field ); uint8 _res3[4]; uint16 allocation_length; // maximum amount of data, big endian uint8 control; } _PACKED scsi_cmd_mode_sense_10; // possible contents of page control (PC) #define SCSI_MODE_SENSE_PC_CURRENT 0 #define SCSI_MODE_SENSE_PC_CHANGABLE 1 // changable field are filled with "1" #define SCSI_MODE_SENSE_PC_DEFAULT 2 #define SCSI_MODE_SENSE_PC_SAVED 3 // special mode page indicating to return all mode pages #define SCSI_MODEPAGE_ALL 0x3f // header of mode data; followed by block descriptors and mode pages typedef struct scsi_mode_param_header_6 { uint8 mode_data_length; // total length excluding this byte uint8 medium_type; uint8 dev_spec_parameter; uint8 block_desc_length; // total length of all transmitted block descriptors } _PACKED scsi_mode_param_header_6; typedef struct scsi_mode_param_header_10 { uint16 mode_data_length; // total length excluding these two bytes uint8 medium_type; uint8 dev_spec_parameter; uint8 _res4[2]; uint16 block_desc_length; // total length of all transmitted block descriptors } _PACKED scsi_mode_param_header_10; // content of dev_spec_parameter for direct access devices typedef struct scsi_mode_param_dev_spec_da { LBITFIELD8_4( _res0_0 : 4, dpo_fua : 1, // 1 = supports DPO and FUA, see READ (10) (sense only) _res0_6 : 1, write_protected : 1 // write protected (sense only) ); } _PACKED scsi_mode_param_dev_spec_da; typedef struct scsi_mode_param_block_desc { uint8 density; // density code of area uint8 high_numblocks; // size of this area in blocks uint8 med_numblocks; // 0 = all remaining blocks uint8 low_numblocks; uint8 _res4; uint8 high_blocklen; // block size uint8 med_blocklen; uint8 low_blocklen; } _PACKED scsi_mode_param_block_desc; // header of a mode pages typedef struct scsi_modepage_header { LBITFIELD8_3( page_code : 6, _res0_6 : 1, PS : 1 // 1 = page can be saved (only valid for MODE SENSE) ); uint8 page_length; // size of page excluding this common header } _PACKED scsi_modepage_header; // control mode page #define SCSI_MODEPAGE_CONTROL 0xa typedef struct scsi_modepage_control { scsi_modepage_header header; LBITFIELD8_2( RLEC : 1, // Report Log Exception Condition res2_1 : 7 ); LBITFIELD8_4( DQue : 1, // disable Queuing QErr : 1, // abort queued commands on contingent allegiance condition res3_2 : 2, QAM : 4 // Queue Algorithm Modifier ); LBITFIELD8_5( EAENP : 1, // error AEN permission; true = send AEN on deferred error // false = generate UA condition after deferred error UAAENP : 1, // unit attention AEN permission; true = send AEN, // false = generate UA condition (for everything but init.) RAENP : 1, // ready AEN permission; true = send async event notification // (AEN) instead of generating an Unit Attention (UA) Condition // after initialization res4_3 : 4, EECA : 1 // enable Extended Contingent Allegiance ); uint8 res5; uint8 high_AEN_holdoff; // ready AEN hold off period - delay in ms between uint8 low_AEN_holdoff; // initialization and AEN } scsi_modepage_control; // values for QAM #define SCSI_QAM_RESTRICTED 0 #define SCSI_QAM_UNRESTRICTED 1 // 2 - 7 reserved, 8 - 0xf vendor-specific // CD audio control page #define SCSI_MODEPAGE_AUDIO 0xe typedef struct scsi_modepage_audio { scsi_modepage_header header; LBITFIELD8_4( _res2_0 : 1, stop_on_track_crossing : 1, // Stop On Track Crossing // 0 - stop according transfer length, 1 - stop at end of track immediately : 1, // must be one _res2_3 : 5 ); uint8 _res3[3]; uint8 _obsolete6[2]; struct { LBITFIELD8_2( channel : 4, // select channel to connect to this port _res0_4 : 4 ); uint8 volume; } ports[4]; } _PACKED scsi_modepage_audio; // connection between output port and audio channel #define SCSI_CHANNEL_SEL_MUTED 0 // mute port #define SCSI_CHANNEL_SEL_CHANNEL0 1 // connect to channel 0 #define SCSI_CHANNEL_SEL_CHANNEL1 2 // connect to channel 1 #define SCSI_CHANNEL_SEL_CHANNEL0_1 3 // connect to channel 0 and channel 1 #define SCSI_CHANNEL_SEL_CHANNEL2 4 // connect to channel 2 #define SCSI_CHANNEL_SEL_CHANNEL3 8 // connect to channel 3 // TUR typedef struct scsi_cmd_tur { uint8 opcode; LBITFIELD8_2( _res1_0 : 5, lun : 3 ); uint8 _res3[3]; uint8 control; } _PACKED scsi_cmd_tur; // READ_TOC typedef struct scsi_cmd_read_toc { uint8 opcode; LBITFIELD8_4( _res1_0 : 1, time : 1, // true, to use MSF format, false for LBA format _res1_2 : 3, lun : 3 ); LBITFIELD8_2( format : 4, // see below _res2_4 : 4 ); uint8 _res3[3]; uint8 track; // (starting) track uint16 allocation_length; // maximum amount of data (big endian) uint8 control; } _PACKED scsi_cmd_read_toc; // values of in TOC command #define SCSI_TOC_FORMAT_TOC 0 // all TOCs starting with (0xaa for lead-out) #define SCSI_TOC_FORMAT_SESSION_INFO 1 // Session info #define SCSI_TOC_FORMAT_FULL_TOC 2 // all Q-channel data in TOC #define SCSI_TOC_FORMAT_PMA 3 // Q-channel data in PMA area #define SCSI_TOC_FORMAT_ATIP 4 // get ATIP data #define SCSI_TOC_FORMAT_CD_TEXT 5 // get CD-Text from R/W-channel in lead-in // general structure of response typedef struct scsi_toc_general { uint16 data_length; // big endian, total length - 2 uint8 first; // first track/session/reserved uint8 last; // last one // remainder are parameter list descriptors } _PACKED scsi_toc_general; // definition of CD-ROM LBA typedef uint32 scsi_cd_lba; // big endian // definition of CD-ROM MSF time typedef struct scsi_cd_msf { uint8 _reserved; uint8 minute; uint8 second; uint8 frame; } _PACKED scsi_cd_msf; // definition of Track Number address format typedef struct scsi_cd_track_number { uint8 _res0[3]; uint8 track; } _PACKED scsi_cd_track_number; // one track for SCSI_TOC_FORMAT_TOC typedef struct scsi_toc_track { uint8 _res0; LBITFIELD8_2( control : 4, adr : 4 ); uint8 track_number; // track number (hex) uint8 _res3; union { // start of track (time or LBA, see TIME of command) scsi_cd_lba lba; scsi_cd_msf time; } start; } _PACKED scsi_toc_track; // possible value of ADR-field (described Q-channel content) enum scsi_adr { scsi_adr_none = 0, // no Q-channel mode info scsi_adr_position = 1, // Q-channel encodes current position data scsi_adr_mcn = 2, // Q-channel encodes Media Catalog Number scsi_adr_isrc = 3 // Q-channel encodes ISRC }; // value of Q-channel control field (CONTROL) enum scsi_q_control { scsi_q_control_2audio = 0, // stereo audio scsi_q_control_2audio_preemp = 1, // stereo audio with 50/15µs pre-emphasis scsi_q_control_1audio = 8, // audio (reserved in CD-R/W) scsi_q_control_1audio_preemp = 9, // audio with pre-emphasis (reserved in CD-R/W) scsi_q_control_data_un_intr = 4, // data, recorded un-interrupted scsi_q_control_data_incr = 5, // data, recorded incremental scsi_q_control_ddcd = 4, // DDCD data scsi_q_control_copy_perm = 2 // copy permitted (or-ed with value above) }; // format SCSI_TOC_FORMAT_TOC typedef struct scsi_toc_toc { uint16 data_length; // big endian, total length - 2 uint8 first_track; // first track uint8 last_track; // last track scsi_toc_track tracks[1]; // one entry per track } _PACKED scsi_toc_toc; // READ SUB-CHANNEL typedef struct scsi_cmd_read_subchannel { uint8 opcode; LBITFIELD8_4( _res1_0 : 1, time : 1, // true, to use MSF format, false for LBA format _res1_2 : 3, lun : 3 ); LBITFIELD8_3( _res2_0 : 6, subq : 1, // 1 - return Q sub-channel data _res2_7 : 1 ); uint8 parameter_list; // see below uint8 _res4[2]; uint8 track; // track number (hex) uint16 allocation_length; // maximum amount of data, big endian uint8 control; } _PACKED scsi_cmd_read_subchannel; // values of parameter_list enum scsi_sub_channel_parameter_list { scsi_sub_channel_parameter_list_cd_pos = 1, // CD current position scsi_sub_channel_parameter_list_mcn = 2, // Media Catalog Number scsi_sub_channel_parameter_list_isrc = 3 // Track International Standard Recording Code }; // header of response typedef struct scsi_subchannel_data_header { uint8 _res0; uint8 audio_status; // see below uint16 data_length; // total length - 4, big endian } _PACKED scsi_subchannel_data_header; // possible audio_status enum scsi_audio_status { scsi_audio_status_not_supported = 0, scsi_audio_status_playing = 0x11, scsi_audio_status_paused = 0x12, scsi_audio_status_completed = 0x13, scsi_audio_status_error_stop = 0x14, scsi_audio_status_no_status = 0x15 }; typedef struct scsi_cd_current_position { uint8 format_code; // always 1 LBITFIELD8_2( control : 4, // see scsi_q_control adr : 4 // see scsi_adr ); uint8 track; uint8 index; union { // current position, relative to logical beginning scsi_cd_lba lba; scsi_cd_msf time; } absolute_address; union { // current position, relative to track scsi_cd_lba lba; scsi_cd_msf time; } track_relative_address; } _PACKED scsi_cd_current_position; // PLAY AUDIO MSF typedef struct scsi_cmd_play_msf { uint8 opcode; LBITFIELD8_2( _res1_0 : 5, lun : 3 ); uint8 _res2; uint8 start_minute; // start time uint8 start_second; uint8 start_frame; uint8 end_minute; // end time (excluding) uint8 end_second; uint8 end_frame; uint8 control; } _PACKED scsi_cmd_play_msf; // STOP AUDIO typedef struct scsi_cmd_stop_play { uint8 opcode; LBITFIELD8_2( _res1_0 : 5, lun : 3 ); uint8 _res2[7]; uint8 control; } _PACKED scsi_cmd_stop_play; // PAUSE/RESUME typedef struct scsi_cmd_pause_resume { uint8 opcode; LBITFIELD8_2( _res1_0 : 5, lun : 3 ); uint8 _res2[6]; LBITFIELD8_2( resume : 1, // 1 for resume, 0 for pause _res8_2 : 7 ); uint8 control; } _PACKED scsi_cmd_pause_resume; // SCAN typedef struct scsi_cmd_scan { uint8 opcode; LBITFIELD8_4( relative_address : 1, // must be zero _res1_1 : 3, direct : 1, // direction: 0 forward, 1 backward lun : 3 ); union { // start of track (depends on ) scsi_cd_lba lba; scsi_cd_msf time; scsi_cd_track_number track_number; } start; uint8 _res6[3]; LBITFIELD8_2( res9_0 : 6, type : 2 // actual type of (see below) ); uint8 _res10; uint8 control; } _PACKED scsi_cmd_scan; // possible values for type enum scsi_scan_type { scsi_scan_lba = 0, scsi_scan_msf = 1, scsi_scan_tno = 2 }; // READ_CD typedef struct scsi_cmd_read_cd { uint8 opcode; LBITFIELD8_4( relative_address : 1, // must be zero _res1_1 : 1, sector_type : 3, // required sector type (1=CDDA) lun : 3 ); scsi_cd_lba lba; uint8 high_length; uint8 mid_length; uint8 low_length; LBITFIELD8_6( _res9_0 : 1, error_field : 2, edc_ecc : 1, // include EDC/ECC; includes 8 byte padding for Mode 1 format user_data : 1, // if 1, include user data // (mode select block size is ignored) header_code : 2, sync : 1 // if 1, include sync field from sector ); LBITFIELD8_2( sub_channel_selection : 4, _res10_4 : 4 ); uint8 control; } _PACKED scsi_cmd_read_cd; // possible values for header_code enum scsi_read_cd_header_code { scsi_read_cd_header_none = 0, scsi_read_cd_header_hdr_only = 1, scsi_read_cd_header_sub_header_only = 2, scsi_read_cd_header_all_headers = 3, }; // possible values for error_field enum scsi_read_cd_error_field { scsi_read_cd_error_none = 0, scsi_read_cd_error_c2_error = 1, // include 2352 bits indicating error in byte scsi_read_cd_error_c2_and_block_error = 2, // include or of C2 data plus pad byte }; // possible values for sub_channel_selection enum scsi_read_cd_sub_channel_selection { scsi_read_cd_sub_channel_none = 0, scsi_read_cd_sub_channel_RAW = 1, scsi_read_cd_sub_channel_Q = 2, scsi_read_cd_sub_channel_P_W = 4 // R/W data, depending on CD capabilities // and Mechanism status page }; // SYNCHRONIZE CACHE (10) typedef struct scsi_cmd_sync_cache { uint8 opcode; LBITFIELD8_4( relative_address : 1, // must be zero immediately : 1, // 1 - return immediately, 0 - return on completion _res1_1 : 3, lun : 3 ); scsi_cd_lba lba; uint8 _res2; uint16 block_count; // big endian uint8 control; } _PACKED scsi_cmd_sync_cache; #endif /* _SCSI_CMDS_H */