950202a70bcf5ea236924edaad5cf35734bfc4cf
[safe/jmp/linux-2.6] / drivers / scsi / osd / osd_initiator.c
1 /*
2  * osd_initiator - Main body of the osd initiator library.
3  *
4  * Note: The file does not contain the advanced security functionality which
5  * is only needed by the security_manager's initiators.
6  *
7  * Copyright (C) 2008 Panasas Inc.  All rights reserved.
8  *
9  * Authors:
10  *   Boaz Harrosh <bharrosh@panasas.com>
11  *   Benny Halevy <bhalevy@panasas.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  *
20  *  1. Redistributions of source code must retain the above copyright
21  *     notice, this list of conditions and the following disclaimer.
22  *  2. Redistributions in binary form must reproduce the above copyright
23  *     notice, this list of conditions and the following disclaimer in the
24  *     documentation and/or other materials provided with the distribution.
25  *  3. Neither the name of the Panasas company nor the names of its
26  *     contributors may be used to endorse or promote products derived
27  *     from this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
30  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
36  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  */
41
42 #include <scsi/osd_initiator.h>
43 #include <scsi/osd_sec.h>
44 #include <scsi/osd_attributes.h>
45 #include <scsi/osd_sense.h>
46
47 #include <scsi/scsi_device.h>
48
49 #include "osd_debug.h"
50
51 #ifndef __unused
52 #    define __unused                    __attribute__((unused))
53 #endif
54
55 enum { OSD_REQ_RETRIES = 1 };
56
57 MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
58 MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
59 MODULE_LICENSE("GPL");
60
61 static inline void build_test(void)
62 {
63         /* structures were not packed */
64         BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN);
65         BUILD_BUG_ON(sizeof(struct osdv2_cdb) != OSD_TOTAL_CDB_LEN);
66         BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
67 }
68
69 static const char *_osd_ver_desc(struct osd_request *or)
70 {
71         return osd_req_is_ver1(or) ? "OSD1" : "OSD2";
72 }
73
74 #define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len)
75
76 static int _osd_get_print_system_info(struct osd_dev *od,
77         void *caps, struct osd_dev_info *odi)
78 {
79         struct osd_request *or;
80         struct osd_attr get_attrs[] = {
81                 ATTR_DEF_RI(OSD_ATTR_RI_VENDOR_IDENTIFICATION, 8),
82                 ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_IDENTIFICATION, 16),
83                 ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_MODEL, 32),
84                 ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_REVISION_LEVEL, 4),
85                 ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER, 64 /*variable*/),
86                 ATTR_DEF_RI(OSD_ATTR_RI_OSD_NAME, 64 /*variable*/),
87                 ATTR_DEF_RI(OSD_ATTR_RI_TOTAL_CAPACITY, 8),
88                 ATTR_DEF_RI(OSD_ATTR_RI_USED_CAPACITY, 8),
89                 ATTR_DEF_RI(OSD_ATTR_RI_NUMBER_OF_PARTITIONS, 8),
90                 ATTR_DEF_RI(OSD_ATTR_RI_CLOCK, 6),
91                 /* IBM-OSD-SIM Has a bug with this one put it last */
92                 ATTR_DEF_RI(OSD_ATTR_RI_OSD_SYSTEM_ID, 20),
93         };
94         void *iter = NULL, *pFirst;
95         int nelem = ARRAY_SIZE(get_attrs), a = 0;
96         int ret;
97
98         or = osd_start_request(od, GFP_KERNEL);
99         if (!or)
100                 return -ENOMEM;
101
102         /* get attrs */
103         osd_req_get_attributes(or, &osd_root_object);
104         osd_req_add_get_attr_list(or, get_attrs, ARRAY_SIZE(get_attrs));
105
106         ret = osd_finalize_request(or, 0, caps, NULL);
107         if (ret)
108                 goto out;
109
110         ret = osd_execute_request(or);
111         if (ret) {
112                 OSD_ERR("Failed to detect %s => %d\n", _osd_ver_desc(or), ret);
113                 goto out;
114         }
115
116         osd_req_decode_get_attr_list(or, get_attrs, &nelem, &iter);
117
118         OSD_INFO("Detected %s device\n",
119                 _osd_ver_desc(or));
120
121         pFirst = get_attrs[a++].val_ptr;
122         OSD_INFO("VENDOR_IDENTIFICATION  [%s]\n",
123                 (char *)pFirst);
124
125         pFirst = get_attrs[a++].val_ptr;
126         OSD_INFO("PRODUCT_IDENTIFICATION [%s]\n",
127                 (char *)pFirst);
128
129         pFirst = get_attrs[a++].val_ptr;
130         OSD_INFO("PRODUCT_MODEL          [%s]\n",
131                 (char *)pFirst);
132
133         pFirst = get_attrs[a++].val_ptr;
134         OSD_INFO("PRODUCT_REVISION_LEVEL [%u]\n",
135                 pFirst ? get_unaligned_be32(pFirst) : ~0U);
136
137         pFirst = get_attrs[a++].val_ptr;
138         OSD_INFO("PRODUCT_SERIAL_NUMBER  [%s]\n",
139                 (char *)pFirst);
140
141         odi->osdname_len = get_attrs[a].len;
142         /* Avoid NULL for memcmp optimization 0-length is good enough */
143         odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL);
144         if (odi->osdname_len)
145                 memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len);
146         OSD_INFO("OSD_NAME               [%s]\n", odi->osdname);
147         a++;
148
149         pFirst = get_attrs[a++].val_ptr;
150         OSD_INFO("TOTAL_CAPACITY         [0x%llx]\n",
151                 pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
152
153         pFirst = get_attrs[a++].val_ptr;
154         OSD_INFO("USED_CAPACITY          [0x%llx]\n",
155                 pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
156
157         pFirst = get_attrs[a++].val_ptr;
158         OSD_INFO("NUMBER_OF_PARTITIONS   [%llu]\n",
159                 pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL);
160
161         if (a >= nelem)
162                 goto out;
163
164         /* FIXME: Where are the time utilities */
165         pFirst = get_attrs[a++].val_ptr;
166         OSD_INFO("CLOCK                  [0x%02x%02x%02x%02x%02x%02x]\n",
167                 ((char *)pFirst)[0], ((char *)pFirst)[1],
168                 ((char *)pFirst)[2], ((char *)pFirst)[3],
169                 ((char *)pFirst)[4], ((char *)pFirst)[5]);
170
171         if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
172                 unsigned len = get_attrs[a].len;
173                 char sid_dump[32*4 + 2]; /* 2nibbles+space+ASCII */
174
175                 hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1,
176                                    sid_dump, sizeof(sid_dump), true);
177                 OSD_INFO("OSD_SYSTEM_ID(%d)\n"
178                          "        [%s]\n", len, sid_dump);
179
180                 if (unlikely(len > sizeof(odi->systemid))) {
181                         OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). "
182                                 "device idetification might not work\n", len);
183                         len = sizeof(odi->systemid);
184                 }
185                 odi->systemid_len = len;
186                 memcpy(odi->systemid, get_attrs[a].val_ptr, len);
187                 a++;
188         }
189 out:
190         osd_end_request(or);
191         return ret;
192 }
193
194 int osd_auto_detect_ver(struct osd_dev *od,
195         void *caps, struct osd_dev_info *odi)
196 {
197         int ret;
198
199         /* Auto-detect the osd version */
200         ret = _osd_get_print_system_info(od, caps, odi);
201         if (ret) {
202                 osd_dev_set_ver(od, OSD_VER1);
203                 OSD_DEBUG("converting to OSD1\n");
204                 ret = _osd_get_print_system_info(od, caps, odi);
205         }
206
207         return ret;
208 }
209 EXPORT_SYMBOL(osd_auto_detect_ver);
210
211 static unsigned _osd_req_cdb_len(struct osd_request *or)
212 {
213         return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN;
214 }
215
216 static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len)
217 {
218         return osd_req_is_ver1(or) ?
219                 osdv1_attr_list_elem_size(len) :
220                 osdv2_attr_list_elem_size(len);
221 }
222
223 static void _osd_req_alist_elem_encode(struct osd_request *or,
224         void *attr_last, const struct osd_attr *oa)
225 {
226         if (osd_req_is_ver1(or)) {
227                 struct osdv1_attributes_list_element *attr = attr_last;
228
229                 attr->attr_page = cpu_to_be32(oa->attr_page);
230                 attr->attr_id = cpu_to_be32(oa->attr_id);
231                 attr->attr_bytes = cpu_to_be16(oa->len);
232                 memcpy(attr->attr_val, oa->val_ptr, oa->len);
233         } else {
234                 struct osdv2_attributes_list_element *attr = attr_last;
235
236                 attr->attr_page = cpu_to_be32(oa->attr_page);
237                 attr->attr_id = cpu_to_be32(oa->attr_id);
238                 attr->attr_bytes = cpu_to_be16(oa->len);
239                 memcpy(attr->attr_val, oa->val_ptr, oa->len);
240         }
241 }
242
243 static int _osd_req_alist_elem_decode(struct osd_request *or,
244         void *cur_p, struct osd_attr *oa, unsigned max_bytes)
245 {
246         unsigned inc;
247         if (osd_req_is_ver1(or)) {
248                 struct osdv1_attributes_list_element *attr = cur_p;
249
250                 if (max_bytes < sizeof(*attr))
251                         return -1;
252
253                 oa->len = be16_to_cpu(attr->attr_bytes);
254                 inc = _osd_req_alist_elem_size(or, oa->len);
255                 if (inc > max_bytes)
256                         return -1;
257
258                 oa->attr_page = be32_to_cpu(attr->attr_page);
259                 oa->attr_id = be32_to_cpu(attr->attr_id);
260
261                 /* OSD1: On empty attributes we return a pointer to 2 bytes
262                  * of zeros. This keeps similar behaviour with OSD2.
263                  * (See below)
264                  */
265                 oa->val_ptr = likely(oa->len) ? attr->attr_val :
266                                                 (u8 *)&attr->attr_bytes;
267         } else {
268                 struct osdv2_attributes_list_element *attr = cur_p;
269
270                 if (max_bytes < sizeof(*attr))
271                         return -1;
272
273                 oa->len = be16_to_cpu(attr->attr_bytes);
274                 inc = _osd_req_alist_elem_size(or, oa->len);
275                 if (inc > max_bytes)
276                         return -1;
277
278                 oa->attr_page = be32_to_cpu(attr->attr_page);
279                 oa->attr_id = be32_to_cpu(attr->attr_id);
280
281                 /* OSD2: For convenience, on empty attributes, we return 8 bytes
282                  * of zeros here. This keeps the same behaviour with OSD2r04,
283                  * and is nice with null terminating ASCII fields.
284                  * oa->val_ptr == NULL marks the end-of-list, or error.
285                  */
286                 oa->val_ptr = likely(oa->len) ? attr->attr_val : attr->reserved;
287         }
288         return inc;
289 }
290
291 static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head)
292 {
293         return osd_req_is_ver1(or) ?
294                 osdv1_list_size(list_head) :
295                 osdv2_list_size(list_head);
296 }
297
298 static unsigned _osd_req_sizeof_alist_header(struct osd_request *or)
299 {
300         return osd_req_is_ver1(or) ?
301                 sizeof(struct osdv1_attributes_list_header) :
302                 sizeof(struct osdv2_attributes_list_header);
303 }
304
305 static void _osd_req_set_alist_type(struct osd_request *or,
306         void *list, int list_type)
307 {
308         if (osd_req_is_ver1(or)) {
309                 struct osdv1_attributes_list_header *attr_list = list;
310
311                 memset(attr_list, 0, sizeof(*attr_list));
312                 attr_list->type = list_type;
313         } else {
314                 struct osdv2_attributes_list_header *attr_list = list;
315
316                 memset(attr_list, 0, sizeof(*attr_list));
317                 attr_list->type = list_type;
318         }
319 }
320
321 static bool _osd_req_is_alist_type(struct osd_request *or,
322         void *list, int list_type)
323 {
324         if (!list)
325                 return false;
326
327         if (osd_req_is_ver1(or)) {
328                 struct osdv1_attributes_list_header *attr_list = list;
329
330                 return attr_list->type == list_type;
331         } else {
332                 struct osdv2_attributes_list_header *attr_list = list;
333
334                 return attr_list->type == list_type;
335         }
336 }
337
338 /* This is for List-objects not Attributes-Lists */
339 static void _osd_req_encode_olist(struct osd_request *or,
340         struct osd_obj_id_list *list)
341 {
342         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
343
344         if (osd_req_is_ver1(or)) {
345                 cdbh->v1.list_identifier = list->list_identifier;
346                 cdbh->v1.start_address = list->continuation_id;
347         } else {
348                 cdbh->v2.list_identifier = list->list_identifier;
349                 cdbh->v2.start_address = list->continuation_id;
350         }
351 }
352
353 static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
354         u64 offset, unsigned *padding)
355 {
356         return __osd_encode_offset(offset, padding,
357                         osd_req_is_ver1(or) ?
358                                 OSDv1_OFFSET_MIN_SHIFT : OSD_OFFSET_MIN_SHIFT,
359                         OSD_OFFSET_MAX_SHIFT);
360 }
361
362 static struct osd_security_parameters *
363 _osd_req_sec_params(struct osd_request *or)
364 {
365         struct osd_cdb *ocdb = &or->cdb;
366
367         if (osd_req_is_ver1(or))
368                 return (struct osd_security_parameters *)&ocdb->v1.sec_params;
369         else
370                 return (struct osd_security_parameters *)&ocdb->v2.sec_params;
371 }
372
373 void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
374 {
375         memset(osdd, 0, sizeof(*osdd));
376         osdd->scsi_device = scsi_device;
377         osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
378 #ifdef OSD_VER1_SUPPORT
379         osdd->version = OSD_VER2;
380 #endif
381         /* TODO: Allocate pools for osd_request attributes ... */
382 }
383 EXPORT_SYMBOL(osd_dev_init);
384
385 void osd_dev_fini(struct osd_dev *osdd)
386 {
387         /* TODO: De-allocate pools */
388
389         osdd->scsi_device = NULL;
390 }
391 EXPORT_SYMBOL(osd_dev_fini);
392
393 static struct osd_request *_osd_request_alloc(gfp_t gfp)
394 {
395         struct osd_request *or;
396
397         /* TODO: Use mempool with one saved request */
398         or = kzalloc(sizeof(*or), gfp);
399         return or;
400 }
401
402 static void _osd_request_free(struct osd_request *or)
403 {
404         kfree(or);
405 }
406
407 struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp)
408 {
409         struct osd_request *or;
410
411         or = _osd_request_alloc(gfp);
412         if (!or)
413                 return NULL;
414
415         or->osd_dev = dev;
416         or->alloc_flags = gfp;
417         or->timeout = dev->def_timeout;
418         or->retries = OSD_REQ_RETRIES;
419
420         return or;
421 }
422 EXPORT_SYMBOL(osd_start_request);
423
424 static void _osd_free_seg(struct osd_request *or __unused,
425         struct _osd_req_data_segment *seg)
426 {
427         if (!seg->buff || !seg->alloc_size)
428                 return;
429
430         kfree(seg->buff);
431         seg->buff = NULL;
432         seg->alloc_size = 0;
433 }
434
435 static void _put_request(struct request *rq , bool is_async)
436 {
437         if (is_async) {
438                 WARN_ON(rq->bio);
439                 __blk_put_request(rq->q, rq);
440         } else {
441                 /*
442                  * If osd_finalize_request() was called but the request was not
443                  * executed through the block layer, then we must release BIOs.
444                  * TODO: Keep error code in or->async_error. Need to audit all
445                  *       code paths.
446                  */
447                 if (unlikely(rq->bio))
448                         blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq));
449                 else
450                         blk_put_request(rq);
451         }
452 }
453
454 void osd_end_request(struct osd_request *or)
455 {
456         struct request *rq = or->request;
457         /* IMPORTANT: make sure this agrees with osd_execute_request_async */
458         bool is_async = (or->request->end_io_data == or);
459
460         _osd_free_seg(or, &or->set_attr);
461         _osd_free_seg(or, &or->enc_get_attr);
462         _osd_free_seg(or, &or->get_attr);
463
464         if (rq) {
465                 if (rq->next_rq) {
466                         _put_request(rq->next_rq, is_async);
467                         rq->next_rq = NULL;
468                 }
469
470                 _put_request(rq, is_async);
471         }
472         _osd_request_free(or);
473 }
474 EXPORT_SYMBOL(osd_end_request);
475
476 int osd_execute_request(struct osd_request *or)
477 {
478         return or->async_error =
479                         blk_execute_rq(or->request->q, NULL, or->request, 0);
480 }
481 EXPORT_SYMBOL(osd_execute_request);
482
483 static void osd_request_async_done(struct request *req, int error)
484 {
485         struct osd_request *or = req->end_io_data;
486
487         or->async_error = error;
488
489         if (unlikely(error)) {
490                 OSD_DEBUG("osd_request_async_done error recieved %d "
491                           "errors 0x%x\n", error, req->errors);
492                 if (!req->errors) /* don't miss out on this one */
493                         req->errors = error;
494         }
495
496         if (or->async_done)
497                 or->async_done(or, or->async_private);
498         else
499                 osd_end_request(or);
500 }
501
502 int osd_execute_request_async(struct osd_request *or,
503         osd_req_done_fn *done, void *private)
504 {
505         or->request->end_io_data = or;
506         or->async_private = private;
507         or->async_done = done;
508
509         blk_execute_rq_nowait(or->request->q, NULL, or->request, 0,
510                               osd_request_async_done);
511         return 0;
512 }
513 EXPORT_SYMBOL(osd_execute_request_async);
514
515 u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
516 u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
517
518 static int _osd_realloc_seg(struct osd_request *or,
519         struct _osd_req_data_segment *seg, unsigned max_bytes)
520 {
521         void *buff;
522
523         if (seg->alloc_size >= max_bytes)
524                 return 0;
525
526         buff = krealloc(seg->buff, max_bytes, or->alloc_flags);
527         if (!buff) {
528                 OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes,
529                         seg->alloc_size);
530                 return -ENOMEM;
531         }
532
533         memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size);
534         seg->buff = buff;
535         seg->alloc_size = max_bytes;
536         return 0;
537 }
538
539 static int _alloc_set_attr_list(struct osd_request *or,
540         const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
541 {
542         unsigned total_bytes = add_bytes;
543
544         for (; nelem; --nelem, ++oa)
545                 total_bytes += _osd_req_alist_elem_size(or, oa->len);
546
547         OSD_DEBUG("total_bytes=%d\n", total_bytes);
548         return _osd_realloc_seg(or, &or->set_attr, total_bytes);
549 }
550
551 static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes)
552 {
553         OSD_DEBUG("total_bytes=%d\n", max_bytes);
554         return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes);
555 }
556
557 static int _alloc_get_attr_list(struct osd_request *or)
558 {
559         OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes);
560         return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes);
561 }
562
563 /*
564  * Common to all OSD commands
565  */
566
567 static void _osdv1_req_encode_common(struct osd_request *or,
568         __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
569 {
570         struct osdv1_cdb *ocdb = &or->cdb.v1;
571
572         /*
573          * For speed, the commands
574          *      OSD_ACT_PERFORM_SCSI_COMMAND    , V1 0x8F7E, V2 0x8F7C
575          *      OSD_ACT_SCSI_TASK_MANAGEMENT    , V1 0x8F7F, V2 0x8F7D
576          * are not supported here. Should pass zero and set after the call
577          */
578         act &= cpu_to_be16(~0x0080); /* V1 action code */
579
580         OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act));
581
582         ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
583         ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
584         ocdb->h.varlen_cdb.service_action = act;
585
586         ocdb->h.partition = cpu_to_be64(obj->partition);
587         ocdb->h.object = cpu_to_be64(obj->id);
588         ocdb->h.v1.length = cpu_to_be64(len);
589         ocdb->h.v1.start_address = cpu_to_be64(offset);
590 }
591
592 static void _osdv2_req_encode_common(struct osd_request *or,
593          __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
594 {
595         struct osdv2_cdb *ocdb = &or->cdb.v2;
596
597         OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act));
598
599         ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
600         ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
601         ocdb->h.varlen_cdb.service_action = act;
602
603         ocdb->h.partition = cpu_to_be64(obj->partition);
604         ocdb->h.object = cpu_to_be64(obj->id);
605         ocdb->h.v2.length = cpu_to_be64(len);
606         ocdb->h.v2.start_address = cpu_to_be64(offset);
607 }
608
609 static void _osd_req_encode_common(struct osd_request *or,
610         __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
611 {
612         if (osd_req_is_ver1(or))
613                 _osdv1_req_encode_common(or, act, obj, offset, len);
614         else
615                 _osdv2_req_encode_common(or, act, obj, offset, len);
616 }
617
618 /*
619  * Device commands
620  */
621 /*TODO: void osd_req_set_master_seed_xchg(struct osd_request *, ...); */
622 /*TODO: void osd_req_set_master_key(struct osd_request *, ...); */
623
624 void osd_req_format(struct osd_request *or, u64 tot_capacity)
625 {
626         _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
627                                 tot_capacity);
628 }
629 EXPORT_SYMBOL(osd_req_format);
630
631 int osd_req_list_dev_partitions(struct osd_request *or,
632         osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem)
633 {
634         return osd_req_list_partition_objects(or, 0, initial_id, list, nelem);
635 }
636 EXPORT_SYMBOL(osd_req_list_dev_partitions);
637
638 static void _osd_req_encode_flush(struct osd_request *or,
639         enum osd_options_flush_scope_values op)
640 {
641         struct osd_cdb_head *ocdb = osd_cdb_head(&or->cdb);
642
643         ocdb->command_specific_options = op;
644 }
645
646 void osd_req_flush_obsd(struct osd_request *or,
647         enum osd_options_flush_scope_values op)
648 {
649         _osd_req_encode_common(or, OSD_ACT_FLUSH_OSD, &osd_root_object, 0, 0);
650         _osd_req_encode_flush(or, op);
651 }
652 EXPORT_SYMBOL(osd_req_flush_obsd);
653
654 /*TODO: void osd_req_perform_scsi_command(struct osd_request *,
655         const u8 *cdb, ...); */
656 /*TODO: void osd_req_task_management(struct osd_request *, ...); */
657
658 /*
659  * Partition commands
660  */
661 static void _osd_req_encode_partition(struct osd_request *or,
662         __be16 act, osd_id partition)
663 {
664         struct osd_obj_id par = {
665                 .partition = partition,
666                 .id = 0,
667         };
668
669         _osd_req_encode_common(or, act, &par, 0, 0);
670 }
671
672 void osd_req_create_partition(struct osd_request *or, osd_id partition)
673 {
674         _osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition);
675 }
676 EXPORT_SYMBOL(osd_req_create_partition);
677
678 void osd_req_remove_partition(struct osd_request *or, osd_id partition)
679 {
680         _osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition);
681 }
682 EXPORT_SYMBOL(osd_req_remove_partition);
683
684 /*TODO: void osd_req_set_partition_key(struct osd_request *,
685         osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE],
686         u8 seed[OSD_CRYPTO_SEED_SIZE]); */
687
688 static int _osd_req_list_objects(struct osd_request *or,
689         __be16 action, const struct osd_obj_id *obj, osd_id initial_id,
690         struct osd_obj_id_list *list, unsigned nelem)
691 {
692         struct request_queue *q = osd_request_queue(or->osd_dev);
693         u64 len = nelem * sizeof(osd_id) + sizeof(*list);
694         struct bio *bio;
695
696         _osd_req_encode_common(or, action, obj, (u64)initial_id, len);
697
698         if (list->list_identifier)
699                 _osd_req_encode_olist(or, list);
700
701         WARN_ON(or->in.bio);
702         bio = bio_map_kern(q, list, len, or->alloc_flags);
703         if (IS_ERR(bio)) {
704                 OSD_ERR("!!! Failed to allocate list_objects BIO\n");
705                 return PTR_ERR(bio);
706         }
707
708         bio->bi_rw &= ~(1 << BIO_RW);
709         or->in.bio = bio;
710         or->in.total_bytes = bio->bi_size;
711         return 0;
712 }
713
714 int osd_req_list_partition_collections(struct osd_request *or,
715         osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
716         unsigned nelem)
717 {
718         struct osd_obj_id par = {
719                 .partition = partition,
720                 .id = 0,
721         };
722
723         return osd_req_list_collection_objects(or, &par, initial_id, list,
724                                                nelem);
725 }
726 EXPORT_SYMBOL(osd_req_list_partition_collections);
727
728 int osd_req_list_partition_objects(struct osd_request *or,
729         osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
730         unsigned nelem)
731 {
732         struct osd_obj_id par = {
733                 .partition = partition,
734                 .id = 0,
735         };
736
737         return _osd_req_list_objects(or, OSD_ACT_LIST, &par, initial_id, list,
738                                      nelem);
739 }
740 EXPORT_SYMBOL(osd_req_list_partition_objects);
741
742 void osd_req_flush_partition(struct osd_request *or,
743         osd_id partition, enum osd_options_flush_scope_values op)
744 {
745         _osd_req_encode_partition(or, OSD_ACT_FLUSH_PARTITION, partition);
746         _osd_req_encode_flush(or, op);
747 }
748 EXPORT_SYMBOL(osd_req_flush_partition);
749
750 /*
751  * Collection commands
752  */
753 /*TODO: void osd_req_create_collection(struct osd_request *,
754         const struct osd_obj_id *); */
755 /*TODO: void osd_req_remove_collection(struct osd_request *,
756         const struct osd_obj_id *); */
757
758 int osd_req_list_collection_objects(struct osd_request *or,
759         const struct osd_obj_id *obj, osd_id initial_id,
760         struct osd_obj_id_list *list, unsigned nelem)
761 {
762         return _osd_req_list_objects(or, OSD_ACT_LIST_COLLECTION, obj,
763                                      initial_id, list, nelem);
764 }
765 EXPORT_SYMBOL(osd_req_list_collection_objects);
766
767 /*TODO: void query(struct osd_request *, ...); V2 */
768
769 void osd_req_flush_collection(struct osd_request *or,
770         const struct osd_obj_id *obj, enum osd_options_flush_scope_values op)
771 {
772         _osd_req_encode_common(or, OSD_ACT_FLUSH_PARTITION, obj, 0, 0);
773         _osd_req_encode_flush(or, op);
774 }
775 EXPORT_SYMBOL(osd_req_flush_collection);
776
777 /*TODO: void get_member_attrs(struct osd_request *, ...); V2 */
778 /*TODO: void set_member_attrs(struct osd_request *, ...); V2 */
779
780 /*
781  * Object commands
782  */
783 void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj)
784 {
785         _osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0);
786 }
787 EXPORT_SYMBOL(osd_req_create_object);
788
789 void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj)
790 {
791         _osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0);
792 }
793 EXPORT_SYMBOL(osd_req_remove_object);
794
795
796 /*TODO: void osd_req_create_multi(struct osd_request *or,
797         struct osd_obj_id *first, struct osd_obj_id_list *list, unsigned nelem);
798 */
799
800 void osd_req_write(struct osd_request *or,
801         const struct osd_obj_id *obj, u64 offset,
802         struct bio *bio, u64 len)
803 {
804         _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len);
805         WARN_ON(or->out.bio || or->out.total_bytes);
806         WARN_ON(0 ==  bio_rw_flagged(bio, BIO_RW));
807         or->out.bio = bio;
808         or->out.total_bytes = len;
809 }
810 EXPORT_SYMBOL(osd_req_write);
811
812 int osd_req_write_kern(struct osd_request *or,
813         const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
814 {
815         struct request_queue *req_q = osd_request_queue(or->osd_dev);
816         struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
817
818         if (IS_ERR(bio))
819                 return PTR_ERR(bio);
820
821         bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
822         osd_req_write(or, obj, offset, bio, len);
823         return 0;
824 }
825 EXPORT_SYMBOL(osd_req_write_kern);
826
827 /*TODO: void osd_req_append(struct osd_request *,
828         const struct osd_obj_id *, struct bio *data_out); */
829 /*TODO: void osd_req_create_write(struct osd_request *,
830         const struct osd_obj_id *, struct bio *data_out, u64 offset); */
831 /*TODO: void osd_req_clear(struct osd_request *,
832         const struct osd_obj_id *, u64 offset, u64 len); */
833 /*TODO: void osd_req_punch(struct osd_request *,
834         const struct osd_obj_id *, u64 offset, u64 len); V2 */
835
836 void osd_req_flush_object(struct osd_request *or,
837         const struct osd_obj_id *obj, enum osd_options_flush_scope_values op,
838         /*V2*/ u64 offset, /*V2*/ u64 len)
839 {
840         if (unlikely(osd_req_is_ver1(or) && (offset || len))) {
841                 OSD_DEBUG("OSD Ver1 flush on specific range ignored\n");
842                 offset = 0;
843                 len = 0;
844         }
845
846         _osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len);
847         _osd_req_encode_flush(or, op);
848 }
849 EXPORT_SYMBOL(osd_req_flush_object);
850
851 void osd_req_read(struct osd_request *or,
852         const struct osd_obj_id *obj, u64 offset,
853         struct bio *bio, u64 len)
854 {
855         _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len);
856         WARN_ON(or->in.bio || or->in.total_bytes);
857         WARN_ON(1 == bio_rw_flagged(bio, BIO_RW));
858         or->in.bio = bio;
859         or->in.total_bytes = len;
860 }
861 EXPORT_SYMBOL(osd_req_read);
862
863 int osd_req_read_kern(struct osd_request *or,
864         const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
865 {
866         struct request_queue *req_q = osd_request_queue(or->osd_dev);
867         struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
868
869         if (IS_ERR(bio))
870                 return PTR_ERR(bio);
871
872         osd_req_read(or, obj, offset, bio, len);
873         return 0;
874 }
875 EXPORT_SYMBOL(osd_req_read_kern);
876
877 void osd_req_get_attributes(struct osd_request *or,
878         const struct osd_obj_id *obj)
879 {
880         _osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0);
881 }
882 EXPORT_SYMBOL(osd_req_get_attributes);
883
884 void osd_req_set_attributes(struct osd_request *or,
885         const struct osd_obj_id *obj)
886 {
887         _osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0);
888 }
889 EXPORT_SYMBOL(osd_req_set_attributes);
890
891 /*
892  * Attributes List-mode
893  */
894
895 int osd_req_add_set_attr_list(struct osd_request *or,
896         const struct osd_attr *oa, unsigned nelem)
897 {
898         unsigned total_bytes = or->set_attr.total_bytes;
899         void *attr_last;
900         int ret;
901
902         if (or->attributes_mode &&
903             or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
904                 WARN_ON(1);
905                 return -EINVAL;
906         }
907         or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
908
909         if (!total_bytes) { /* first-time: allocate and put list header */
910                 total_bytes = _osd_req_sizeof_alist_header(or);
911                 ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
912                 if (ret)
913                         return ret;
914                 _osd_req_set_alist_type(or, or->set_attr.buff,
915                                         OSD_ATTR_LIST_SET_RETRIEVE);
916         }
917         attr_last = or->set_attr.buff + total_bytes;
918
919         for (; nelem; --nelem) {
920                 unsigned elem_size = _osd_req_alist_elem_size(or, oa->len);
921
922                 total_bytes += elem_size;
923                 if (unlikely(or->set_attr.alloc_size < total_bytes)) {
924                         or->set_attr.total_bytes = total_bytes - elem_size;
925                         ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
926                         if (ret)
927                                 return ret;
928                         attr_last =
929                                 or->set_attr.buff + or->set_attr.total_bytes;
930                 }
931
932                 _osd_req_alist_elem_encode(or, attr_last, oa);
933
934                 attr_last += elem_size;
935                 ++oa;
936         }
937
938         or->set_attr.total_bytes = total_bytes;
939         return 0;
940 }
941 EXPORT_SYMBOL(osd_req_add_set_attr_list);
942
943 static int _req_append_segment(struct osd_request *or,
944         unsigned padding, struct _osd_req_data_segment *seg,
945         struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
946 {
947         void *pad_buff;
948         int ret;
949
950         if (padding) {
951                 /* check if we can just add it to last buffer */
952                 if (last_seg &&
953                     (padding <= last_seg->alloc_size - last_seg->total_bytes))
954                         pad_buff = last_seg->buff + last_seg->total_bytes;
955                 else
956                         pad_buff = io->pad_buff;
957
958                 ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding,
959                                        or->alloc_flags);
960                 if (ret)
961                         return ret;
962                 io->total_bytes += padding;
963         }
964
965         ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes,
966                                or->alloc_flags);
967         if (ret)
968                 return ret;
969
970         io->total_bytes += seg->total_bytes;
971         OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff,
972                   seg->total_bytes);
973         return 0;
974 }
975
976 static int _osd_req_finalize_set_attr_list(struct osd_request *or)
977 {
978         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
979         unsigned padding;
980         int ret;
981
982         if (!or->set_attr.total_bytes) {
983                 cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED;
984                 return 0;
985         }
986
987         cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes);
988         cdbh->attrs_list.set_attr_offset =
989                 osd_req_encode_offset(or, or->out.total_bytes, &padding);
990
991         ret = _req_append_segment(or, padding, &or->set_attr,
992                                   or->out.last_seg, &or->out);
993         if (ret)
994                 return ret;
995
996         or->out.last_seg = &or->set_attr;
997         return 0;
998 }
999
1000 int osd_req_add_get_attr_list(struct osd_request *or,
1001         const struct osd_attr *oa, unsigned nelem)
1002 {
1003         unsigned total_bytes = or->enc_get_attr.total_bytes;
1004         void *attr_last;
1005         int ret;
1006
1007         if (or->attributes_mode &&
1008             or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
1009                 WARN_ON(1);
1010                 return -EINVAL;
1011         }
1012         or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
1013
1014         /* first time calc data-in list header size */
1015         if (!or->get_attr.total_bytes)
1016                 or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or);
1017
1018         /* calc data-out info */
1019         if (!total_bytes) { /* first-time: allocate and put list header */
1020                 unsigned max_bytes;
1021
1022                 total_bytes = _osd_req_sizeof_alist_header(or);
1023                 max_bytes = total_bytes +
1024                         nelem * sizeof(struct osd_attributes_list_attrid);
1025                 ret = _alloc_get_attr_desc(or, max_bytes);
1026                 if (ret)
1027                         return ret;
1028
1029                 _osd_req_set_alist_type(or, or->enc_get_attr.buff,
1030                                         OSD_ATTR_LIST_GET);
1031         }
1032         attr_last = or->enc_get_attr.buff + total_bytes;
1033
1034         for (; nelem; --nelem) {
1035                 struct osd_attributes_list_attrid *attrid;
1036                 const unsigned cur_size = sizeof(*attrid);
1037
1038                 total_bytes += cur_size;
1039                 if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) {
1040                         or->enc_get_attr.total_bytes = total_bytes - cur_size;
1041                         ret = _alloc_get_attr_desc(or,
1042                                         total_bytes + nelem * sizeof(*attrid));
1043                         if (ret)
1044                                 return ret;
1045                         attr_last = or->enc_get_attr.buff +
1046                                 or->enc_get_attr.total_bytes;
1047                 }
1048
1049                 attrid = attr_last;
1050                 attrid->attr_page = cpu_to_be32(oa->attr_page);
1051                 attrid->attr_id = cpu_to_be32(oa->attr_id);
1052
1053                 attr_last += cur_size;
1054
1055                 /* calc data-in size */
1056                 or->get_attr.total_bytes +=
1057                         _osd_req_alist_elem_size(or, oa->len);
1058                 ++oa;
1059         }
1060
1061         or->enc_get_attr.total_bytes = total_bytes;
1062
1063         OSD_DEBUG(
1064                "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n",
1065                or->get_attr.total_bytes,
1066                or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or),
1067                or->enc_get_attr.total_bytes,
1068                (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or))
1069                         / sizeof(struct osd_attributes_list_attrid));
1070
1071         return 0;
1072 }
1073 EXPORT_SYMBOL(osd_req_add_get_attr_list);
1074
1075 static int _osd_req_finalize_get_attr_list(struct osd_request *or)
1076 {
1077         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1078         unsigned out_padding;
1079         unsigned in_padding;
1080         int ret;
1081
1082         if (!or->enc_get_attr.total_bytes) {
1083                 cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED;
1084                 cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED;
1085                 return 0;
1086         }
1087
1088         ret = _alloc_get_attr_list(or);
1089         if (ret)
1090                 return ret;
1091
1092         /* The out-going buffer info update */
1093         OSD_DEBUG("out-going\n");
1094         cdbh->attrs_list.get_attr_desc_bytes =
1095                 cpu_to_be32(or->enc_get_attr.total_bytes);
1096
1097         cdbh->attrs_list.get_attr_desc_offset =
1098                 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
1099
1100         ret = _req_append_segment(or, out_padding, &or->enc_get_attr,
1101                                   or->out.last_seg, &or->out);
1102         if (ret)
1103                 return ret;
1104         or->out.last_seg = &or->enc_get_attr;
1105
1106         /* The incoming buffer info update */
1107         OSD_DEBUG("in-coming\n");
1108         cdbh->attrs_list.get_attr_alloc_length =
1109                 cpu_to_be32(or->get_attr.total_bytes);
1110
1111         cdbh->attrs_list.get_attr_offset =
1112                 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
1113
1114         ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
1115                                   &or->in);
1116         if (ret)
1117                 return ret;
1118         or->in.last_seg = &or->get_attr;
1119
1120         return 0;
1121 }
1122
1123 int osd_req_decode_get_attr_list(struct osd_request *or,
1124         struct osd_attr *oa, int *nelem, void **iterator)
1125 {
1126         unsigned cur_bytes, returned_bytes;
1127         int n;
1128         const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or);
1129         void *cur_p;
1130
1131         if (!_osd_req_is_alist_type(or, or->get_attr.buff,
1132                                     OSD_ATTR_LIST_SET_RETRIEVE)) {
1133                 oa->attr_page = 0;
1134                 oa->attr_id = 0;
1135                 oa->val_ptr = NULL;
1136                 oa->len = 0;
1137                 *iterator = NULL;
1138                 return 0;
1139         }
1140
1141         if (*iterator) {
1142                 BUG_ON((*iterator < or->get_attr.buff) ||
1143                      (or->get_attr.buff + or->get_attr.alloc_size < *iterator));
1144                 cur_p = *iterator;
1145                 cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list;
1146                 returned_bytes = or->get_attr.total_bytes;
1147         } else { /* first time decode the list header */
1148                 cur_bytes = sizeof_attr_list;
1149                 returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) +
1150                                         sizeof_attr_list;
1151
1152                 cur_p = or->get_attr.buff + sizeof_attr_list;
1153
1154                 if (returned_bytes > or->get_attr.alloc_size) {
1155                         OSD_DEBUG("target report: space was not big enough! "
1156                                   "Allocate=%u Needed=%u\n",
1157                                   or->get_attr.alloc_size,
1158                                   returned_bytes + sizeof_attr_list);
1159
1160                         returned_bytes =
1161                                 or->get_attr.alloc_size - sizeof_attr_list;
1162                 }
1163                 or->get_attr.total_bytes = returned_bytes;
1164         }
1165
1166         for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) {
1167                 int inc = _osd_req_alist_elem_decode(or, cur_p, oa,
1168                                                  returned_bytes - cur_bytes);
1169
1170                 if (inc < 0) {
1171                         OSD_ERR("BAD FOOD from target. list not valid!"
1172                                 "c=%d r=%d n=%d\n",
1173                                 cur_bytes, returned_bytes, n);
1174                         oa->val_ptr = NULL;
1175                         cur_bytes = returned_bytes; /* break the caller loop */
1176                         break;
1177                 }
1178
1179                 cur_bytes += inc;
1180                 cur_p += inc;
1181                 ++oa;
1182         }
1183
1184         *iterator = (returned_bytes - cur_bytes) ? cur_p : NULL;
1185         *nelem = n;
1186         return returned_bytes - cur_bytes;
1187 }
1188 EXPORT_SYMBOL(osd_req_decode_get_attr_list);
1189
1190 /*
1191  * Attributes Page-mode
1192  */
1193
1194 int osd_req_add_get_attr_page(struct osd_request *or,
1195         u32 page_id, void *attar_page, unsigned max_page_len,
1196         const struct osd_attr *set_one_attr)
1197 {
1198         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1199
1200         if (or->attributes_mode &&
1201             or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
1202                 WARN_ON(1);
1203                 return -EINVAL;
1204         }
1205         or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE;
1206
1207         or->get_attr.buff = attar_page;
1208         or->get_attr.total_bytes = max_page_len;
1209
1210         or->set_attr.buff = set_one_attr->val_ptr;
1211         or->set_attr.total_bytes = set_one_attr->len;
1212
1213         cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
1214         cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
1215         /* ocdb->attrs_page.get_attr_offset; */
1216
1217         cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
1218         cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
1219         cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
1220         /* ocdb->attrs_page.set_attr_offset; */
1221         return 0;
1222 }
1223 EXPORT_SYMBOL(osd_req_add_get_attr_page);
1224
1225 static int _osd_req_finalize_attr_page(struct osd_request *or)
1226 {
1227         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1228         unsigned in_padding, out_padding;
1229         int ret;
1230
1231         /* returned page */
1232         cdbh->attrs_page.get_attr_offset =
1233                 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
1234
1235         ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
1236                                   &or->in);
1237         if (ret)
1238                 return ret;
1239
1240         /* set one value */
1241         cdbh->attrs_page.set_attr_offset =
1242                 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
1243
1244         ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
1245                                   &or->out);
1246         return ret;
1247 }
1248
1249 static inline void osd_sec_parms_set_out_offset(bool is_v1,
1250         struct osd_security_parameters *sec_parms, osd_cdb_offset offset)
1251 {
1252         if (is_v1)
1253                 sec_parms->v1.data_out_integrity_check_offset = offset;
1254         else
1255                 sec_parms->v2.data_out_integrity_check_offset = offset;
1256 }
1257
1258 static inline void osd_sec_parms_set_in_offset(bool is_v1,
1259         struct osd_security_parameters *sec_parms, osd_cdb_offset offset)
1260 {
1261         if (is_v1)
1262                 sec_parms->v1.data_in_integrity_check_offset = offset;
1263         else
1264                 sec_parms->v2.data_in_integrity_check_offset = offset;
1265 }
1266
1267 static int _osd_req_finalize_data_integrity(struct osd_request *or,
1268         bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key)
1269 {
1270         struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
1271         int ret;
1272
1273         if (!osd_is_sec_alldata(sec_parms))
1274                 return 0;
1275
1276         if (has_out) {
1277                 struct _osd_req_data_segment seg = {
1278                         .buff = &or->out_data_integ,
1279                         .total_bytes = sizeof(or->out_data_integ),
1280                 };
1281                 unsigned pad;
1282
1283                 or->out_data_integ.data_bytes = cpu_to_be64(out_data_bytes);
1284                 or->out_data_integ.set_attributes_bytes = cpu_to_be64(
1285                         or->set_attr.total_bytes);
1286                 or->out_data_integ.get_attributes_bytes = cpu_to_be64(
1287                         or->enc_get_attr.total_bytes);
1288
1289                 osd_sec_parms_set_out_offset(osd_req_is_ver1(or), sec_parms,
1290                         osd_req_encode_offset(or, or->out.total_bytes, &pad));
1291
1292                 ret = _req_append_segment(or, pad, &seg, or->out.last_seg,
1293                                           &or->out);
1294                 if (ret)
1295                         return ret;
1296                 or->out.last_seg = NULL;
1297
1298                 /* they are now all chained to request sign them all together */
1299                 osd_sec_sign_data(&or->out_data_integ, or->out.req->bio,
1300                                   cap_key);
1301         }
1302
1303         if (has_in) {
1304                 struct _osd_req_data_segment seg = {
1305                         .buff = &or->in_data_integ,
1306                         .total_bytes = sizeof(or->in_data_integ),
1307                 };
1308                 unsigned pad;
1309
1310                 osd_sec_parms_set_in_offset(osd_req_is_ver1(or), sec_parms,
1311                         osd_req_encode_offset(or, or->in.total_bytes, &pad));
1312
1313                 ret = _req_append_segment(or, pad, &seg, or->in.last_seg,
1314                                           &or->in);
1315                 if (ret)
1316                         return ret;
1317
1318                 or->in.last_seg = NULL;
1319         }
1320
1321         return 0;
1322 }
1323
1324 /*
1325  * osd_finalize_request and helpers
1326  */
1327 static struct request *_make_request(struct request_queue *q, bool has_write,
1328                               struct _osd_io_info *oii, gfp_t flags)
1329 {
1330         if (oii->bio)
1331                 return blk_make_request(q, oii->bio, flags);
1332         else {
1333                 struct request *req;
1334
1335                 req = blk_get_request(q, has_write ? WRITE : READ, flags);
1336                 if (unlikely(!req))
1337                         return ERR_PTR(-ENOMEM);
1338
1339                 return req;
1340         }
1341 }
1342
1343 static int _init_blk_request(struct osd_request *or,
1344         bool has_in, bool has_out)
1345 {
1346         gfp_t flags = or->alloc_flags;
1347         struct scsi_device *scsi_device = or->osd_dev->scsi_device;
1348         struct request_queue *q = scsi_device->request_queue;
1349         struct request *req;
1350         int ret;
1351
1352         req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags);
1353         if (IS_ERR(req)) {
1354                 ret = PTR_ERR(req);
1355                 goto out;
1356         }
1357
1358         or->request = req;
1359         req->cmd_type = REQ_TYPE_BLOCK_PC;
1360         req->cmd_flags |= REQ_QUIET;
1361
1362         req->timeout = or->timeout;
1363         req->retries = or->retries;
1364         req->sense = or->sense;
1365         req->sense_len = 0;
1366
1367         if (has_out) {
1368                 or->out.req = req;
1369                 if (has_in) {
1370                         /* allocate bidi request */
1371                         req = _make_request(q, false, &or->in, flags);
1372                         if (IS_ERR(req)) {
1373                                 OSD_DEBUG("blk_get_request for bidi failed\n");
1374                                 ret = PTR_ERR(req);
1375                                 goto out;
1376                         }
1377                         req->cmd_type = REQ_TYPE_BLOCK_PC;
1378                         or->in.req = or->request->next_rq = req;
1379                 }
1380         } else if (has_in)
1381                 or->in.req = req;
1382
1383         ret = 0;
1384 out:
1385         OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n",
1386                         or, has_in, has_out, ret, or->request);
1387         return ret;
1388 }
1389
1390 int osd_finalize_request(struct osd_request *or,
1391         u8 options, const void *cap, const u8 *cap_key)
1392 {
1393         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1394         bool has_in, has_out;
1395         u64 out_data_bytes = or->out.total_bytes;
1396         int ret;
1397
1398         if (options & OSD_REQ_FUA)
1399                 cdbh->options |= OSD_CDB_FUA;
1400
1401         if (options & OSD_REQ_DPO)
1402                 cdbh->options |= OSD_CDB_DPO;
1403
1404         if (options & OSD_REQ_BYPASS_TIMESTAMPS)
1405                 cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS;
1406
1407         osd_set_caps(&or->cdb, cap);
1408
1409         has_in = or->in.bio || or->get_attr.total_bytes;
1410         has_out = or->out.bio || or->set_attr.total_bytes ||
1411                 or->enc_get_attr.total_bytes;
1412
1413         ret = _init_blk_request(or, has_in, has_out);
1414         if (ret) {
1415                 OSD_DEBUG("_init_blk_request failed\n");
1416                 return ret;
1417         }
1418
1419         or->out.pad_buff = sg_out_pad_buffer;
1420         or->in.pad_buff = sg_in_pad_buffer;
1421
1422         if (!or->attributes_mode)
1423                 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
1424         cdbh->command_specific_options |= or->attributes_mode;
1425         if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
1426                 ret = _osd_req_finalize_attr_page(or);
1427         } else {
1428                 /* TODO: I think that for the GET_ATTR command these 2 should
1429                  * be reversed to keep them in execution order (for embeded
1430                  * targets with low memory footprint)
1431                  */
1432                 ret = _osd_req_finalize_set_attr_list(or);
1433                 if (ret) {
1434                         OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n");
1435                         return ret;
1436                 }
1437
1438                 ret = _osd_req_finalize_get_attr_list(or);
1439                 if (ret) {
1440                         OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n");
1441                         return ret;
1442                 }
1443         }
1444
1445         ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
1446                                                out_data_bytes, cap_key);
1447         if (ret)
1448                 return ret;
1449
1450         osd_sec_sign_cdb(&or->cdb, cap_key);
1451
1452         or->request->cmd = or->cdb.buff;
1453         or->request->cmd_len = _osd_req_cdb_len(or);
1454
1455         return 0;
1456 }
1457 EXPORT_SYMBOL(osd_finalize_request);
1458
1459 static bool _is_osd_security_code(int code)
1460 {
1461         return  (code == osd_security_audit_value_frozen) ||
1462                 (code == osd_security_working_key_frozen) ||
1463                 (code == osd_nonce_not_unique) ||
1464                 (code == osd_nonce_timestamp_out_of_range) ||
1465                 (code == osd_invalid_dataout_buffer_integrity_check_value);
1466 }
1467
1468 #define OSD_SENSE_PRINT1(fmt, a...) \
1469         do { \
1470                 if (__cur_sense_need_output) \
1471                         OSD_ERR(fmt, ##a); \
1472         } while (0)
1473
1474 #define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1("    " fmt, ##a)
1475
1476 int osd_req_decode_sense_full(struct osd_request *or,
1477         struct osd_sense_info *osi, bool silent,
1478         struct osd_obj_id *bad_obj_list __unused, int max_obj __unused,
1479         struct osd_attr *bad_attr_list, int max_attr)
1480 {
1481         int sense_len, original_sense_len;
1482         struct osd_sense_info local_osi;
1483         struct scsi_sense_descriptor_based *ssdb;
1484         void *cur_descriptor;
1485 #if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0)
1486         const bool __cur_sense_need_output = false;
1487 #else
1488         bool __cur_sense_need_output = !silent;
1489 #endif
1490         int ret;
1491
1492         if (likely(!or->request->errors)) {
1493                 osi->out_resid = 0;
1494                 osi->in_resid = 0;
1495                 return 0;
1496         }
1497
1498         osi = osi ? : &local_osi;
1499         memset(osi, 0, sizeof(*osi));
1500
1501         ssdb = or->request->sense;
1502         sense_len = or->request->sense_len;
1503         if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) {
1504                 OSD_ERR("Block-layer returned error(0x%x) but "
1505                         "sense_len(%u) || key(%d) is empty\n",
1506                         or->request->errors, sense_len, ssdb->sense_key);
1507                 goto analyze;
1508         }
1509
1510         if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
1511                 OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n",
1512                         ssdb->response_code, sense_len);
1513                 goto analyze;
1514         }
1515
1516         osi->key = ssdb->sense_key;
1517         osi->additional_code = be16_to_cpu(ssdb->additional_sense_code);
1518         original_sense_len = ssdb->additional_sense_length + 8;
1519
1520 #if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1)
1521         if (__cur_sense_need_output)
1522                 __cur_sense_need_output = (osi->key > scsi_sk_recovered_error);
1523 #endif
1524         OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) "
1525                         "additional_code=0x%x async_error=%d errors=0x%x\n",
1526                         osi->key, original_sense_len, sense_len,
1527                         osi->additional_code, or->async_error,
1528                         or->request->errors);
1529
1530         if (original_sense_len < sense_len)
1531                 sense_len = original_sense_len;
1532
1533         cur_descriptor = ssdb->ssd;
1534         sense_len -= sizeof(*ssdb);
1535         while (sense_len > 0) {
1536                 struct scsi_sense_descriptor *ssd = cur_descriptor;
1537                 int cur_len = ssd->additional_length + 2;
1538
1539                 sense_len -= cur_len;
1540
1541                 if (sense_len < 0)
1542                         break; /* sense was truncated */
1543
1544                 switch (ssd->descriptor_type) {
1545                 case scsi_sense_information:
1546                 case scsi_sense_command_specific_information:
1547                 {
1548                         struct scsi_sense_command_specific_data_descriptor
1549                                 *sscd = cur_descriptor;
1550
1551                         osi->command_info =
1552                                 get_unaligned_be64(&sscd->information) ;
1553                         OSD_SENSE_PRINT2(
1554                                 "command_specific_information 0x%llx \n",
1555                                 _LLU(osi->command_info));
1556                         break;
1557                 }
1558                 case scsi_sense_key_specific:
1559                 {
1560                         struct scsi_sense_key_specific_data_descriptor
1561                                 *ssks = cur_descriptor;
1562
1563                         osi->sense_info = get_unaligned_be16(&ssks->value);
1564                         OSD_SENSE_PRINT2(
1565                                 "sense_key_specific_information %u"
1566                                 "sksv_cd_bpv_bp (0x%x)\n",
1567                                 osi->sense_info, ssks->sksv_cd_bpv_bp);
1568                         break;
1569                 }
1570                 case osd_sense_object_identification:
1571                 { /*FIXME: Keep first not last, Store in array*/
1572                         struct osd_sense_identification_data_descriptor
1573                                 *osidd = cur_descriptor;
1574
1575                         osi->not_initiated_command_functions =
1576                                 le32_to_cpu(osidd->not_initiated_functions);
1577                         osi->completed_command_functions =
1578                                 le32_to_cpu(osidd->completed_functions);
1579                         osi->obj.partition = be64_to_cpu(osidd->partition_id);
1580                         osi->obj.id = be64_to_cpu(osidd->object_id);
1581                         OSD_SENSE_PRINT2(
1582                                 "object_identification pid=0x%llx oid=0x%llx\n",
1583                                 _LLU(osi->obj.partition), _LLU(osi->obj.id));
1584                         OSD_SENSE_PRINT2(
1585                                 "not_initiated_bits(%x) "
1586                                 "completed_command_bits(%x)\n",
1587                                 osi->not_initiated_command_functions,
1588                                 osi->completed_command_functions);
1589                         break;
1590                 }
1591                 case osd_sense_response_integrity_check:
1592                 {
1593                         struct osd_sense_response_integrity_check_descriptor
1594                                 *osricd = cur_descriptor;
1595                         const unsigned len =
1596                                           sizeof(osricd->integrity_check_value);
1597                         char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */
1598
1599                         hex_dump_to_buffer(osricd->integrity_check_value, len,
1600                                        32, 1, key_dump, sizeof(key_dump), true);
1601                         OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump);
1602                 }
1603                 case osd_sense_attribute_identification:
1604                 {
1605                         struct osd_sense_attributes_data_descriptor
1606                                 *osadd = cur_descriptor;
1607                         unsigned len = min(cur_len, sense_len);
1608                         struct osd_sense_attr *pattr = osadd->sense_attrs;
1609
1610                         while (len >= sizeof(*pattr)) {
1611                                 u32 attr_page = be32_to_cpu(pattr->attr_page);
1612                                 u32 attr_id = be32_to_cpu(pattr->attr_id);
1613
1614                                 if (!osi->attr.attr_page) {
1615                                         osi->attr.attr_page = attr_page;
1616                                         osi->attr.attr_id = attr_id;
1617                                 }
1618
1619                                 if (bad_attr_list && max_attr) {
1620                                         bad_attr_list->attr_page = attr_page;
1621                                         bad_attr_list->attr_id = attr_id;
1622                                         bad_attr_list++;
1623                                         max_attr--;
1624                                 }
1625
1626                                 len -= sizeof(*pattr);
1627                                 OSD_SENSE_PRINT2(
1628                                         "osd_sense_attribute_identification"
1629                                         "attr_page=0x%x attr_id=0x%x\n",
1630                                         attr_page, attr_id);
1631                         }
1632                 }
1633                 /*These are not legal for OSD*/
1634                 case scsi_sense_field_replaceable_unit:
1635                         OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n");
1636                         break;
1637                 case scsi_sense_stream_commands:
1638                         OSD_SENSE_PRINT2("scsi_sense_stream_commands\n");
1639                         break;
1640                 case scsi_sense_block_commands:
1641                         OSD_SENSE_PRINT2("scsi_sense_block_commands\n");
1642                         break;
1643                 case scsi_sense_ata_return:
1644                         OSD_SENSE_PRINT2("scsi_sense_ata_return\n");
1645                         break;
1646                 default:
1647                         if (ssd->descriptor_type <= scsi_sense_Reserved_last)
1648                                 OSD_SENSE_PRINT2(
1649                                         "scsi_sense Reserved descriptor (0x%x)",
1650                                         ssd->descriptor_type);
1651                         else
1652                                 OSD_SENSE_PRINT2(
1653                                         "scsi_sense Vendor descriptor (0x%x)",
1654                                         ssd->descriptor_type);
1655                 }
1656
1657                 cur_descriptor += cur_len;
1658         }
1659
1660 analyze:
1661         if (!osi->key) {
1662                 /* scsi sense is Empty, the request was never issued to target
1663                  * linux return code might tell us what happened.
1664                  */
1665                 if (or->async_error == -ENOMEM)
1666                         osi->osd_err_pri = OSD_ERR_PRI_RESOURCE;
1667                 else
1668                         osi->osd_err_pri = OSD_ERR_PRI_UNREACHABLE;
1669                 ret = or->async_error;
1670         } else if (osi->key <= scsi_sk_recovered_error) {
1671                 osi->osd_err_pri = 0;
1672                 ret = 0;
1673         } else if (osi->additional_code == scsi_invalid_field_in_cdb) {
1674                 if (osi->cdb_field_offset == OSD_CFO_STARTING_BYTE) {
1675                         osi->osd_err_pri = OSD_ERR_PRI_CLEAR_PAGES;
1676                         ret = -EFAULT; /* caller should recover from this */
1677                 } else if (osi->cdb_field_offset == OSD_CFO_OBJECT_ID) {
1678                         osi->osd_err_pri = OSD_ERR_PRI_NOT_FOUND;
1679                         ret = -ENOENT;
1680                 } else if (osi->cdb_field_offset == OSD_CFO_PERMISSIONS) {
1681                         osi->osd_err_pri = OSD_ERR_PRI_NO_ACCESS;
1682                         ret = -EACCES;
1683                 } else {
1684                         osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
1685                         ret = -EINVAL;
1686                 }
1687         } else if (osi->additional_code == osd_quota_error) {
1688                 osi->osd_err_pri = OSD_ERR_PRI_NO_SPACE;
1689                 ret = -ENOSPC;
1690         } else if (_is_osd_security_code(osi->additional_code)) {
1691                 osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
1692                 ret = -EINVAL;
1693         } else {
1694                 osi->osd_err_pri = OSD_ERR_PRI_EIO;
1695                 ret = -EIO;
1696         }
1697
1698         if (or->out.req)
1699                 osi->out_resid = or->out.req->resid_len ?: or->out.total_bytes;
1700         if (or->in.req)
1701                 osi->in_resid = or->in.req->resid_len ?: or->in.total_bytes;
1702
1703         return ret;
1704 }
1705 EXPORT_SYMBOL(osd_req_decode_sense_full);
1706
1707 /*
1708  * Implementation of osd_sec.h API
1709  * TODO: Move to a separate osd_sec.c file at a later stage.
1710  */
1711
1712 enum { OSD_SEC_CAP_V1_ALL_CAPS =
1713         OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE   |
1714         OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR |
1715         OSD_SEC_CAP_WRITE  | OSD_SEC_CAP_READ     | OSD_SEC_CAP_POL_SEC  |
1716         OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT
1717 };
1718
1719 enum { OSD_SEC_CAP_V2_ALL_CAPS =
1720         OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT
1721 };
1722
1723 void osd_sec_init_nosec_doall_caps(void *caps,
1724         const struct osd_obj_id *obj, bool is_collection, const bool is_v1)
1725 {
1726         struct osd_capability *cap = caps;
1727         u8 type;
1728         u8 descriptor_type;
1729
1730         if (likely(obj->id)) {
1731                 if (unlikely(is_collection)) {
1732                         type = OSD_SEC_OBJ_COLLECTION;
1733                         descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ :
1734                                                   OSD_SEC_OBJ_DESC_COL;
1735                 } else {
1736                         type = OSD_SEC_OBJ_USER;
1737                         descriptor_type = OSD_SEC_OBJ_DESC_OBJ;
1738                 }
1739                 WARN_ON(!obj->partition);
1740         } else {
1741                 type = obj->partition ? OSD_SEC_OBJ_PARTITION :
1742                                         OSD_SEC_OBJ_ROOT;
1743                 descriptor_type = OSD_SEC_OBJ_DESC_PAR;
1744         }
1745
1746         memset(cap, 0, sizeof(*cap));
1747
1748         cap->h.format = OSD_SEC_CAP_FORMAT_VER1;
1749         cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */
1750         cap->h.security_method = OSD_SEC_NOSEC;
1751 /*      cap->expiration_time;
1752         cap->AUDIT[30-10];
1753         cap->discriminator[42-30];
1754         cap->object_created_time; */
1755         cap->h.object_type = type;
1756         osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS);
1757         cap->h.object_descriptor_type = descriptor_type;
1758         cap->od.obj_desc.policy_access_tag = 0;
1759         cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition);
1760         cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id);
1761 }
1762 EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
1763
1764 /* FIXME: Extract version from caps pointer.
1765  *        Also Pete's target only supports caps from OSDv1 for now
1766  */
1767 void osd_set_caps(struct osd_cdb *cdb, const void *caps)
1768 {
1769         bool is_ver1 = true;
1770         /* NOTE: They start at same address */
1771         memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN);
1772 }
1773
1774 bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
1775 {
1776         return false;
1777 }
1778
1779 void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused)
1780 {
1781 }
1782
1783 void osd_sec_sign_data(void *data_integ __unused,
1784                        struct bio *bio __unused, const u8 *cap_key __unused)
1785 {
1786 }
1787
1788 /*
1789  * Declared in osd_protocol.h
1790  * 4.12.5 Data-In and Data-Out buffer offsets
1791  * byte offset = mantissa * (2^(exponent+8))
1792  * Returns the smallest allowed encoded offset that contains given @offset
1793  * The actual encoded offset returned is @offset + *@padding.
1794  */
1795 osd_cdb_offset __osd_encode_offset(
1796         u64 offset, unsigned *padding, int min_shift, int max_shift)
1797 {
1798         u64 try_offset = -1, mod, align;
1799         osd_cdb_offset be32_offset;
1800         int shift;
1801
1802         *padding = 0;
1803         if (!offset)
1804                 return 0;
1805
1806         for (shift = min_shift; shift < max_shift; ++shift) {
1807                 try_offset = offset >> shift;
1808                 if (try_offset < (1 << OSD_OFFSET_MAX_BITS))
1809                         break;
1810         }
1811
1812         BUG_ON(shift == max_shift);
1813
1814         align = 1 << shift;
1815         mod = offset & (align - 1);
1816         if (mod) {
1817                 *padding = align - mod;
1818                 try_offset += 1;
1819         }
1820
1821         try_offset |= ((shift - 8) & 0xf) << 28;
1822         be32_offset = cpu_to_be32((u32)try_offset);
1823
1824         OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n",
1825                  _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift,
1826                  be32_offset, *padding);
1827         return be32_offset;
1828 }