diff options
-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 | ||