Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] libosd: OSD version 2 Support

Add support for OSD2 at run time. It is now possible to run with
both OSDv1 and OSDv2 targets at the same time. The actual detection
should be preformed by the security manager, as the version is encoded
in the capability structure.

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

authored by

Boaz Harrosh and committed by
James Bottomley
c6572c98 ae30c994

+205 -18
+80 -14
drivers/scsi/osd/osd_initiator.c
··· 59 59 { 60 60 /* structures were not packed */ 61 61 BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN); 62 + BUILD_BUG_ON(sizeof(struct osdv2_cdb) != OSD_TOTAL_CDB_LEN); 62 63 BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN); 63 64 } 64 65 65 66 static unsigned _osd_req_cdb_len(struct osd_request *or) 66 67 { 67 - return OSDv1_TOTAL_CDB_LEN; 68 + return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN; 68 69 } 69 70 70 71 static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len) 71 72 { 72 - return osdv1_attr_list_elem_size(len); 73 + return osd_req_is_ver1(or) ? 74 + osdv1_attr_list_elem_size(len) : 75 + osdv2_attr_list_elem_size(len); 73 76 } 74 77 75 78 static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head) 76 79 { 77 - return osdv1_list_size(list_head); 80 + return osd_req_is_ver1(or) ? 81 + osdv1_list_size(list_head) : 82 + osdv2_list_size(list_head); 78 83 } 79 84 80 85 static unsigned _osd_req_sizeof_alist_header(struct osd_request *or) 81 86 { 82 - return sizeof(struct osdv1_attributes_list_header); 87 + return osd_req_is_ver1(or) ? 88 + sizeof(struct osdv1_attributes_list_header) : 89 + sizeof(struct osdv2_attributes_list_header); 83 90 } 84 91 85 92 static void _osd_req_set_alist_type(struct osd_request *or, 86 93 void *list, int list_type) 87 94 { 88 - struct osdv1_attributes_list_header *attr_list = list; 95 + if (osd_req_is_ver1(or)) { 96 + struct osdv1_attributes_list_header *attr_list = list; 89 97 90 - memset(attr_list, 0, sizeof(*attr_list)); 91 - attr_list->type = list_type; 98 + memset(attr_list, 0, sizeof(*attr_list)); 99 + attr_list->type = list_type; 100 + } else { 101 + struct osdv2_attributes_list_header *attr_list = list; 102 + 103 + memset(attr_list, 0, sizeof(*attr_list)); 104 + attr_list->type = list_type; 105 + } 92 106 } 93 107 94 108 static bool _osd_req_is_alist_type(struct osd_request *or, ··· 111 97 if (!list) 112 98 return false; 113 99 114 - if (1) { 100 + if (osd_req_is_ver1(or)) { 115 101 struct osdv1_attributes_list_header *attr_list = list; 102 + 103 + return attr_list->type == list_type; 104 + } else { 105 + struct osdv2_attributes_list_header *attr_list = list; 116 106 117 107 return attr_list->type == list_type; 118 108 } ··· 128 110 { 129 111 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); 130 112 131 - cdbh->v1.list_identifier = list->list_identifier; 132 - cdbh->v1.start_address = list->continuation_id; 113 + if (osd_req_is_ver1(or)) { 114 + cdbh->v1.list_identifier = list->list_identifier; 115 + cdbh->v1.start_address = list->continuation_id; 116 + } else { 117 + cdbh->v2.list_identifier = list->list_identifier; 118 + cdbh->v2.start_address = list->continuation_id; 119 + } 133 120 } 134 121 135 122 static osd_cdb_offset osd_req_encode_offset(struct osd_request *or, 136 123 u64 offset, unsigned *padding) 137 124 { 138 125 return __osd_encode_offset(offset, padding, 139 - OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT); 126 + osd_req_is_ver1(or) ? 127 + OSDv1_OFFSET_MIN_SHIFT : OSD_OFFSET_MIN_SHIFT, 128 + OSD_OFFSET_MAX_SHIFT); 140 129 } 141 130 142 131 static struct osd_security_parameters * ··· 151 126 { 152 127 struct osd_cdb *ocdb = &or->cdb; 153 128 154 - return &ocdb->v1.sec_params; 129 + if (osd_req_is_ver1(or)) 130 + return &ocdb->v1.sec_params; 131 + else 132 + return &ocdb->v2.sec_params; 155 133 } 156 134 157 135 void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device) ··· 162 134 memset(osdd, 0, sizeof(*osdd)); 163 135 osdd->scsi_device = scsi_device; 164 136 osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT; 137 + #ifdef OSD_VER1_SUPPORT 138 + osdd->version = OSD_VER2; 139 + #endif 165 140 /* TODO: Allocate pools for osd_request attributes ... */ 166 141 } 167 142 EXPORT_SYMBOL(osd_dev_init); ··· 365 334 ocdb->h.v1.start_address = cpu_to_be64(offset); 366 335 } 367 336 337 + static void _osdv2_req_encode_common(struct osd_request *or, 338 + __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) 339 + { 340 + struct osdv2_cdb *ocdb = &or->cdb.v2; 341 + 342 + OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act)); 343 + 344 + ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD; 345 + ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH; 346 + ocdb->h.varlen_cdb.service_action = act; 347 + 348 + ocdb->h.partition = cpu_to_be64(obj->partition); 349 + ocdb->h.object = cpu_to_be64(obj->id); 350 + ocdb->h.v2.length = cpu_to_be64(len); 351 + ocdb->h.v2.start_address = cpu_to_be64(offset); 352 + } 353 + 368 354 static void _osd_req_encode_common(struct osd_request *or, 369 355 __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) 370 356 { 371 - _osdv1_req_encode_common(or, act, obj, offset, len); 357 + if (osd_req_is_ver1(or)) 358 + _osdv1_req_encode_common(or, act, obj, offset, len); 359 + else 360 + _osdv2_req_encode_common(or, act, obj, offset, len); 372 361 } 373 362 374 363 /* ··· 597 546 const struct osd_obj_id *obj, enum osd_options_flush_scope_values op, 598 547 /*V2*/ u64 offset, /*V2*/ u64 len) 599 548 { 549 + if (unlikely(osd_req_is_ver1(or) && (offset || len))) { 550 + OSD_DEBUG("OSD Ver1 flush on specific range ignored\n"); 551 + offset = 0; 552 + len = 0; 553 + } 554 + 600 555 _osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len); 601 556 _osd_req_encode_flush(or, op); 602 557 } ··· 1226 1169 OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT 1227 1170 }; 1228 1171 1172 + enum { OSD_SEC_CAP_V2_ALL_CAPS = 1173 + OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT 1174 + }; 1175 + 1229 1176 void osd_sec_init_nosec_doall_caps(void *caps, 1230 1177 const struct osd_obj_id *obj, bool is_collection, const bool is_v1) 1231 1178 { ··· 1271 1210 } 1272 1211 EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps); 1273 1212 1213 + /* FIXME: Extract version from caps pointer. 1214 + * Also Pete's target only supports caps from OSDv1 for now 1215 + */ 1274 1216 void osd_set_caps(struct osd_cdb *cdb, const void *caps) 1275 1217 { 1276 - memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN); 1218 + bool is_ver1 = true; 1219 + /* NOTE: They start at same address */ 1220 + memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN); 1277 1221 } 1278 1222 1279 1223 bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
+39
include/scsi/osd_initiator.h
··· 21 21 22 22 /* Note: "NI" in comments below means "Not Implemented yet" */ 23 23 24 + /* Configure of code: 25 + * #undef if you *don't* want OSD v1 support in runtime. 26 + * If #defined the initiator will dynamically configure to encode OSD v1 27 + * CDB's if the target is detected to be OSD v1 only. 28 + * OSD v2 only commands, options, and attributes will be ignored if target 29 + * is v1 only. 30 + * If #defined will result in bigger/slower code (OK Slower maybe not) 31 + * Q: Should this be CONFIG_SCSI_OSD_VER1_SUPPORT and set from Kconfig? 32 + */ 33 + #define OSD_VER1_SUPPORT y 34 + 35 + enum osd_std_version { 36 + OSD_VER_NONE = 0, 37 + OSD_VER1 = 1, 38 + OSD_VER2 = 2, 39 + }; 40 + 24 41 /* 25 42 * Object-based Storage Device. 26 43 * This object represents an OSD device. ··· 48 31 struct osd_dev { 49 32 struct scsi_device *scsi_device; 50 33 unsigned def_timeout; 34 + 35 + #ifdef OSD_VER1_SUPPORT 36 + enum osd_std_version version; 37 + #endif 51 38 }; 52 39 53 40 /* Retrieve/return osd_dev(s) for use by Kernel clients */ ··· 66 45 /* These are called by uld at probe time */ 67 46 void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device); 68 47 void osd_dev_fini(struct osd_dev *od); 48 + 49 + /* we might want to use function vector in the future */ 50 + static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v) 51 + { 52 + #ifdef OSD_VER1_SUPPORT 53 + od->version = v; 54 + #endif 55 + } 69 56 70 57 struct osd_request; 71 58 typedef void (osd_req_done_fn)(struct osd_request *or, void *private); ··· 110 81 void *async_private; 111 82 int async_error; 112 83 }; 84 + 85 + /* OSD Version control */ 86 + static inline bool osd_req_is_ver1(struct osd_request *or) 87 + { 88 + #ifdef OSD_VER1_SUPPORT 89 + return or->osd_dev->version == OSD_VER1; 90 + #else 91 + return false; 92 + #endif 93 + } 113 94 114 95 /* 115 96 * How to use the osd library:
+86 -4
include/scsi/osd_protocol.h
··· 25 25 OSDv1_TOTAL_CDB_LEN = OSDv1_ADDITIONAL_CDB_LENGTH + 8, 26 26 OSDv1_CAP_LEN = 80, 27 27 /* Latest supported version */ 28 - OSD_ADDITIONAL_CDB_LENGTH = OSDv1_ADDITIONAL_CDB_LENGTH, 29 - OSD_TOTAL_CDB_LEN = OSDv1_TOTAL_CDB_LEN, 30 - OSD_CAP_LEN = OSDv1_CAP_LEN, 28 + /* OSD_ADDITIONAL_CDB_LENGTH = 216,*/ 29 + OSD_ADDITIONAL_CDB_LENGTH = 30 + OSDv1_ADDITIONAL_CDB_LENGTH, /* FIXME: Pete rev-001 sup */ 31 + OSD_TOTAL_CDB_LEN = OSD_ADDITIONAL_CDB_LENGTH + 8, 32 + /* OSD_CAP_LEN = 104,*/ 33 + OSD_CAP_LEN = OSDv1_CAP_LEN,/* FIXME: Pete rev-001 sup */ 31 34 32 35 OSD_SYSTEMID_LEN = 20, 33 36 OSD_CRYPTO_KEYID_SIZE = 20, 37 + /*FIXME: OSDv2_CRYPTO_KEYID_SIZE = 32,*/ 34 38 OSD_CRYPTO_SEED_SIZE = 4, 35 39 OSD_CRYPTO_NONCE_SIZE = 12, 36 40 OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */ ··· 112 108 OSD_OFFSET_MAX_BITS = 28, 113 109 114 110 OSDv1_OFFSET_MIN_SHIFT = 8, 111 + OSD_OFFSET_MIN_SHIFT = 3, 115 112 OSD_OFFSET_MAX_SHIFT = 16, 116 113 }; 117 114 ··· 134 129 OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT); 135 130 } 136 131 132 + /* Minimum 8 bytes alignment 133 + * Same as v1 but since exponent can be signed than a less than 134 + * 256 alignment can be reached with small offsets (<2GB) 135 + */ 136 + static inline osd_cdb_offset osd_encode_offset_v2(u64 offset, unsigned *padding) 137 + { 138 + return __osd_encode_offset(offset, padding, 139 + OSD_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT); 140 + } 141 + 137 142 /* osd2r03: 5.2.1 Overview */ 138 143 struct osd_cdb_head { 139 144 struct scsi_varlen_cdb_hdr varlen_cdb; ··· 159 144 /*36*/ __be64 length; 160 145 /*44*/ __be64 start_address; 161 146 } __packed v1; 147 + 148 + struct __osdv2_cdb_addr_len { 149 + /* called allocation_length in some commands */ 150 + /*32*/ __be64 length; 151 + /*40*/ __be64 start_address; 152 + /*48*/ __be32 list_identifier;/* Rarely used */ 153 + } __packed v2; 162 154 }; 163 155 /*52*/ union { /* selected attributes mode Page/List/Single */ 164 156 struct osd_attributes_page_mode { ··· 204 182 /*80*/ 205 183 206 184 /*160 v1*/ 185 + /*184 v2*/ 207 186 struct osd_security_parameters { 208 187 /*160*/u8 integrity_check_value[OSD_CRYPTO_KEYID_SIZE]; 209 188 /*180*/u8 request_nonce[OSD_CRYPTO_NONCE_SIZE]; ··· 212 189 /*196*/osd_cdb_offset data_out_integrity_check_offset; 213 190 } __packed; 214 191 /*200 v1*/ 192 + /*224 v2*/ 193 + 194 + /* FIXME: osdv2_security_parameters */ 215 195 216 196 struct osdv1_cdb { 217 197 struct osd_cdb_head h; ··· 222 196 struct osd_security_parameters sec_params; 223 197 } __packed; 224 198 199 + struct osdv2_cdb { 200 + struct osd_cdb_head h; 201 + u8 caps[OSD_CAP_LEN]; 202 + struct osd_security_parameters sec_params; 203 + /* FIXME: osdv2_security_parameters */ 204 + } __packed; 205 + 225 206 struct osd_cdb { 226 207 union { 227 208 struct osdv1_cdb v1; 209 + struct osdv2_cdb v2; 228 210 u8 buff[OSD_TOTAL_CDB_LEN]; 229 211 }; 230 212 } __packed; ··· 303 269 /* 304 270 * osd2r03: 7.1.3.3 List entry format for retrieved attributes and 305 271 * for setting attributes 272 + * NOTE: v2 is 8-bytes aligned, v1 is not aligned. 306 273 */ 307 274 struct osd_attributes_list_element { 308 275 __be32 attr_page; ··· 314 279 315 280 enum { 316 281 OSDv1_ATTRIBUTES_ELEM_ALIGN = 1, 282 + OSD_ATTRIBUTES_ELEM_ALIGN = 8, 317 283 }; 318 284 319 285 enum { ··· 326 290 { 327 291 return ALIGN(len + sizeof(struct osd_attributes_list_element), 328 292 OSDv1_ATTRIBUTES_ELEM_ALIGN); 293 + } 294 + 295 + static inline unsigned osdv2_attr_list_elem_size(unsigned len) 296 + { 297 + return ALIGN(len + sizeof(struct osd_attributes_list_element), 298 + OSD_ATTRIBUTES_ELEM_ALIGN); 329 299 } 330 300 331 301 /* ··· 366 324 static inline unsigned osdv1_list_size(struct osdv1_attributes_list_header *h) 367 325 { 368 326 return be16_to_cpu(h->list_bytes); 327 + } 328 + 329 + struct osdv2_attributes_list_header { 330 + u8 type; /* lower 4-bits only */ 331 + u8 pad[3]; 332 + /*4*/ __be32 list_bytes; /* Initiator shall set to zero. Only set by target */ 333 + /* 334 + * type=9 followed by struct osd_attributes_list_element's 335 + * type=E followed by struct osd_attributes_list_multi_header's 336 + */ 337 + } __packed; 338 + 339 + static inline unsigned osdv2_list_size(struct osdv2_attributes_list_header *h) 340 + { 341 + return be32_to_cpu(h->list_bytes); 369 342 } 370 343 371 344 /* (osd-r10 6.13) ··· 526 469 } __packed; 527 470 /*80 v1*/ 528 471 529 - struct osd_capability { 472 + /*56 v2*/ 473 + struct osd_cap_object_descriptor { 474 + union { 475 + struct { 476 + /*56*/ __be32 allowed_attributes_access; 477 + /*60*/ __be32 policy_access_tag; 478 + /*64*/ __be16 boot_epoch; 479 + /*66*/ u8 reserved[6]; 480 + /*72*/ __be64 allowed_partition_id; 481 + /*80*/ __be64 allowed_object_id; 482 + /*88*/ __be64 allowed_range_length; 483 + /*96*/ __be64 allowed_range_start; 484 + } __packed obj_desc; 485 + 486 + /*56*/ u8 object_descriptor[48]; 487 + }; 488 + } __packed; 489 + /*104 v2*/ 490 + 491 + struct osdv1_capability { 530 492 struct osd_capability_head h; 531 493 struct osdv1_cap_object_descriptor od; 494 + } __packed; 495 + 496 + struct osd_capability { 497 + struct osd_capability_head h; 498 + /* struct osd_cap_object_descriptor od;*/ 499 + struct osdv1_cap_object_descriptor od; /* FIXME: Pete rev-001 sup */ 532 500 } __packed; 533 501 534 502 /**