diff options
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 94 | ||||
-rw-r--r-- | include/scsi/osd_initiator.h | 39 | ||||
-rw-r--r-- | include/scsi/osd_protocol.h | 90 |
3 files changed, 205 insertions, 18 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 3fd021a57e59..86a76cccfebd 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -59,36 +59,50 @@ static inline void build_test(void) { /* structures were not packed */ BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN); + BUILD_BUG_ON(sizeof(struct osdv2_cdb) != OSD_TOTAL_CDB_LEN); BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN); } static unsigned _osd_req_cdb_len(struct osd_request *or) { - return OSDv1_TOTAL_CDB_LEN; + return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN; } static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len) { - return osdv1_attr_list_elem_size(len); + return osd_req_is_ver1(or) ? + osdv1_attr_list_elem_size(len) : + osdv2_attr_list_elem_size(len); } static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head) { - return osdv1_list_size(list_head); + return osd_req_is_ver1(or) ? + osdv1_list_size(list_head) : + osdv2_list_size(list_head); } static unsigned _osd_req_sizeof_alist_header(struct osd_request *or) { - return sizeof(struct osdv1_attributes_list_header); + return osd_req_is_ver1(or) ? + sizeof(struct osdv1_attributes_list_header) : + sizeof(struct osdv2_attributes_list_header); } static void _osd_req_set_alist_type(struct osd_request *or, void *list, int list_type) { - struct osdv1_attributes_list_header *attr_list = list; + if (osd_req_is_ver1(or)) { + struct osdv1_attributes_list_header *attr_list = list; + + memset(attr_list, 0, sizeof(*attr_list)); + attr_list->type = list_type; + } else { + struct osdv2_attributes_list_header *attr_list = list; - memset(attr_list, 0, sizeof(*attr_list)); - attr_list->type = list_type; + memset(attr_list, 0, sizeof(*attr_list)); + attr_list->type = list_type; + } } static bool _osd_req_is_alist_type(struct osd_request *or, @@ -97,10 +111,14 @@ static bool _osd_req_is_alist_type(struct osd_request *or, if (!list) return false; - if (1) { + if (osd_req_is_ver1(or)) { struct osdv1_attributes_list_header *attr_list = list; return attr_list->type == list_type; + } else { + struct osdv2_attributes_list_header *attr_list = list; + + return attr_list->type == list_type; } } @@ -110,15 +128,22 @@ static void _osd_req_encode_olist(struct osd_request *or, { struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - cdbh->v1.list_identifier = list->list_identifier; - cdbh->v1.start_address = list->continuation_id; + if (osd_req_is_ver1(or)) { + cdbh->v1.list_identifier = list->list_identifier; + cdbh->v1.start_address = list->continuation_id; + } else { + cdbh->v2.list_identifier = list->list_identifier; + cdbh->v2.start_address = list->continuation_id; + } } static osd_cdb_offset osd_req_encode_offset(struct osd_request *or, u64 offset, unsigned *padding) { return __osd_encode_offset(offset, padding, - OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT); + osd_req_is_ver1(or) ? + OSDv1_OFFSET_MIN_SHIFT : OSD_OFFSET_MIN_SHIFT, + OSD_OFFSET_MAX_SHIFT); } static struct osd_security_parameters * @@ -126,7 +151,10 @@ _osd_req_sec_params(struct osd_request *or) { struct osd_cdb *ocdb = &or->cdb; - return &ocdb->v1.sec_params; + if (osd_req_is_ver1(or)) + return &ocdb->v1.sec_params; + else + return &ocdb->v2.sec_params; } void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device) @@ -134,6 +162,9 @@ void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device) memset(osdd, 0, sizeof(*osdd)); osdd->scsi_device = scsi_device; osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT; +#ifdef OSD_VER1_SUPPORT + osdd->version = OSD_VER2; +#endif /* TODO: Allocate pools for osd_request attributes ... */ } EXPORT_SYMBOL(osd_dev_init); @@ -334,10 +365,30 @@ static void _osdv1_req_encode_common(struct osd_request *or, ocdb->h.v1.start_address = cpu_to_be64(offset); } +static void _osdv2_req_encode_common(struct osd_request *or, + __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) +{ + struct osdv2_cdb *ocdb = &or->cdb.v2; + + OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act)); + + ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD; + ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH; + ocdb->h.varlen_cdb.service_action = act; + + ocdb->h.partition = cpu_to_be64(obj->partition); + ocdb->h.object = cpu_to_be64(obj->id); + ocdb->h.v2.length = cpu_to_be64(len); + ocdb->h.v2.start_address = cpu_to_be64(offset); +} + static void _osd_req_encode_common(struct osd_request *or, __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) { - _osdv1_req_encode_common(or, act, obj, offset, len); + if (osd_req_is_ver1(or)) + _osdv1_req_encode_common(or, act, obj, offset, len); + else + _osdv2_req_encode_common(or, act, obj, offset, len); } /* @@ -546,6 +597,12 @@ void osd_req_flush_object(struct osd_request *or, const struct osd_obj_id *obj, enum osd_options_flush_scope_values op, /*V2*/ u64 offset, /*V2*/ u64 len) { + if (unlikely(osd_req_is_ver1(or) && (offset || len))) { + OSD_DEBUG("OSD Ver1 flush on specific range ignored\n"); + offset = 0; + len = 0; + } + _osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len); _osd_req_encode_flush(or, op); } @@ -1169,6 +1226,10 @@ enum { OSD_SEC_CAP_V1_ALL_CAPS = OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT }; +enum { OSD_SEC_CAP_V2_ALL_CAPS = + OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT +}; + void osd_sec_init_nosec_doall_caps(void *caps, const struct osd_obj_id *obj, bool is_collection, const bool is_v1) { @@ -1210,9 +1271,14 @@ void osd_sec_init_nosec_doall_caps(void *caps, } EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps); +/* FIXME: Extract version from caps pointer. + * Also Pete's target only supports caps from OSDv1 for now + */ void osd_set_caps(struct osd_cdb *cdb, const void *caps) { - memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN); + bool is_ver1 = true; + /* NOTE: They start at same address */ + memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN); } bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused) diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h index e84dc7aa5e34..8482777416d8 100644 --- a/include/scsi/osd_initiator.h +++ b/include/scsi/osd_initiator.h @@ -21,6 +21,23 @@ /* Note: "NI" in comments below means "Not Implemented yet" */ +/* Configure of code: + * #undef if you *don't* want OSD v1 support in runtime. + * If #defined the initiator will dynamically configure to encode OSD v1 + * CDB's if the target is detected to be OSD v1 only. + * OSD v2 only commands, options, and attributes will be ignored if target + * is v1 only. + * If #defined will result in bigger/slower code (OK Slower maybe not) + * Q: Should this be CONFIG_SCSI_OSD_VER1_SUPPORT and set from Kconfig? + */ +#define OSD_VER1_SUPPORT y + +enum osd_std_version { + OSD_VER_NONE = 0, + OSD_VER1 = 1, + OSD_VER2 = 2, +}; + /* * Object-based Storage Device. * This object represents an OSD device. @@ -31,6 +48,10 @@ struct osd_dev { struct scsi_device *scsi_device; unsigned def_timeout; + +#ifdef OSD_VER1_SUPPORT + enum osd_std_version version; +#endif }; /* Retrieve/return osd_dev(s) for use by Kernel clients */ @@ -46,6 +67,14 @@ void osduld_unregister_test(unsigned ioctl); void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device); void osd_dev_fini(struct osd_dev *od); +/* we might want to use function vector in the future */ +static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v) +{ +#ifdef OSD_VER1_SUPPORT + od->version = v; +#endif +} + struct osd_request; typedef void (osd_req_done_fn)(struct osd_request *or, void *private); @@ -82,6 +111,16 @@ struct osd_request { int async_error; }; +/* OSD Version control */ +static inline bool osd_req_is_ver1(struct osd_request *or) +{ +#ifdef OSD_VER1_SUPPORT + return or->osd_dev->version == OSD_VER1; +#else + return false; +#endif +} + /* * How to use the osd library: * diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h index ce1a8771ea71..cd3cbf764650 100644 --- a/include/scsi/osd_protocol.h +++ b/include/scsi/osd_protocol.h @@ -25,12 +25,16 @@ enum { 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, +/* OSD_ADDITIONAL_CDB_LENGTH = 216,*/ + OSD_ADDITIONAL_CDB_LENGTH = + OSDv1_ADDITIONAL_CDB_LENGTH, /* FIXME: Pete rev-001 sup */ + OSD_TOTAL_CDB_LEN = OSD_ADDITIONAL_CDB_LENGTH + 8, +/* OSD_CAP_LEN = 104,*/ + OSD_CAP_LEN = OSDv1_CAP_LEN,/* FIXME: Pete rev-001 sup */ OSD_SYSTEMID_LEN = 20, OSD_CRYPTO_KEYID_SIZE = 20, + /*FIXME: OSDv2_CRYPTO_KEYID_SIZE = 32,*/ OSD_CRYPTO_SEED_SIZE = 4, OSD_CRYPTO_NONCE_SIZE = 12, OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */ @@ -108,6 +112,7 @@ enum { OSD_OFFSET_MAX_BITS = 28, OSDv1_OFFSET_MIN_SHIFT = 8, + OSD_OFFSET_MIN_SHIFT = 3, OSD_OFFSET_MAX_SHIFT = 16, }; @@ -129,6 +134,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 +159,13 @@ 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; +/*48*/ __be32 list_identifier;/* Rarely used */ + } __packed v2; }; /*52*/ union { /* selected attributes mode Page/List/Single */ struct osd_attributes_page_mode { @@ -182,6 +204,7 @@ struct osd_cdb_head { /*80*/ /*160 v1*/ +/*184 v2*/ struct osd_security_parameters { /*160*/u8 integrity_check_value[OSD_CRYPTO_KEYID_SIZE]; /*180*/u8 request_nonce[OSD_CRYPTO_NONCE_SIZE]; @@ -189,6 +212,9 @@ struct osd_security_parameters { /*196*/osd_cdb_offset data_out_integrity_check_offset; } __packed; /*200 v1*/ +/*224 v2*/ + +/* FIXME: osdv2_security_parameters */ struct osdv1_cdb { struct osd_cdb_head h; @@ -196,9 +222,17 @@ struct osdv1_cdb { struct osd_security_parameters sec_params; } __packed; +struct osdv2_cdb { + struct osd_cdb_head h; + u8 caps[OSD_CAP_LEN]; + struct osd_security_parameters sec_params; + /* FIXME: osdv2_security_parameters */ +} __packed; + struct osd_cdb { union { struct osdv1_cdb v1; + struct osdv2_cdb v2; u8 buff[OSD_TOTAL_CDB_LEN]; }; } __packed; @@ -269,6 +303,7 @@ struct osd_attributes_list_attrid { /* * osd2r03: 7.1.3.3 List entry format for retrieved attributes and * for setting attributes + * NOTE: v2 is 8-bytes aligned, v1 is not aligned. */ struct osd_attributes_list_element { __be32 attr_page; @@ -279,6 +314,7 @@ struct osd_attributes_list_element { enum { OSDv1_ATTRIBUTES_ELEM_ALIGN = 1, + OSD_ATTRIBUTES_ELEM_ALIGN = 8, }; enum { @@ -292,6 +328,12 @@ static inline unsigned osdv1_attr_list_elem_size(unsigned len) OSDv1_ATTRIBUTES_ELEM_ALIGN); } +static inline unsigned osdv2_attr_list_elem_size(unsigned len) +{ + return ALIGN(len + sizeof(struct osd_attributes_list_element), + OSD_ATTRIBUTES_ELEM_ALIGN); +} + /* * osd2r03: 7.1.3 OSD attributes lists (Table 184) — List type values */ @@ -326,6 +368,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 @@ -469,11 +526,36 @@ 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;*/ + struct osdv1_cap_object_descriptor od; /* FIXME: Pete rev-001 sup */ +} __packed; + /** * osd_sec_set_caps - set cap-bits into the capabilities header * |