diff options
| author | Boaz Harrosh <bharrosh@panasas.com> | 2009-04-19 12:11:42 -0400 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-27 12:05:40 -0400 |
| commit | 71f32e31e5638df37904697e2d04182935add85d (patch) | |
| tree | 2f1ab62477f8d5129cbae751c219a2c069fa31b8 | |
| parent | bf5e84f69618f416e89a5a53434a8c865e70252e (diff) | |
[SCSI] libosd: OSD2r05: Prepare for rev5 attribute list changes
In OSD2r05 draft each attribute list element header was changed
so attribute-value would be 8 bytes aligned. In OSD2r01-r04
it was aligned on 2 bytes. (This is because in OSD2r01 the complete
element was 8 bytes padded at end but the header was not adjusted
and caused permanent miss-alignment.)
OSD1 elements are not padded and might be or might not be aligned.
OSD1 is still supported.
In this code we do all the code re-factoring to separate OSD1/OSD2
differences but do not change actual wire format. All wire format
changes will happen in one patch later, for bisect-ability.
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
| -rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 86 | ||||
| -rw-r--r-- | include/scsi/osd_protocol.h | 20 |
2 files changed, 83 insertions, 23 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index 76de88962237..e266f803aa96 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
| @@ -205,6 +205,69 @@ static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len) | |||
| 205 | osdv2_attr_list_elem_size(len); | 205 | osdv2_attr_list_elem_size(len); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static void _osd_req_alist_elem_encode(struct osd_request *or, | ||
| 209 | void *attr_last, const struct osd_attr *oa) | ||
| 210 | { | ||
| 211 | if (osd_req_is_ver1(or)) { | ||
| 212 | struct osdv1_attributes_list_element *attr = attr_last; | ||
| 213 | |||
| 214 | attr->attr_page = cpu_to_be32(oa->attr_page); | ||
| 215 | attr->attr_id = cpu_to_be32(oa->attr_id); | ||
| 216 | attr->attr_bytes = cpu_to_be16(oa->len); | ||
| 217 | memcpy(attr->attr_val, oa->val_ptr, oa->len); | ||
| 218 | } else { | ||
| 219 | struct osdv2_attributes_list_element *attr = attr_last; | ||
| 220 | |||
| 221 | attr->attr_page = cpu_to_be32(oa->attr_page); | ||
| 222 | attr->attr_id = cpu_to_be32(oa->attr_id); | ||
| 223 | attr->attr_bytes = cpu_to_be16(oa->len); | ||
| 224 | memcpy(attr->attr_val, oa->val_ptr, oa->len); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | static int _osd_req_alist_elem_decode(struct osd_request *or, | ||
| 229 | void *cur_p, struct osd_attr *oa, unsigned max_bytes) | ||
| 230 | { | ||
| 231 | unsigned inc; | ||
| 232 | if (osd_req_is_ver1(or)) { | ||
| 233 | struct osdv1_attributes_list_element *attr = cur_p; | ||
| 234 | |||
| 235 | if (max_bytes < sizeof(*attr)) | ||
| 236 | return -1; | ||
| 237 | |||
| 238 | oa->len = be16_to_cpu(attr->attr_bytes); | ||
| 239 | inc = _osd_req_alist_elem_size(or, oa->len); | ||
| 240 | if (inc > max_bytes) | ||
| 241 | return -1; | ||
| 242 | |||
| 243 | oa->attr_page = be32_to_cpu(attr->attr_page); | ||
| 244 | oa->attr_id = be32_to_cpu(attr->attr_id); | ||
| 245 | |||
| 246 | /* OSD1: On empty attributes we return a pointer to 2 bytes | ||
| 247 | * of zeros. This keeps similar behaviour with OSD2. | ||
| 248 | * (See below) | ||
| 249 | */ | ||
| 250 | oa->val_ptr = likely(oa->len) ? attr->attr_val : | ||
| 251 | (u8 *)&attr->attr_bytes; | ||
| 252 | } else { | ||
| 253 | struct osdv2_attributes_list_element *attr = cur_p; | ||
| 254 | |||
| 255 | if (max_bytes < sizeof(*attr)) | ||
| 256 | return -1; | ||
| 257 | |||
| 258 | oa->len = be16_to_cpu(attr->attr_bytes); | ||
| 259 | inc = _osd_req_alist_elem_size(or, oa->len); | ||
| 260 | if (inc > max_bytes) | ||
| 261 | return -1; | ||
| 262 | |||
| 263 | oa->attr_page = be32_to_cpu(attr->attr_page); | ||
| 264 | oa->attr_id = be32_to_cpu(attr->attr_id); | ||
| 265 | |||
| 266 | oa->val_ptr = attr->attr_val; | ||
| 267 | } | ||
| 268 | return inc; | ||
| 269 | } | ||
| 270 | |||
| 208 | static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head) | 271 | static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head) |
| 209 | { | 272 | { |
| 210 | return osd_req_is_ver1(or) ? | 273 | return osd_req_is_ver1(or) ? |
| @@ -798,7 +861,6 @@ int osd_req_add_set_attr_list(struct osd_request *or, | |||
| 798 | attr_last = or->set_attr.buff + total_bytes; | 861 | attr_last = or->set_attr.buff + total_bytes; |
| 799 | 862 | ||
| 800 | for (; nelem; --nelem) { | 863 | for (; nelem; --nelem) { |
| 801 | struct osd_attributes_list_element *attr; | ||
| 802 | unsigned elem_size = _osd_req_alist_elem_size(or, oa->len); | 864 | unsigned elem_size = _osd_req_alist_elem_size(or, oa->len); |
| 803 | 865 | ||
| 804 | total_bytes += elem_size; | 866 | total_bytes += elem_size; |
| @@ -811,11 +873,7 @@ int osd_req_add_set_attr_list(struct osd_request *or, | |||
| 811 | or->set_attr.buff + or->set_attr.total_bytes; | 873 | or->set_attr.buff + or->set_attr.total_bytes; |
| 812 | } | 874 | } |
| 813 | 875 | ||
| 814 | attr = attr_last; | 876 | _osd_req_alist_elem_encode(or, attr_last, oa); |
| 815 | attr->attr_page = cpu_to_be32(oa->attr_page); | ||
| 816 | attr->attr_id = cpu_to_be32(oa->attr_id); | ||
| 817 | attr->attr_bytes = cpu_to_be16(oa->len); | ||
| 818 | memcpy(attr->attr_val, oa->val_ptr, oa->len); | ||
| 819 | 877 | ||
| 820 | attr_last += elem_size; | 878 | attr_last += elem_size; |
| 821 | ++oa; | 879 | ++oa; |
| @@ -1070,15 +1128,10 @@ int osd_req_decode_get_attr_list(struct osd_request *or, | |||
| 1070 | } | 1128 | } |
| 1071 | 1129 | ||
| 1072 | for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) { | 1130 | for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) { |
| 1073 | struct osd_attributes_list_element *attr = cur_p; | 1131 | int inc = _osd_req_alist_elem_decode(or, cur_p, oa, |
| 1074 | unsigned inc; | 1132 | returned_bytes - cur_bytes); |
| 1075 | 1133 | ||
| 1076 | oa->len = be16_to_cpu(attr->attr_bytes); | 1134 | if (inc < 0) { |
| 1077 | inc = _osd_req_alist_elem_size(or, oa->len); | ||
| 1078 | OSD_DEBUG("oa->len=%d inc=%d cur_bytes=%d\n", | ||
| 1079 | oa->len, inc, cur_bytes); | ||
| 1080 | cur_bytes += inc; | ||
| 1081 | if (cur_bytes > returned_bytes) { | ||
| 1082 | OSD_ERR("BAD FOOD from target. list not valid!" | 1135 | OSD_ERR("BAD FOOD from target. list not valid!" |
| 1083 | "c=%d r=%d n=%d\n", | 1136 | "c=%d r=%d n=%d\n", |
| 1084 | cur_bytes, returned_bytes, n); | 1137 | cur_bytes, returned_bytes, n); |
| @@ -1086,10 +1139,7 @@ int osd_req_decode_get_attr_list(struct osd_request *or, | |||
| 1086 | break; | 1139 | break; |
| 1087 | } | 1140 | } |
| 1088 | 1141 | ||
| 1089 | oa->attr_page = be32_to_cpu(attr->attr_page); | 1142 | cur_bytes += inc; |
| 1090 | oa->attr_id = be32_to_cpu(attr->attr_id); | ||
| 1091 | oa->val_ptr = attr->attr_val; | ||
| 1092 | |||
| 1093 | cur_p += inc; | 1143 | cur_p += inc; |
| 1094 | ++oa; | 1144 | ++oa; |
| 1095 | } | 1145 | } |
diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h index cd3cbf764650..fa8343ce3ca2 100644 --- a/include/scsi/osd_protocol.h +++ b/include/scsi/osd_protocol.h | |||
| @@ -301,14 +301,24 @@ struct osd_attributes_list_attrid { | |||
| 301 | } __packed; | 301 | } __packed; |
| 302 | 302 | ||
| 303 | /* | 303 | /* |
| 304 | * NOTE: v1: is not aligned. | ||
| 305 | */ | ||
| 306 | struct osdv1_attributes_list_element { | ||
| 307 | __be32 attr_page; | ||
| 308 | __be32 attr_id; | ||
| 309 | __be16 attr_bytes; /* valid bytes at attr_val without padding */ | ||
| 310 | u8 attr_val[0]; | ||
| 311 | } __packed; | ||
| 312 | |||
| 313 | /* | ||
| 304 | * osd2r03: 7.1.3.3 List entry format for retrieved attributes and | 314 | * osd2r03: 7.1.3.3 List entry format for retrieved attributes and |
| 305 | * for setting attributes | 315 | * for setting attributes |
| 306 | * NOTE: v2 is 8-bytes aligned, v1 is not aligned. | 316 | * NOTE: v2 is 8-bytes aligned |
| 307 | */ | 317 | */ |
| 308 | struct osd_attributes_list_element { | 318 | struct osdv2_attributes_list_element { |
| 309 | __be32 attr_page; | 319 | __be32 attr_page; |
| 310 | __be32 attr_id; | 320 | __be32 attr_id; |
| 311 | __be16 attr_bytes; | 321 | __be16 attr_bytes; /* valid bytes at attr_val without padding */ |
| 312 | u8 attr_val[0]; | 322 | u8 attr_val[0]; |
| 313 | } __packed; | 323 | } __packed; |
| 314 | 324 | ||
| @@ -324,13 +334,13 @@ enum { | |||
| 324 | 334 | ||
| 325 | static inline unsigned osdv1_attr_list_elem_size(unsigned len) | 335 | static inline unsigned osdv1_attr_list_elem_size(unsigned len) |
| 326 | { | 336 | { |
| 327 | return ALIGN(len + sizeof(struct osd_attributes_list_element), | 337 | return ALIGN(len + sizeof(struct osdv1_attributes_list_element), |
| 328 | OSDv1_ATTRIBUTES_ELEM_ALIGN); | 338 | OSDv1_ATTRIBUTES_ELEM_ALIGN); |
| 329 | } | 339 | } |
| 330 | 340 | ||
| 331 | static inline unsigned osdv2_attr_list_elem_size(unsigned len) | 341 | static inline unsigned osdv2_attr_list_elem_size(unsigned len) |
| 332 | { | 342 | { |
| 333 | return ALIGN(len + sizeof(struct osd_attributes_list_element), | 343 | return ALIGN(len + sizeof(struct osdv2_attributes_list_element), |
| 334 | OSD_ATTRIBUTES_ELEM_ALIGN); | 344 | OSD_ATTRIBUTES_ELEM_ALIGN); |
| 335 | } | 345 | } |
| 336 | 346 | ||
