/**/ /***************************************************************************/ /** **/ /** © Copyright 2010, Hewlett-Packard Development Company, L.P. **/ /** **/ /** Confidential computer software. Valid license from HP and/or **/ /** its subsidiaries required for possession, use, or copying. **/ /** **/ /** Consistent with FAR 12.211 and 12.212, Commercial Computer Software, **/ /** Computer Software Documentation, and Technical Data for Commercial **/ /** Items are licensed to the U.S. Government under vendor's standard **/ /** commercial license. **/ /** **/ /** Neither HP nor any of its subsidiaries shall be liable for technical **/ /** or editorial errors or omissions contained herein. The information **/ /** in this document is provided "as is" without warranty of any kind and **/ /** is subject to change without notice. The warranties for HP products **/ /** are set forth in the express limited warranty statements accompanying **/ /** such products. Nothing herein should be construed as constituting an **/ /** additional warranty. **/ /** **/ /***************************************************************************/ /********************************************************************************************************************************/ /* Created: 30-Mar-2010 17:26:21 by OpenVMS SDL EV3-3 */ /* Source: 18-JUN-2007 14:04:20 $1$DGA7274:[LIB_H.SRC]SASDEVDEF.SDL;1 */ /********************************************************************************************************************************/ /*** MODULE $SASDEVDEF IDENT X-8 ***/ #ifndef __SASDEVDEF_LOADED #define __SASDEVDEF_LOADED 1 #pragma __nostandard /* This file uses non-ANSI-Standard features */ #pragma __member_alignment __save #pragma __nomember_alignment #ifdef __INITIAL_POINTER_SIZE /* Defined whenever ptr size pragmas supported */ #pragma __required_pointer_size __save /* Save the previously-defined required ptr size */ #pragma __required_pointer_size __short /* And set ptr size default to 32-bit pointers */ #endif #ifdef __cplusplus extern "C" { #define __unknown_params ... #define __optional_params ... #else #define __unknown_params #define __optional_params ... #endif #ifndef __struct #if !defined(__VAXC) #define __struct struct #else #define __struct variant_struct #endif #endif #ifndef __union #if !defined(__VAXC) #define __union union #else #define __union variant_union #endif #endif /* Definitions used by both PKMDRIVER and IOGEN. */ #include #define IO$_SASREADCAPACITY IO$_AVAILABLE /* 011 */ #define IO$_SASREADPBLK IO$_REREADP /* 017 */ #define IO$_SASGETDEVDATA IO$_READRCT /* 009 */ #define IO$_SASID2TARG IO$_DISPLAY /* 013 */ #define IO$_TARG2SASID (IO$_DISPLAY + IO$M_SWAP) /* 113 */ #define IO$_SASGETUDID IO$_READHEAD /* 00E */ #define IO$_SASSETUDID IO$_WRITEHEAD /* 00D */ #define IO$_PORTRESET IO$_DSE /* 015 */ #define SCSI_SAS_HARD_RESET 0x101 #define SAS_PURGE_PERSISTENT 0x102 #define SAS_CLEAR_PERSISTENT 0x103 #define SAS_DISCOVERY_SCAN 0x104 #define SCSI_SAS_BUS_RESET 0x105 #define SCSI_GET_NEGOTIATED 0x106 #define GET_SAS_UDID 0x1234 #define GET_SATA_END_DEVICE_BIT 0x2345 #define SAS_TARG$M_SAS_DEVICE_TYPE 0xF #define SAS_TARG$M_VALID 0x10 #define SAS_TARG$M_CONNECTED 0x20 #define SAS_TARG$M_UDID_CAPABLE 0x40 #define SAS_TARG$M_NVRAM_UDID_CAPABLE 0x80 #define SAS_TARG$M_DIRECT_ATTACHED 0x100 #define SAS_TARG$M_TARGET_RESET 0x200 #define SAS_TARG$M_DA_WITH_ENCL_MGMT 0x400 #define SAS_TARG$C_SATA_WWNAME_SIZE 60 /* Specified max bytes, minus leading invariant bytes */ #define SAS_TARG$C_NO_DEVICE 0 /* No device */ #define SAS_TARG$C_SAS_END_DEVICE 1 /* SAS end device */ #define SAS_TARG$C_SATA_END_DEVICE 2 /* SATA end device */ #define SAS_TARG$C_ATAPI_END_DEVICE 3 /* ATAPI end device */ #define SAS_TARG$C_SEP_END_DEVICE 4 /* SEP end device */ #define SAS_TARG$C_SAS_SATA_DEVICE 13 /* SAS/SATA device */ #define SAS_TARG$C_RAID_PHYS_DISK 14 /* Integrated RAID physical disk */ #define SAS_TARG$C_RAID_VOLUME 15 /* Integrated RAID volume */ #if !defined(__NOBASEALIGN_SUPPORT) && !defined(__cplusplus) /* If using pre DECC V4.0 or C++ */ #pragma __nomember_alignment __quadword #else #pragma __nomember_alignment #endif typedef struct _sas_target_device_block { #pragma __nomember_alignment __union { unsigned __int64 sas_targ$q_sas_address; /* 00h 00 */ __struct { unsigned int sas_targ$l_sas_address_lo; /* 00h 00 */ unsigned int sas_targ$l_sas_address_hi; /* 04h 04 */ } sas_targ$r_sas_address_longwords; } sas_targ$r_sas_address_union; __union { unsigned __int64 sas_targ$q_udid; /* 08h 08 */ __struct { unsigned int sas_targ$l_udid_lo; /* 08h 08 */ unsigned int sas_targ$l_udid_hi; /* 0Ch 12 */ } sas_targ$r_udid_longwords; } sas_targ$r_udid_union; unsigned __int64 sas_targ$q_highest_lbn; /* 10h 16 */ unsigned char sas_targ$b_wwname [60]; /* 18h 24 */ unsigned char sas_targ$b_wwname_len; /* 54h 84 */ unsigned char sas_targ$b_port; /* 55h 85 */ unsigned char sas_targ$b_target_id; /* 56h 86 */ unsigned char sas_targ$b_peripheral_dev_type; /* 57h 87 */ #if !defined(__NOBASEALIGN_SUPPORT) && !defined(__cplusplus) /* If using pre DECC V4.0 or C++ */ #pragma __nomember_alignment __longword #else #pragma __nomember_alignment #endif __union { /* 58h 88 */ #pragma __nomember_alignment __struct { unsigned sas_targ$v_sas_device_type : 4; /* 0 */ unsigned sas_targ$v_valid : 1; /* 4 */ unsigned sas_targ$v_connected : 1; /* 5 */ unsigned sas_targ$v_udid_capable : 1; /* 6 */ unsigned sas_targ$v_nvram_udid_capable : 1; /* 7 */ unsigned sas_targ$v_direct_attached : 1; /* 8 */ unsigned sas_targ$v_target_reset : 1; /* 9 */ unsigned sas_targ$v_da_with_encl_mgmt : 1; /* 10 */ unsigned sas_targ$v_fill_0_ : 5; } sas_targ$r_info_bits; __struct { unsigned short int sas_targ$w_info_bitfield; /* 58h 88 */ unsigned short int sas_targ$w_reserved1; /* 5Ah 90 */ } sas_targ$r_bitfield_container; } sas_targ$r_bitfield_union; unsigned short int sas_targ$w_parent; /* 5Ch 92 */ unsigned short int sas_targ$w_enclosure; /* 5Eh 94 */ unsigned short int sas_targ$w_slot; /* 60h 96 */ unsigned short int sas_targ$w_start_slot; /* 62h 98 */ unsigned int sas_targ$l_reserved2; /* 64h 100 */ } SAS_TARGET_DEVICE_BLOCK; #if !defined(__VAXC) #define sas_targ$q_sas_address sas_targ$r_sas_address_union.sas_targ$q_sas_address #define sas_targ$r_sas_address_longwords sas_targ$r_sas_address_union.sas_targ$r_sas_address_longwords #define sas_targ$l_sas_address_lo sas_targ$r_sas_address_longwords.sas_targ$l_sas_address_lo #define sas_targ$l_sas_address_hi sas_targ$r_sas_address_longwords.sas_targ$l_sas_address_hi #define sas_targ$q_udid sas_targ$r_udid_union.sas_targ$q_udid #define sas_targ$r_udid_longwords sas_targ$r_udid_union.sas_targ$r_udid_longwords #define sas_targ$l_udid_lo sas_targ$r_udid_longwords.sas_targ$l_udid_lo #define sas_targ$l_udid_hi sas_targ$r_udid_longwords.sas_targ$l_udid_hi #define sas_targ$v_sas_device_type sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_sas_device_type #define sas_targ$v_valid sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_valid #define sas_targ$v_connected sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_connected #define sas_targ$v_udid_capable sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_udid_capable #define sas_targ$v_nvram_udid_capable sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_nvram_udid_capable #define sas_targ$v_direct_attached sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_direct_attached #define sas_targ$v_target_reset sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_target_reset #define sas_targ$v_da_with_encl_mgmt sas_targ$r_bitfield_union.sas_targ$r_info_bits.sas_targ$v_da_with_encl_mgmt #define sas_targ$r_bitfield_container sas_targ$r_bitfield_union.sas_targ$r_bitfield_container #define sas_targ$w_info_bitfield sas_targ$r_bitfield_container.sas_targ$w_info_bitfield #define sas_targ$w_reserved1 sas_targ$r_bitfield_container.sas_targ$w_reserved1 #endif /* #if !defined(__VAXC) */ /* Definitions used by both PKMDRIVER and EFI. */ /* * Definition of SAS UDID record version numbers and format. */ static const char sas_udid_version_01_00[] = { 0x00, 0x01 }; /* LSB MSB * minor major */ /* * Storage required for zero-terminated banner string. */ static const char efi_sas_udid_banner[] = "EFI SAS/SATA UDID record"; static const char vms_sas_udid_banner[] = "OpenVMS SAS/SATA UDID record"; /* 012345678901234567890123456789012 * | * 29 bytes */ /* * Disk-resident SAS UDID data record. */ #define SAS_UDID_VERSION_SIZE 2 #define SAS_UDID_BANNER_SIZE 38 #define SAS_UDID_SYSTIME_SIZE 8 #define SAS_UDID_VALUE_SIZE 8 typedef struct _sas_udid_record { char version [SAS_UDID_VERSION_SIZE]; char banner [SAS_UDID_BANNER_SIZE]; char systime [SAS_UDID_SYSTIME_SIZE]; char udid [SAS_UDID_VALUE_SIZE]; unsigned short int checksum; } SAS_UDID_RECORD; /* * We only store UDIDs on disks with a 512-byte block size. */ #define SAS_UDID_BLOCK_SIZE 512 /* * Block boundary and size of hidden on-disk SAS UDID storage region. * * We are hiding the highest logical blocks on the volume such that our UDID * records plus the volume's secondary GUID Partition Table. The secondary * GPT must reside in the volume's highest logical blocks. The size of our * hidden region must be hard-coded and must never change, or the bitmaps of * existing volumes would become incompatible with the apparent volume size. * * The GPT consists of a header that occupies a single 512-byte block, and an * array of GUID Partition Entries. Each GUID Partition Entry is either not * in use, or describes one of the volume's partitions. Our hidden region must * be large enough that increasing the number of partitions will never cause * the table to overflow its space in the region. VMS currently provides for * up to 128 GPTEs of the current GPTE size in the array. We should provide * for a lot more than that. */ #define SAS_MAX_PARTITIONS 1024 /* Max elements in GPTE array */ #define SAS_GPTE_BYTES 128 /* Current size of a GPTE */ #define SAS_MAX_GPTE_BYTES (SAS_MAX_PARTITIONS * SAS_GPTE_BYTES) #define SAS_MAX_GPTE_BLOCKS ((SAS_MAX_GPTE_BYTES / SAS_UDID_BLOCK_SIZE) \ + ((SAS_MAX_GPTE_BYTES % SAS_UDID_BLOCK_SIZE) != 0)) #define SAS_GPT_HEADER_BLOCKS 1 #define SAS_MAX_GPT_BLOCKS (SAS_GPT_HEADER_BLOCKS + SAS_MAX_GPTE_BLOCKS) /* * Our hidden region consists of consecutive blocks containing UDID records, * consecutive unused blocks, and the maximum number of consecutive GPT blocks, * rounded up in size so it will start on a 2^n block boundary. */ #define SAS_UDID_BLOCK_BOUNDARY 8 /* Start on a 2^n block boundary */ #define SAS_UDID_UDID_BLOCKS 2 /* Blocks of UDID record data */ #define SAS_UDID_UNUSED_BLOCKS 2 /* Unused blocks between UDID and GPT */ #define SAS_UDID_GPT_BLOCKS SAS_MAX_GPT_BLOCKS #define SAS_UDID_TOTAL_BLOCKS (SAS_UDID_UDID_BLOCKS \ + SAS_UDID_UNUSED_BLOCKS \ + SAS_UDID_GPT_BLOCKS) /* * Retrieve data from a SAS UDID data record. */ __inline static int sas_get_udid_record_data( void *p_udid_record, void *p_version, void *p_banner, void *p_systime, void *p_udid, unsigned short int *p_checksum ) { SAS_UDID_RECORD record; char *p_data; unsigned long int checksum; unsigned long int limit; unsigned long int i; unsigned short int checksum_word; union { unsigned short int word; unsigned char byte [2]; } checksum_data; memcpy( (char *)&record, p_udid_record, sizeof(SAS_UDID_RECORD) ); memcpy( (char *)p_version, record.version, SAS_UDID_VERSION_SIZE ); strncpy( (char *)p_banner, record.banner, SAS_UDID_BANNER_SIZE ); ((char *)p_banner)[SAS_UDID_BANNER_SIZE-1] = '\0'; memcpy( (char *)p_systime, record.systime, SAS_UDID_SYSTIME_SIZE ); memcpy( (char *)p_udid, record.udid, SAS_UDID_VALUE_SIZE ); *p_checksum = record.checksum; limit = offsetof( SAS_UDID_RECORD, checksum ); p_data = (char *)&record; checksum = 0; for( i = 0; i < limit; i++ ) { if( !(i & 1) ) { checksum_data.word = 0; if( (i + 1) < limit ) checksum_data.byte[1] = p_data[i + 1]; checksum_data.byte[0] = p_data[i]; checksum += checksum_data.word; } } checksum_word = (unsigned short int) checksum; if( checksum_word == record.checksum ) return 1; else return 0; } /* * Populate a SAS UDID data record. */ __inline static void sas_build_udid_record( void *p_udid_record, void *p_version, void *p_banner, void *p_systime, void *p_udid, unsigned short int *p_checksum ) { SAS_UDID_RECORD record; char *p_data; unsigned long int checksum; unsigned long int limit; unsigned long int i; union { unsigned short int word; unsigned char byte [2]; } checksum_data; memcpy( record.version, (char *)p_version, SAS_UDID_VERSION_SIZE ); strncpy( record.banner, (char *)p_banner, SAS_UDID_BANNER_SIZE ); record.banner[SAS_UDID_BANNER_SIZE-1] = '\0'; memcpy( record.systime, (char *)p_systime, SAS_UDID_SYSTIME_SIZE ); memcpy( record.udid, (char *)p_udid, SAS_UDID_VALUE_SIZE ); limit = offsetof( SAS_UDID_RECORD, checksum ); p_data = (char *)&record; checksum = 0; for( i = 0; i < limit; i++ ) { if( !(i & 1) ) { checksum_data.word = 0; if( (i + 1) < limit ) checksum_data.byte[1] = p_data[i + 1]; checksum_data.byte[0] = p_data[i]; checksum += checksum_data.word; } } record.checksum = (unsigned short int) checksum; *p_checksum = record.checksum; memcpy( p_udid_record, (char *)&record, sizeof(SAS_UDID_RECORD) ); } /* * Starting with the last logical block value in the RETURNED LOGICAL BLOCK * ADDRESS field of the READ CAPACITY data, return the starting logical * block of the hidden on-disk SAS UDID and GPT storage region. */ __inline static unsigned long long sas_get_starting_udid_block( unsigned long long true_last_block ) { unsigned long long starting_udid_block; starting_udid_block = true_last_block + 1; starting_udid_block -= SAS_UDID_TOTAL_BLOCKS; starting_udid_block /= SAS_UDID_BLOCK_BOUNDARY; starting_udid_block *= SAS_UDID_BLOCK_BOUNDARY; return starting_udid_block; } /* * Starting with the last logical block value in the RETURNED LOGICAL BLOCK * ADDRESS field of the READ CAPACITY data, return the last logical block * before the hidden on-disk SAS UDID and GPT storage region. */ __inline static unsigned long long sas_get_last_non_udid_block( unsigned long long true_last_block ) { unsigned long long last_non_udid_block; last_non_udid_block = sas_get_starting_udid_block( true_last_block ) - 1; return last_non_udid_block; } #pragma __member_alignment __restore #ifdef __INITIAL_POINTER_SIZE /* Defined whenever ptr size pragmas supported */ #pragma __required_pointer_size __restore /* Restore the previously-defined required ptr size */ #endif #ifdef __cplusplus } #endif #pragma __standard #endif /* __SASDEVDEF_LOADED */