diff options
Diffstat (limited to 'drivers/scsi/osd/osd_initiator.c')
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 86 |
1 files changed, 68 insertions, 18 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 | } |