Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[safe/jmp/linux-2.6] / include / scsi / osd_protocol.h
index ce1a877..6856612 100644 (file)
@@ -17,6 +17,7 @@
 #define __OSD_PROTOCOL_H__
 
 #include <linux/types.h>
+#include <linux/kernel.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi.h>
 
@@ -24,13 +25,18 @@ enum {
        OSDv1_ADDITIONAL_CDB_LENGTH = 192,
        OSDv1_TOTAL_CDB_LEN = OSDv1_ADDITIONAL_CDB_LENGTH + 8,
        OSDv1_CAP_LEN = 80,
+
        /* Latest supported version */
-       OSD_ADDITIONAL_CDB_LENGTH = OSDv1_ADDITIONAL_CDB_LENGTH,
-       OSD_TOTAL_CDB_LEN = OSDv1_TOTAL_CDB_LEN,
-       OSD_CAP_LEN = OSDv1_CAP_LEN,
+       OSDv2_ADDITIONAL_CDB_LENGTH = 228,
+       OSD_ADDITIONAL_CDB_LENGTH =
+               OSDv2_ADDITIONAL_CDB_LENGTH,
+       OSD_TOTAL_CDB_LEN = OSD_ADDITIONAL_CDB_LENGTH + 8,
+       OSD_CAP_LEN = 104,
 
        OSD_SYSTEMID_LEN = 20,
-       OSD_CRYPTO_KEYID_SIZE = 20,
+       OSDv1_CRYPTO_KEYID_SIZE = 20,
+       OSDv2_CRYPTO_KEYID_SIZE = 32,
+       OSD_CRYPTO_KEYID_SIZE = OSDv2_CRYPTO_KEYID_SIZE,
        OSD_CRYPTO_SEED_SIZE = 4,
        OSD_CRYPTO_NONCE_SIZE = 12,
        OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */
@@ -108,6 +114,7 @@ enum {
        OSD_OFFSET_MAX_BITS = 28,
 
        OSDv1_OFFSET_MIN_SHIFT = 8,
+       OSD_OFFSET_MIN_SHIFT = 3,
        OSD_OFFSET_MAX_SHIFT = 16,
 };
 
@@ -129,6 +136,16 @@ static inline osd_cdb_offset osd_encode_offset_v1(u64 offset, unsigned *padding)
                                OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
 }
 
+/* Minimum 8 bytes alignment
+ * Same as v1 but since exponent can be signed than a less than
+ * 256 alignment can be reached with small offsets (<2GB)
+ */
+static inline osd_cdb_offset osd_encode_offset_v2(u64 offset, unsigned *padding)
+{
+       return __osd_encode_offset(offset, padding,
+                                  OSD_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
+}
+
 /* osd2r03: 5.2.1 Overview */
 struct osd_cdb_head {
        struct scsi_varlen_cdb_hdr varlen_cdb;
@@ -144,6 +161,17 @@ struct osd_cdb_head {
 /*36*/                 __be64          length;
 /*44*/                 __be64          start_address;
                } __packed v1;
+
+               struct __osdv2_cdb_addr_len {
+                       /* called allocation_length in some commands */
+/*32*/                 __be64  length;
+/*40*/                 __be64  start_address;
+                       union {
+/*48*/                         __be32 list_identifier;/* Rarely used */
+                               /* OSD2r05 5.2.5 CDB continuation length */
+/*48*/                         __be32 cdb_continuation_length;
+                       };
+               } __packed v2;
        };
 /*52*/ union { /* selected attributes mode Page/List/Single */
                struct osd_attributes_page_mode {
@@ -182,23 +210,46 @@ struct osd_cdb_head {
 /*80*/
 
 /*160 v1*/
-struct osd_security_parameters {
-/*160*/u8      integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
+struct osdv1_security_parameters {
+/*160*/u8      integrity_check_value[OSDv1_CRYPTO_KEYID_SIZE];
 /*180*/u8      request_nonce[OSD_CRYPTO_NONCE_SIZE];
 /*192*/osd_cdb_offset  data_in_integrity_check_offset;
 /*196*/osd_cdb_offset  data_out_integrity_check_offset;
 } __packed;
 /*200 v1*/
 
+/*184 v2*/
+struct osdv2_security_parameters {
+/*184*/u8      integrity_check_value[OSDv2_CRYPTO_KEYID_SIZE];
+/*216*/u8      request_nonce[OSD_CRYPTO_NONCE_SIZE];
+/*228*/osd_cdb_offset  data_in_integrity_check_offset;
+/*232*/osd_cdb_offset  data_out_integrity_check_offset;
+} __packed;
+/*236 v2*/
+
+struct osd_security_parameters {
+       union {
+               struct osdv1_security_parameters v1;
+               struct osdv2_security_parameters v2;
+       };
+};
+
 struct osdv1_cdb {
        struct osd_cdb_head h;
        u8 caps[OSDv1_CAP_LEN];
-       struct osd_security_parameters sec_params;
+       struct osdv1_security_parameters sec_params;
+} __packed;
+
+struct osdv2_cdb {
+       struct osd_cdb_head h;
+       u8 caps[OSD_CAP_LEN];
+       struct osdv2_security_parameters sec_params;
 } __packed;
 
 struct osd_cdb {
        union {
                struct osdv1_cdb v1;
+               struct osdv2_cdb v2;
                u8 buff[OSD_TOTAL_CDB_LEN];
        };
 } __packed;
@@ -253,7 +304,15 @@ enum osd_service_actions {
        OSD_ACT_V2(REMOVE_MEMBER_OBJECTS,       0x21)
        OSD_ACT_V2(GET_MEMBER_ATTRIBUTES,       0x22)
        OSD_ACT_V2(SET_MEMBER_ATTRIBUTES,       0x23)
+
+       OSD_ACT_V2(CREATE_CLONE,                0x28)
+       OSD_ACT_V2(CREATE_SNAPSHOT,             0x29)
+       OSD_ACT_V2(DETACH_CLONE,                0x2A)
+       OSD_ACT_V2(REFRESH_SNAPSHOT_CLONE,      0x2B)
+       OSD_ACT_V2(RESTORE_PARTITION_FROM_SNAPSHOT, 0x2C)
+
        OSD_ACT_V2(READ_MAP,                    0x31)
+       OSD_ACT_V2(READ_MAPS_COMPARE,           0x32)
 
        OSD_ACT_V1_V2(PERFORM_SCSI_COMMAND,     0x8F7E, 0x8F7C)
        OSD_ACT_V1_V2(SCSI_TASK_MANAGEMENT,     0x8F7F, 0x8F7D)
@@ -267,18 +326,31 @@ struct osd_attributes_list_attrid {
 } __packed;
 
 /*
+ * NOTE: v1: is not aligned.
+ */
+struct osdv1_attributes_list_element {
+       __be32 attr_page;
+       __be32 attr_id;
+       __be16 attr_bytes; /* valid bytes at attr_val without padding */
+       u8 attr_val[0];
+} __packed;
+
+/*
  * osd2r03: 7.1.3.3 List entry format for retrieved attributes and
  *                  for setting attributes
+ * NOTE: v2 is 8-bytes aligned
  */
-struct osd_attributes_list_element {
+struct osdv2_attributes_list_element {
        __be32 attr_page;
        __be32 attr_id;
-       __be16 attr_bytes;
+       u8 reserved[6];
+       __be16 attr_bytes; /* valid bytes at attr_val without padding */
        u8 attr_val[0];
 } __packed;
 
 enum {
        OSDv1_ATTRIBUTES_ELEM_ALIGN = 1,
+       OSD_ATTRIBUTES_ELEM_ALIGN = 8,
 };
 
 enum {
@@ -288,10 +360,16 @@ enum {
 
 static inline unsigned osdv1_attr_list_elem_size(unsigned len)
 {
-       return ALIGN(len + sizeof(struct osd_attributes_list_element),
+       return ALIGN(len + sizeof(struct osdv1_attributes_list_element),
                     OSDv1_ATTRIBUTES_ELEM_ALIGN);
 }
 
+static inline unsigned osdv2_attr_list_elem_size(unsigned len)
+{
+       return ALIGN(len + sizeof(struct osdv2_attributes_list_element),
+                    OSD_ATTRIBUTES_ELEM_ALIGN);
+}
+
 /*
  * osd2r03: 7.1.3 OSD attributes lists (Table 184) — List type values
  */
@@ -326,6 +404,21 @@ static inline unsigned osdv1_list_size(struct osdv1_attributes_list_header *h)
        return be16_to_cpu(h->list_bytes);
 }
 
+struct osdv2_attributes_list_header {
+       u8 type;        /* lower 4-bits only */
+       u8 pad[3];
+/*4*/  __be32 list_bytes; /* Initiator shall set to zero. Only set by target */
+       /*
+        * type=9 followed by struct osd_attributes_list_element's
+        * type=E followed by struct osd_attributes_list_multi_header's
+        */
+} __packed;
+
+static inline unsigned osdv2_list_size(struct osdv2_attributes_list_header *h)
+{
+       return be32_to_cpu(h->list_bytes);
+}
+
 /* (osd-r10 6.13)
  * osd2r03: 6.15 LIST (Table 79) LIST command parameter data.
  *     for root_lstchg below
@@ -362,15 +455,35 @@ struct osd_data_out_integrity_info {
        __be64 data_bytes;
        __be64 set_attributes_bytes;
        __be64 get_attributes_bytes;
-       __be64 integrity_check_value;
+       __u8 integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
 } __packed;
 
+/* Same osd_data_out_integrity_info is used for OSD2/OSD1. The only difference
+ * Is the sizeof the structure since in OSD1 the last array is smaller. Use
+ * below for version independent handling of this structure
+ */
+static inline int osd_data_out_integrity_info_sizeof(bool is_ver1)
+{
+       return sizeof(struct osd_data_out_integrity_info) -
+               (is_ver1 * (OSDv2_CRYPTO_KEYID_SIZE - OSDv1_CRYPTO_KEYID_SIZE));
+}
+
 struct osd_data_in_integrity_info {
        __be64 data_bytes;
        __be64 retrieved_attributes_bytes;
-       __be64 integrity_check_value;
+       __u8 integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
 } __packed;
 
+/* Same osd_data_in_integrity_info is used for OSD2/OSD1. The only difference
+ * Is the sizeof the structure since in OSD1 the last array is smaller. Use
+ * below for version independent handling of this structure
+ */
+static inline int osd_data_in_integrity_info_sizeof(bool is_ver1)
+{
+       return sizeof(struct osd_data_in_integrity_info) -
+               (is_ver1 * (OSDv2_CRYPTO_KEYID_SIZE - OSDv1_CRYPTO_KEYID_SIZE));
+}
+
 struct osd_timestamp {
        u8 time[6]; /* number of milliseconds since 1/1/1970 UT (big endian) */
 } __packed;
@@ -420,7 +533,7 @@ enum osd_capability_bit_masks {
 
        OSD_SEC_CAP_NONE1       = BIT(8),
        OSD_SEC_CAP_NONE2       = BIT(9),
-       OSD_SEC_CAP_NONE3       = BIT(10),
+       OSD_SEC_GBL_REM         = BIT(10), /*v2 only*/
        OSD_SEC_CAP_QUERY       = BIT(11), /*v2 only*/
        OSD_SEC_CAP_M_OBJECT    = BIT(12), /*v2 only*/
        OSD_SEC_CAP_POL_SEC     = BIT(13),
@@ -469,11 +582,35 @@ struct osdv1_cap_object_descriptor {
 } __packed;
 /*80 v1*/
 
-struct osd_capability {
+/*56 v2*/
+struct osd_cap_object_descriptor {
+       union {
+               struct {
+/*56*/                 __be32 allowed_attributes_access;
+/*60*/                 __be32 policy_access_tag;
+/*64*/                 __be16 boot_epoch;
+/*66*/                 u8 reserved[6];
+/*72*/                 __be64 allowed_partition_id;
+/*80*/                 __be64 allowed_object_id;
+/*88*/                 __be64 allowed_range_length;
+/*96*/                 __be64 allowed_range_start;
+               } __packed obj_desc;
+
+/*56*/         u8 object_descriptor[48];
+       };
+} __packed;
+/*104 v2*/
+
+struct osdv1_capability {
        struct osd_capability_head h;
        struct osdv1_cap_object_descriptor od;
 } __packed;
 
+struct osd_capability {
+       struct osd_capability_head h;
+       struct osd_cap_object_descriptor od;
+} __packed;
+
 /**
  * osd_sec_set_caps - set cap-bits into the capabilities header
  *