[SCSI] libosd: Fix blk_put_request locking again
[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)
436 {
437         /*
438          * If osd_finalize_request() was called but the request was not
439          * executed through the block layer, then we must release BIOs.
440          * TODO: Keep error code in or->async_error. Need to audit all
441          *       code paths.
442          */
443         if (unlikely(rq->bio))
444                 blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq));
445         else
446                 blk_put_request(rq);
447 }
448
449 void osd_end_request(struct osd_request *or)
450 {
451         struct request *rq = or->request;
452
453         _osd_free_seg(or, &or->set_attr);
454         _osd_free_seg(or, &or->enc_get_attr);
455         _osd_free_seg(or, &or->get_attr);
456
457         if (rq) {
458                 if (rq->next_rq) {
459                         _put_request(rq->next_rq);
460                         rq->next_rq = NULL;
461                 }
462
463                 _put_request(rq);
464         }
465         _osd_request_free(or);
466 }
467 EXPORT_SYMBOL(osd_end_request);
468
469 static void _set_error_resid(struct osd_request *or, struct request *req,
470                              int error)
471 {
472         or->async_error = error;
473         or->req_errors = req->errors ? : error;
474         or->sense_len = req->sense_len;
475         if (or->out.req)
476                 or->out.residual = or->out.req->resid_len;
477         if (or->in.req)
478                 or->in.residual = or->in.req->resid_len;
479 }
480
481 int osd_execute_request(struct osd_request *or)
482 {
483         int error = blk_execute_rq(or->request->q, NULL, or->request, 0);
484
485         _set_error_resid(or, or->request, error);
486         return error;
487 }
488 EXPORT_SYMBOL(osd_execute_request);
489
490 static void osd_request_async_done(struct request *req, int error)
491 {
492         struct osd_request *or = req->end_io_data;
493
494         _set_error_resid(or, req, error);
495         if (req->next_rq) {
496                 __blk_put_request(req->q, req->next_rq);
497                 req->next_rq = NULL;
498         }
499
500         __blk_put_request(req->q, req);
501         or->request = NULL;
502         or->in.req = NULL;
503         or->out.req = NULL;
504
505         if (or->async_done)
506                 or->async_done(or, or->async_private);
507         else
508                 osd_end_request(or);
509 }
510
511 int osd_execute_request_async(struct osd_request *or,
512         osd_req_done_fn *done, void *private)
513 {
514         or->request->end_io_data = or;
515         or->async_private = private;
516         or->async_done = done;
517
518         blk_execute_rq_nowait(or->request->q, NULL, or->request, 0,
519                               osd_request_async_done);
520         return 0;
521 }
522 EXPORT_SYMBOL(osd_execute_request_async);
523
524 u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
525 u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
526
527 static int _osd_realloc_seg(struct osd_request *or,
528         struct _osd_req_data_segment *seg, unsigned max_bytes)
529 {
530         void *buff;
531
532         if (seg->alloc_size >= max_bytes)
533                 return 0;
534
535         buff = krealloc(seg->buff, max_bytes, or->alloc_flags);
536         if (!buff) {
537                 OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes,
538                         seg->alloc_size);
539                 return -ENOMEM;
540         }
541
542         memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size);
543         seg->buff = buff;
544         seg->alloc_size = max_bytes;
545         return 0;
546 }
547
548 static int _alloc_set_attr_list(struct osd_request *or,
549         const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
550 {
551         unsigned total_bytes = add_bytes;
552
553         for (; nelem; --nelem, ++oa)
554                 total_bytes += _osd_req_alist_elem_size(or, oa->len);
555
556         OSD_DEBUG("total_bytes=%d\n", total_bytes);
557         return _osd_realloc_seg(or, &or->set_attr, total_bytes);
558 }
559
560 static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes)
561 {
562         OSD_DEBUG("total_bytes=%d\n", max_bytes);
563         return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes);
564 }
565
566 static int _alloc_get_attr_list(struct osd_request *or)
567 {
568         OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes);
569         return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes);
570 }
571
572 /*
573  * Common to all OSD commands
574  */
575
576 static void _osdv1_req_encode_common(struct osd_request *or,
577         __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
578 {
579         struct osdv1_cdb *ocdb = &or->cdb.v1;
580
581         /*
582          * For speed, the commands
583          *      OSD_ACT_PERFORM_SCSI_COMMAND    , V1 0x8F7E, V2 0x8F7C
584          *      OSD_ACT_SCSI_TASK_MANAGEMENT    , V1 0x8F7F, V2 0x8F7D
585          * are not supported here. Should pass zero and set after the call
586          */
587         act &= cpu_to_be16(~0x0080); /* V1 action code */
588
589         OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act));
590
591         ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
592         ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
593         ocdb->h.varlen_cdb.service_action = act;
594
595         ocdb->h.partition = cpu_to_be64(obj->partition);
596         ocdb->h.object = cpu_to_be64(obj->id);
597         ocdb->h.v1.length = cpu_to_be64(len);
598         ocdb->h.v1.start_address = cpu_to_be64(offset);
599 }
600
601 static void _osdv2_req_encode_common(struct osd_request *or,
602          __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
603 {
604         struct osdv2_cdb *ocdb = &or->cdb.v2;
605
606         OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act));
607
608         ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
609         ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
610         ocdb->h.varlen_cdb.service_action = act;
611
612         ocdb->h.partition = cpu_to_be64(obj->partition);
613         ocdb->h.object = cpu_to_be64(obj->id);
614         ocdb->h.v2.length = cpu_to_be64(len);
615         ocdb->h.v2.start_address = cpu_to_be64(offset);
616 }
617
618 static void _osd_req_encode_common(struct osd_request *or,
619         __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
620 {
621         if (osd_req_is_ver1(or))
622                 _osdv1_req_encode_common(or, act, obj, offset, len);
623         else
624                 _osdv2_req_encode_common(or, act, obj, offset, len);
625 }
626
627 /*
628  * Device commands
629  */
630 /*TODO: void osd_req_set_master_seed_xchg(struct osd_request *, ...); */
631 /*TODO: void osd_req_set_master_key(struct osd_request *, ...); */
632
633 void osd_req_format(struct osd_request *or, u64 tot_capacity)
634 {
635         _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
636                                 tot_capacity);
637 }
638 EXPORT_SYMBOL(osd_req_format);
639
640 int osd_req_list_dev_partitions(struct osd_request *or,
641         osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem)
642 {
643         return osd_req_list_partition_objects(or, 0, initial_id, list, nelem);
644 }
645 EXPORT_SYMBOL(osd_req_list_dev_partitions);
646
647 static void _osd_req_encode_flush(struct osd_request *or,
648         enum osd_options_flush_scope_values op)
649 {
650         struct osd_cdb_head *ocdb = osd_cdb_head(&or->cdb);
651
652         ocdb->command_specific_options = op;
653 }
654
655 void osd_req_flush_obsd(struct osd_request *or,
656         enum osd_options_flush_scope_values op)
657 {
658         _osd_req_encode_common(or, OSD_ACT_FLUSH_OSD, &osd_root_object, 0, 0);
659         _osd_req_encode_flush(or, op);
660 }
661 EXPORT_SYMBOL(osd_req_flush_obsd);
662
663 /*TODO: void osd_req_perform_scsi_command(struct osd_request *,
664         const u8 *cdb, ...); */
665 /*TODO: void osd_req_task_management(struct osd_request *, ...); */
666
667 /*
668  * Partition commands
669  */
670 static void _osd_req_encode_partition(struct osd_request *or,
671         __be16 act, osd_id partition)
672 {
673         struct osd_obj_id par = {
674                 .partition = partition,
675                 .id = 0,
676         };
677
678         _osd_req_encode_common(or, act, &par, 0, 0);
679 }
680
681 void osd_req_create_partition(struct osd_request *or, osd_id partition)
682 {
683         _osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition);
684 }
685 EXPORT_SYMBOL(osd_req_create_partition);
686
687 void osd_req_remove_partition(struct osd_request *or, osd_id partition)
688 {
689         _osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition);
690 }
691 EXPORT_SYMBOL(osd_req_remove_partition);
692
693 /*TODO: void osd_req_set_partition_key(struct osd_request *,
694         osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE],
695         u8 seed[OSD_CRYPTO_SEED_SIZE]); */
696
697 static int _osd_req_list_objects(struct osd_request *or,
698         __be16 action, const struct osd_obj_id *obj, osd_id initial_id,
699         struct osd_obj_id_list *list, unsigned nelem)
700 {
701         struct request_queue *q = osd_request_queue(or->osd_dev);
702         u64 len = nelem * sizeof(osd_id) + sizeof(*list);
703         struct bio *bio;
704
705         _osd_req_encode_common(or, action, obj, (u64)initial_id, len);
706
707         if (list->list_identifier)
708                 _osd_req_encode_olist(or, list);
709
710         WARN_ON(or->in.bio);
711         bio = bio_map_kern(q, list, len, or->alloc_flags);
712         if (IS_ERR(bio)) {
713                 OSD_ERR("!!! Failed to allocate list_objects BIO\n");
714                 return PTR_ERR(bio);
715         }
716
717         bio->bi_rw &= ~(1 << BIO_RW);
718         or->in.bio = bio;
719         or->in.total_bytes = bio->bi_size;
720         return 0;
721 }
722
723 int osd_req_list_partition_collections(struct osd_request *or,
724         osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
725         unsigned nelem)
726 {
727         struct osd_obj_id par = {
728                 .partition = partition,
729                 .id = 0,
730         };
731
732         return osd_req_list_collection_objects(or, &par, initial_id, list,
733                                                nelem);
734 }
735 EXPORT_SYMBOL(osd_req_list_partition_collections);
736
737 int osd_req_list_partition_objects(struct osd_request *or,
738         osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
739         unsigned nelem)
740 {
741         struct osd_obj_id par = {
742                 .partition = partition,
743                 .id = 0,
744         };
745
746         return _osd_req_list_objects(or, OSD_ACT_LIST, &par, initial_id, list,
747                                      nelem);
748 }
749 EXPORT_SYMBOL(osd_req_list_partition_objects);
750
751 void osd_req_flush_partition(struct osd_request *or,
752         osd_id partition, enum osd_options_flush_scope_values op)
753 {
754         _osd_req_encode_partition(or, OSD_ACT_FLUSH_PARTITION, partition);
755         _osd_req_encode_flush(or, op);
756 }
757 EXPORT_SYMBOL(osd_req_flush_partition);
758
759 /*
760  * Collection commands
761  */
762 /*TODO: void osd_req_create_collection(struct osd_request *,
763         const struct osd_obj_id *); */
764 /*TODO: void osd_req_remove_collection(struct osd_request *,
765         const struct osd_obj_id *); */
766
767 int osd_req_list_collection_objects(struct osd_request *or,
768         const struct osd_obj_id *obj, osd_id initial_id,
769         struct osd_obj_id_list *list, unsigned nelem)
770 {
771         return _osd_req_list_objects(or, OSD_ACT_LIST_COLLECTION, obj,
772                                      initial_id, list, nelem);
773 }
774 EXPORT_SYMBOL(osd_req_list_collection_objects);
775
776 /*TODO: void query(struct osd_request *, ...); V2 */
777
778 void osd_req_flush_collection(struct osd_request *or,
779         const struct osd_obj_id *obj, enum osd_options_flush_scope_values op)
780 {
781         _osd_req_encode_common(or, OSD_ACT_FLUSH_PARTITION, obj, 0, 0);
782         _osd_req_encode_flush(or, op);
783 }
784 EXPORT_SYMBOL(osd_req_flush_collection);
785
786 /*TODO: void get_member_attrs(struct osd_request *, ...); V2 */
787 /*TODO: void set_member_attrs(struct osd_request *, ...); V2 */
788
789 /*
790  * Object commands
791  */
792 void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj)
793 {
794         _osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0);
795 }
796 EXPORT_SYMBOL(osd_req_create_object);
797
798 void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj)
799 {
800         _osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0);
801 }
802 EXPORT_SYMBOL(osd_req_remove_object);
803
804
805 /*TODO: void osd_req_create_multi(struct osd_request *or,
806         struct osd_obj_id *first, struct osd_obj_id_list *list, unsigned nelem);
807 */
808
809 void osd_req_write(struct osd_request *or,
810         const struct osd_obj_id *obj, u64 offset,
811         struct bio *bio, u64 len)
812 {
813         _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len);
814         WARN_ON(or->out.bio || or->out.total_bytes);
815         WARN_ON(0 ==  bio_rw_flagged(bio, BIO_RW));
816         or->out.bio = bio;
817         or->out.total_bytes = len;
818 }
819 EXPORT_SYMBOL(osd_req_write);
820
821 int osd_req_write_kern(struct osd_request *or,
822         const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
823 {
824         struct request_queue *req_q = osd_request_queue(or->osd_dev);
825         struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
826
827         if (IS_ERR(bio))
828                 return PTR_ERR(bio);
829
830         bio->bi_rw |= (1 << BIO_RW); /* FIXME: bio_set_dir() */
831         osd_req_write(or, obj, offset, bio, len);
832         return 0;
833 }
834 EXPORT_SYMBOL(osd_req_write_kern);
835
836 /*TODO: void osd_req_append(struct osd_request *,
837         const struct osd_obj_id *, struct bio *data_out); */
838 /*TODO: void osd_req_create_write(struct osd_request *,
839         const struct osd_obj_id *, struct bio *data_out, u64 offset); */
840 /*TODO: void osd_req_clear(struct osd_request *,
841         const struct osd_obj_id *, u64 offset, u64 len); */
842 /*TODO: void osd_req_punch(struct osd_request *,
843         const struct osd_obj_id *, u64 offset, u64 len); V2 */
844
845 void osd_req_flush_object(struct osd_request *or,
846         const struct osd_obj_id *obj, enum osd_options_flush_scope_values op,
847         /*V2*/ u64 offset, /*V2*/ u64 len)
848 {
849         if (unlikely(osd_req_is_ver1(or) && (offset || len))) {
850                 OSD_DEBUG("OSD Ver1 flush on specific range ignored\n");
851                 offset = 0;
852                 len = 0;
853         }
854
855         _osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len);
856         _osd_req_encode_flush(or, op);
857 }
858 EXPORT_SYMBOL(osd_req_flush_object);
859
860 void osd_req_read(struct osd_request *or,
861         const struct osd_obj_id *obj, u64 offset,
862         struct bio *bio, u64 len)
863 {
864         _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len);
865         WARN_ON(or->in.bio || or->in.total_bytes);
866         WARN_ON(1 == bio_rw_flagged(bio, BIO_RW));
867         or->in.bio = bio;
868         or->in.total_bytes = len;
869 }
870 EXPORT_SYMBOL(osd_req_read);
871
872 int osd_req_read_kern(struct osd_request *or,
873         const struct osd_obj_id *obj, u64 offset, void* buff, u64 len)
874 {
875         struct request_queue *req_q = osd_request_queue(or->osd_dev);
876         struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL);
877
878         if (IS_ERR(bio))
879                 return PTR_ERR(bio);
880
881         osd_req_read(or, obj, offset, bio, len);
882         return 0;
883 }
884 EXPORT_SYMBOL(osd_req_read_kern);
885
886 void osd_req_get_attributes(struct osd_request *or,
887         const struct osd_obj_id *obj)
888 {
889         _osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0);
890 }
891 EXPORT_SYMBOL(osd_req_get_attributes);
892
893 void osd_req_set_attributes(struct osd_request *or,
894         const struct osd_obj_id *obj)
895 {
896         _osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0);
897 }
898 EXPORT_SYMBOL(osd_req_set_attributes);
899
900 /*
901  * Attributes List-mode
902  */
903
904 int osd_req_add_set_attr_list(struct osd_request *or,
905         const struct osd_attr *oa, unsigned nelem)
906 {
907         unsigned total_bytes = or->set_attr.total_bytes;
908         void *attr_last;
909         int ret;
910
911         if (or->attributes_mode &&
912             or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
913                 WARN_ON(1);
914                 return -EINVAL;
915         }
916         or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
917
918         if (!total_bytes) { /* first-time: allocate and put list header */
919                 total_bytes = _osd_req_sizeof_alist_header(or);
920                 ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
921                 if (ret)
922                         return ret;
923                 _osd_req_set_alist_type(or, or->set_attr.buff,
924                                         OSD_ATTR_LIST_SET_RETRIEVE);
925         }
926         attr_last = or->set_attr.buff + total_bytes;
927
928         for (; nelem; --nelem) {
929                 unsigned elem_size = _osd_req_alist_elem_size(or, oa->len);
930
931                 total_bytes += elem_size;
932                 if (unlikely(or->set_attr.alloc_size < total_bytes)) {
933                         or->set_attr.total_bytes = total_bytes - elem_size;
934                         ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
935                         if (ret)
936                                 return ret;
937                         attr_last =
938                                 or->set_attr.buff + or->set_attr.total_bytes;
939                 }
940
941                 _osd_req_alist_elem_encode(or, attr_last, oa);
942
943                 attr_last += elem_size;
944                 ++oa;
945         }
946
947         or->set_attr.total_bytes = total_bytes;
948         return 0;
949 }
950 EXPORT_SYMBOL(osd_req_add_set_attr_list);
951
952 static int _req_append_segment(struct osd_request *or,
953         unsigned padding, struct _osd_req_data_segment *seg,
954         struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
955 {
956         void *pad_buff;
957         int ret;
958
959         if (padding) {
960                 /* check if we can just add it to last buffer */
961                 if (last_seg &&
962                     (padding <= last_seg->alloc_size - last_seg->total_bytes))
963                         pad_buff = last_seg->buff + last_seg->total_bytes;
964                 else
965                         pad_buff = io->pad_buff;
966
967                 ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding,
968                                        or->alloc_flags);
969                 if (ret)
970                         return ret;
971                 io->total_bytes += padding;
972         }
973
974         ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes,
975                                or->alloc_flags);
976         if (ret)
977                 return ret;
978
979         io->total_bytes += seg->total_bytes;
980         OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff,
981                   seg->total_bytes);
982         return 0;
983 }
984
985 static int _osd_req_finalize_set_attr_list(struct osd_request *or)
986 {
987         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
988         unsigned padding;
989         int ret;
990
991         if (!or->set_attr.total_bytes) {
992                 cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED;
993                 return 0;
994         }
995
996         cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes);
997         cdbh->attrs_list.set_attr_offset =
998                 osd_req_encode_offset(or, or->out.total_bytes, &padding);
999
1000         ret = _req_append_segment(or, padding, &or->set_attr,
1001                                   or->out.last_seg, &or->out);
1002         if (ret)
1003                 return ret;
1004
1005         or->out.last_seg = &or->set_attr;
1006         return 0;
1007 }
1008
1009 int osd_req_add_get_attr_list(struct osd_request *or,
1010         const struct osd_attr *oa, unsigned nelem)
1011 {
1012         unsigned total_bytes = or->enc_get_attr.total_bytes;
1013         void *attr_last;
1014         int ret;
1015
1016         if (or->attributes_mode &&
1017             or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
1018                 WARN_ON(1);
1019                 return -EINVAL;
1020         }
1021         or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
1022
1023         /* first time calc data-in list header size */
1024         if (!or->get_attr.total_bytes)
1025                 or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or);
1026
1027         /* calc data-out info */
1028         if (!total_bytes) { /* first-time: allocate and put list header */
1029                 unsigned max_bytes;
1030
1031                 total_bytes = _osd_req_sizeof_alist_header(or);
1032                 max_bytes = total_bytes +
1033                         nelem * sizeof(struct osd_attributes_list_attrid);
1034                 ret = _alloc_get_attr_desc(or, max_bytes);
1035                 if (ret)
1036                         return ret;
1037
1038                 _osd_req_set_alist_type(or, or->enc_get_attr.buff,
1039                                         OSD_ATTR_LIST_GET);
1040         }
1041         attr_last = or->enc_get_attr.buff + total_bytes;
1042
1043         for (; nelem; --nelem) {
1044                 struct osd_attributes_list_attrid *attrid;
1045                 const unsigned cur_size = sizeof(*attrid);
1046
1047                 total_bytes += cur_size;
1048                 if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) {
1049                         or->enc_get_attr.total_bytes = total_bytes - cur_size;
1050                         ret = _alloc_get_attr_desc(or,
1051                                         total_bytes + nelem * sizeof(*attrid));
1052                         if (ret)
1053                                 return ret;
1054                         attr_last = or->enc_get_attr.buff +
1055                                 or->enc_get_attr.total_bytes;
1056                 }
1057
1058                 attrid = attr_last;
1059                 attrid->attr_page = cpu_to_be32(oa->attr_page);
1060                 attrid->attr_id = cpu_to_be32(oa->attr_id);
1061
1062                 attr_last += cur_size;
1063
1064                 /* calc data-in size */
1065                 or->get_attr.total_bytes +=
1066                         _osd_req_alist_elem_size(or, oa->len);
1067                 ++oa;
1068         }
1069
1070         or->enc_get_attr.total_bytes = total_bytes;
1071
1072         OSD_DEBUG(
1073                "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n",
1074                or->get_attr.total_bytes,
1075                or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or),
1076                or->enc_get_attr.total_bytes,
1077                (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or))
1078                         / sizeof(struct osd_attributes_list_attrid));
1079
1080         return 0;
1081 }
1082 EXPORT_SYMBOL(osd_req_add_get_attr_list);
1083
1084 static int _osd_req_finalize_get_attr_list(struct osd_request *or)
1085 {
1086         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1087         unsigned out_padding;
1088         unsigned in_padding;
1089         int ret;
1090
1091         if (!or->enc_get_attr.total_bytes) {
1092                 cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED;
1093                 cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED;
1094                 return 0;
1095         }
1096
1097         ret = _alloc_get_attr_list(or);
1098         if (ret)
1099                 return ret;
1100
1101         /* The out-going buffer info update */
1102         OSD_DEBUG("out-going\n");
1103         cdbh->attrs_list.get_attr_desc_bytes =
1104                 cpu_to_be32(or->enc_get_attr.total_bytes);
1105
1106         cdbh->attrs_list.get_attr_desc_offset =
1107                 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
1108
1109         ret = _req_append_segment(or, out_padding, &or->enc_get_attr,
1110                                   or->out.last_seg, &or->out);
1111         if (ret)
1112                 return ret;
1113         or->out.last_seg = &or->enc_get_attr;
1114
1115         /* The incoming buffer info update */
1116         OSD_DEBUG("in-coming\n");
1117         cdbh->attrs_list.get_attr_alloc_length =
1118                 cpu_to_be32(or->get_attr.total_bytes);
1119
1120         cdbh->attrs_list.get_attr_offset =
1121                 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
1122
1123         ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
1124                                   &or->in);
1125         if (ret)
1126                 return ret;
1127         or->in.last_seg = &or->get_attr;
1128
1129         return 0;
1130 }
1131
1132 int osd_req_decode_get_attr_list(struct osd_request *or,
1133         struct osd_attr *oa, int *nelem, void **iterator)
1134 {
1135         unsigned cur_bytes, returned_bytes;
1136         int n;
1137         const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or);
1138         void *cur_p;
1139
1140         if (!_osd_req_is_alist_type(or, or->get_attr.buff,
1141                                     OSD_ATTR_LIST_SET_RETRIEVE)) {
1142                 oa->attr_page = 0;
1143                 oa->attr_id = 0;
1144                 oa->val_ptr = NULL;
1145                 oa->len = 0;
1146                 *iterator = NULL;
1147                 return 0;
1148         }
1149
1150         if (*iterator) {
1151                 BUG_ON((*iterator < or->get_attr.buff) ||
1152                      (or->get_attr.buff + or->get_attr.alloc_size < *iterator));
1153                 cur_p = *iterator;
1154                 cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list;
1155                 returned_bytes = or->get_attr.total_bytes;
1156         } else { /* first time decode the list header */
1157                 cur_bytes = sizeof_attr_list;
1158                 returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) +
1159                                         sizeof_attr_list;
1160
1161                 cur_p = or->get_attr.buff + sizeof_attr_list;
1162
1163                 if (returned_bytes > or->get_attr.alloc_size) {
1164                         OSD_DEBUG("target report: space was not big enough! "
1165                                   "Allocate=%u Needed=%u\n",
1166                                   or->get_attr.alloc_size,
1167                                   returned_bytes + sizeof_attr_list);
1168
1169                         returned_bytes =
1170                                 or->get_attr.alloc_size - sizeof_attr_list;
1171                 }
1172                 or->get_attr.total_bytes = returned_bytes;
1173         }
1174
1175         for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) {
1176                 int inc = _osd_req_alist_elem_decode(or, cur_p, oa,
1177                                                  returned_bytes - cur_bytes);
1178
1179                 if (inc < 0) {
1180                         OSD_ERR("BAD FOOD from target. list not valid!"
1181                                 "c=%d r=%d n=%d\n",
1182                                 cur_bytes, returned_bytes, n);
1183                         oa->val_ptr = NULL;
1184                         cur_bytes = returned_bytes; /* break the caller loop */
1185                         break;
1186                 }
1187
1188                 cur_bytes += inc;
1189                 cur_p += inc;
1190                 ++oa;
1191         }
1192
1193         *iterator = (returned_bytes - cur_bytes) ? cur_p : NULL;
1194         *nelem = n;
1195         return returned_bytes - cur_bytes;
1196 }
1197 EXPORT_SYMBOL(osd_req_decode_get_attr_list);
1198
1199 /*
1200  * Attributes Page-mode
1201  */
1202
1203 int osd_req_add_get_attr_page(struct osd_request *or,
1204         u32 page_id, void *attar_page, unsigned max_page_len,
1205         const struct osd_attr *set_one_attr)
1206 {
1207         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1208
1209         if (or->attributes_mode &&
1210             or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
1211                 WARN_ON(1);
1212                 return -EINVAL;
1213         }
1214         or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE;
1215
1216         or->get_attr.buff = attar_page;
1217         or->get_attr.total_bytes = max_page_len;
1218
1219         or->set_attr.buff = set_one_attr->val_ptr;
1220         or->set_attr.total_bytes = set_one_attr->len;
1221
1222         cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
1223         cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
1224         /* ocdb->attrs_page.get_attr_offset; */
1225
1226         cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
1227         cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
1228         cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
1229         /* ocdb->attrs_page.set_attr_offset; */
1230         return 0;
1231 }
1232 EXPORT_SYMBOL(osd_req_add_get_attr_page);
1233
1234 static int _osd_req_finalize_attr_page(struct osd_request *or)
1235 {
1236         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1237         unsigned in_padding, out_padding;
1238         int ret;
1239
1240         /* returned page */
1241         cdbh->attrs_page.get_attr_offset =
1242                 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
1243
1244         ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
1245                                   &or->in);
1246         if (ret)
1247                 return ret;
1248
1249         /* set one value */
1250         cdbh->attrs_page.set_attr_offset =
1251                 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
1252
1253         ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
1254                                   &or->out);
1255         return ret;
1256 }
1257
1258 static inline void osd_sec_parms_set_out_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_out_integrity_check_offset = offset;
1263         else
1264                 sec_parms->v2.data_out_integrity_check_offset = offset;
1265 }
1266
1267 static inline void osd_sec_parms_set_in_offset(bool is_v1,
1268         struct osd_security_parameters *sec_parms, osd_cdb_offset offset)
1269 {
1270         if (is_v1)
1271                 sec_parms->v1.data_in_integrity_check_offset = offset;
1272         else
1273                 sec_parms->v2.data_in_integrity_check_offset = offset;
1274 }
1275
1276 static int _osd_req_finalize_data_integrity(struct osd_request *or,
1277         bool has_in, bool has_out, u64 out_data_bytes, const u8 *cap_key)
1278 {
1279         struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
1280         int ret;
1281
1282         if (!osd_is_sec_alldata(sec_parms))
1283                 return 0;
1284
1285         if (has_out) {
1286                 struct _osd_req_data_segment seg = {
1287                         .buff = &or->out_data_integ,
1288                         .total_bytes = sizeof(or->out_data_integ),
1289                 };
1290                 unsigned pad;
1291
1292                 or->out_data_integ.data_bytes = cpu_to_be64(out_data_bytes);
1293                 or->out_data_integ.set_attributes_bytes = cpu_to_be64(
1294                         or->set_attr.total_bytes);
1295                 or->out_data_integ.get_attributes_bytes = cpu_to_be64(
1296                         or->enc_get_attr.total_bytes);
1297
1298                 osd_sec_parms_set_out_offset(osd_req_is_ver1(or), sec_parms,
1299                         osd_req_encode_offset(or, or->out.total_bytes, &pad));
1300
1301                 ret = _req_append_segment(or, pad, &seg, or->out.last_seg,
1302                                           &or->out);
1303                 if (ret)
1304                         return ret;
1305                 or->out.last_seg = NULL;
1306
1307                 /* they are now all chained to request sign them all together */
1308                 osd_sec_sign_data(&or->out_data_integ, or->out.req->bio,
1309                                   cap_key);
1310         }
1311
1312         if (has_in) {
1313                 struct _osd_req_data_segment seg = {
1314                         .buff = &or->in_data_integ,
1315                         .total_bytes = sizeof(or->in_data_integ),
1316                 };
1317                 unsigned pad;
1318
1319                 osd_sec_parms_set_in_offset(osd_req_is_ver1(or), sec_parms,
1320                         osd_req_encode_offset(or, or->in.total_bytes, &pad));
1321
1322                 ret = _req_append_segment(or, pad, &seg, or->in.last_seg,
1323                                           &or->in);
1324                 if (ret)
1325                         return ret;
1326
1327                 or->in.last_seg = NULL;
1328         }
1329
1330         return 0;
1331 }
1332
1333 /*
1334  * osd_finalize_request and helpers
1335  */
1336 static struct request *_make_request(struct request_queue *q, bool has_write,
1337                               struct _osd_io_info *oii, gfp_t flags)
1338 {
1339         if (oii->bio)
1340                 return blk_make_request(q, oii->bio, flags);
1341         else {
1342                 struct request *req;
1343
1344                 req = blk_get_request(q, has_write ? WRITE : READ, flags);
1345                 if (unlikely(!req))
1346                         return ERR_PTR(-ENOMEM);
1347
1348                 return req;
1349         }
1350 }
1351
1352 static int _init_blk_request(struct osd_request *or,
1353         bool has_in, bool has_out)
1354 {
1355         gfp_t flags = or->alloc_flags;
1356         struct scsi_device *scsi_device = or->osd_dev->scsi_device;
1357         struct request_queue *q = scsi_device->request_queue;
1358         struct request *req;
1359         int ret;
1360
1361         req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags);
1362         if (IS_ERR(req)) {
1363                 ret = PTR_ERR(req);
1364                 goto out;
1365         }
1366
1367         or->request = req;
1368         req->cmd_type = REQ_TYPE_BLOCK_PC;
1369         req->cmd_flags |= REQ_QUIET;
1370
1371         req->timeout = or->timeout;
1372         req->retries = or->retries;
1373         req->sense = or->sense;
1374         req->sense_len = 0;
1375
1376         if (has_out) {
1377                 or->out.req = req;
1378                 if (has_in) {
1379                         /* allocate bidi request */
1380                         req = _make_request(q, false, &or->in, flags);
1381                         if (IS_ERR(req)) {
1382                                 OSD_DEBUG("blk_get_request for bidi failed\n");
1383                                 ret = PTR_ERR(req);
1384                                 goto out;
1385                         }
1386                         req->cmd_type = REQ_TYPE_BLOCK_PC;
1387                         or->in.req = or->request->next_rq = req;
1388                 }
1389         } else if (has_in)
1390                 or->in.req = req;
1391
1392         ret = 0;
1393 out:
1394         OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n",
1395                         or, has_in, has_out, ret, or->request);
1396         return ret;
1397 }
1398
1399 int osd_finalize_request(struct osd_request *or,
1400         u8 options, const void *cap, const u8 *cap_key)
1401 {
1402         struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
1403         bool has_in, has_out;
1404         u64 out_data_bytes = or->out.total_bytes;
1405         int ret;
1406
1407         if (options & OSD_REQ_FUA)
1408                 cdbh->options |= OSD_CDB_FUA;
1409
1410         if (options & OSD_REQ_DPO)
1411                 cdbh->options |= OSD_CDB_DPO;
1412
1413         if (options & OSD_REQ_BYPASS_TIMESTAMPS)
1414                 cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS;
1415
1416         osd_set_caps(&or->cdb, cap);
1417
1418         has_in = or->in.bio || or->get_attr.total_bytes;
1419         has_out = or->out.bio || or->set_attr.total_bytes ||
1420                 or->enc_get_attr.total_bytes;
1421
1422         ret = _init_blk_request(or, has_in, has_out);
1423         if (ret) {
1424                 OSD_DEBUG("_init_blk_request failed\n");
1425                 return ret;
1426         }
1427
1428         or->out.pad_buff = sg_out_pad_buffer;
1429         or->in.pad_buff = sg_in_pad_buffer;
1430
1431         if (!or->attributes_mode)
1432                 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
1433         cdbh->command_specific_options |= or->attributes_mode;
1434         if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
1435                 ret = _osd_req_finalize_attr_page(or);
1436         } else {
1437                 /* TODO: I think that for the GET_ATTR command these 2 should
1438                  * be reversed to keep them in execution order (for embeded
1439                  * targets with low memory footprint)
1440                  */
1441                 ret = _osd_req_finalize_set_attr_list(or);
1442                 if (ret) {
1443                         OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n");
1444                         return ret;
1445                 }
1446
1447                 ret = _osd_req_finalize_get_attr_list(or);
1448                 if (ret) {
1449                         OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n");
1450                         return ret;
1451                 }
1452         }
1453
1454         ret = _osd_req_finalize_data_integrity(or, has_in, has_out,
1455                                                out_data_bytes, cap_key);
1456         if (ret)
1457                 return ret;
1458
1459         osd_sec_sign_cdb(&or->cdb, cap_key);
1460
1461         or->request->cmd = or->cdb.buff;
1462         or->request->cmd_len = _osd_req_cdb_len(or);
1463
1464         return 0;
1465 }
1466 EXPORT_SYMBOL(osd_finalize_request);
1467
1468 static bool _is_osd_security_code(int code)
1469 {
1470         return  (code == osd_security_audit_value_frozen) ||
1471                 (code == osd_security_working_key_frozen) ||
1472                 (code == osd_nonce_not_unique) ||
1473                 (code == osd_nonce_timestamp_out_of_range) ||
1474                 (code == osd_invalid_dataout_buffer_integrity_check_value);
1475 }
1476
1477 #define OSD_SENSE_PRINT1(fmt, a...) \
1478         do { \
1479                 if (__cur_sense_need_output) \
1480                         OSD_ERR(fmt, ##a); \
1481         } while (0)
1482
1483 #define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1("    " fmt, ##a)
1484
1485 int osd_req_decode_sense_full(struct osd_request *or,
1486         struct osd_sense_info *osi, bool silent,
1487         struct osd_obj_id *bad_obj_list __unused, int max_obj __unused,
1488         struct osd_attr *bad_attr_list, int max_attr)
1489 {
1490         int sense_len, original_sense_len;
1491         struct osd_sense_info local_osi;
1492         struct scsi_sense_descriptor_based *ssdb;
1493         void *cur_descriptor;
1494 #if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0)
1495         const bool __cur_sense_need_output = false;
1496 #else
1497         bool __cur_sense_need_output = !silent;
1498 #endif
1499         int ret;
1500
1501         if (likely(!or->req_errors))
1502                 return 0;
1503
1504         osi = osi ? : &local_osi;
1505         memset(osi, 0, sizeof(*osi));
1506
1507         ssdb = (typeof(ssdb))or->sense;
1508         sense_len = or->sense_len;
1509         if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) {
1510                 OSD_ERR("Block-layer returned error(0x%x) but "
1511                         "sense_len(%u) || key(%d) is empty\n",
1512                         or->req_errors, sense_len, ssdb->sense_key);
1513                 goto analyze;
1514         }
1515
1516         if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
1517                 OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n",
1518                         ssdb->response_code, sense_len);
1519                 goto analyze;
1520         }
1521
1522         osi->key = ssdb->sense_key;
1523         osi->additional_code = be16_to_cpu(ssdb->additional_sense_code);
1524         original_sense_len = ssdb->additional_sense_length + 8;
1525
1526 #if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1)
1527         if (__cur_sense_need_output)
1528                 __cur_sense_need_output = (osi->key > scsi_sk_recovered_error);
1529 #endif
1530         OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) "
1531                         "additional_code=0x%x async_error=%d errors=0x%x\n",
1532                         osi->key, original_sense_len, sense_len,
1533                         osi->additional_code, or->async_error,
1534                         or->req_errors);
1535
1536         if (original_sense_len < sense_len)
1537                 sense_len = original_sense_len;
1538
1539         cur_descriptor = ssdb->ssd;
1540         sense_len -= sizeof(*ssdb);
1541         while (sense_len > 0) {
1542                 struct scsi_sense_descriptor *ssd = cur_descriptor;
1543                 int cur_len = ssd->additional_length + 2;
1544
1545                 sense_len -= cur_len;
1546
1547                 if (sense_len < 0)
1548                         break; /* sense was truncated */
1549
1550                 switch (ssd->descriptor_type) {
1551                 case scsi_sense_information:
1552                 case scsi_sense_command_specific_information:
1553                 {
1554                         struct scsi_sense_command_specific_data_descriptor
1555                                 *sscd = cur_descriptor;
1556
1557                         osi->command_info =
1558                                 get_unaligned_be64(&sscd->information) ;
1559                         OSD_SENSE_PRINT2(
1560                                 "command_specific_information 0x%llx \n",
1561                                 _LLU(osi->command_info));
1562                         break;
1563                 }
1564                 case scsi_sense_key_specific:
1565                 {
1566                         struct scsi_sense_key_specific_data_descriptor
1567                                 *ssks = cur_descriptor;
1568
1569                         osi->sense_info = get_unaligned_be16(&ssks->value);
1570                         OSD_SENSE_PRINT2(
1571                                 "sense_key_specific_information %u"
1572                                 "sksv_cd_bpv_bp (0x%x)\n",
1573                                 osi->sense_info, ssks->sksv_cd_bpv_bp);
1574                         break;
1575                 }
1576                 case osd_sense_object_identification:
1577                 { /*FIXME: Keep first not last, Store in array*/
1578                         struct osd_sense_identification_data_descriptor
1579                                 *osidd = cur_descriptor;
1580
1581                         osi->not_initiated_command_functions =
1582                                 le32_to_cpu(osidd->not_initiated_functions);
1583                         osi->completed_command_functions =
1584                                 le32_to_cpu(osidd->completed_functions);
1585                         osi->obj.partition = be64_to_cpu(osidd->partition_id);
1586                         osi->obj.id = be64_to_cpu(osidd->object_id);
1587                         OSD_SENSE_PRINT2(
1588                                 "object_identification pid=0x%llx oid=0x%llx\n",
1589                                 _LLU(osi->obj.partition), _LLU(osi->obj.id));
1590                         OSD_SENSE_PRINT2(
1591                                 "not_initiated_bits(%x) "
1592                                 "completed_command_bits(%x)\n",
1593                                 osi->not_initiated_command_functions,
1594                                 osi->completed_command_functions);
1595                         break;
1596                 }
1597                 case osd_sense_response_integrity_check:
1598                 {
1599                         struct osd_sense_response_integrity_check_descriptor
1600                                 *osricd = cur_descriptor;
1601                         const unsigned len =
1602                                           sizeof(osricd->integrity_check_value);
1603                         char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */
1604
1605                         hex_dump_to_buffer(osricd->integrity_check_value, len,
1606                                        32, 1, key_dump, sizeof(key_dump), true);
1607                         OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump);
1608                 }
1609                 case osd_sense_attribute_identification:
1610                 {
1611                         struct osd_sense_attributes_data_descriptor
1612                                 *osadd = cur_descriptor;
1613                         unsigned len = min(cur_len, sense_len);
1614                         struct osd_sense_attr *pattr = osadd->sense_attrs;
1615
1616                         while (len >= sizeof(*pattr)) {
1617                                 u32 attr_page = be32_to_cpu(pattr->attr_page);
1618                                 u32 attr_id = be32_to_cpu(pattr->attr_id);
1619
1620                                 if (!osi->attr.attr_page) {
1621                                         osi->attr.attr_page = attr_page;
1622                                         osi->attr.attr_id = attr_id;
1623                                 }
1624
1625                                 if (bad_attr_list && max_attr) {
1626                                         bad_attr_list->attr_page = attr_page;
1627                                         bad_attr_list->attr_id = attr_id;
1628                                         bad_attr_list++;
1629                                         max_attr--;
1630                                 }
1631
1632                                 len -= sizeof(*pattr);
1633                                 OSD_SENSE_PRINT2(
1634                                         "osd_sense_attribute_identification"
1635                                         "attr_page=0x%x attr_id=0x%x\n",
1636                                         attr_page, attr_id);
1637                         }
1638                 }
1639                 /*These are not legal for OSD*/
1640                 case scsi_sense_field_replaceable_unit:
1641                         OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n");
1642                         break;
1643                 case scsi_sense_stream_commands:
1644                         OSD_SENSE_PRINT2("scsi_sense_stream_commands\n");
1645                         break;
1646                 case scsi_sense_block_commands:
1647                         OSD_SENSE_PRINT2("scsi_sense_block_commands\n");
1648                         break;
1649                 case scsi_sense_ata_return:
1650                         OSD_SENSE_PRINT2("scsi_sense_ata_return\n");
1651                         break;
1652                 default:
1653                         if (ssd->descriptor_type <= scsi_sense_Reserved_last)
1654                                 OSD_SENSE_PRINT2(
1655                                         "scsi_sense Reserved descriptor (0x%x)",
1656                                         ssd->descriptor_type);
1657                         else
1658                                 OSD_SENSE_PRINT2(
1659                                         "scsi_sense Vendor descriptor (0x%x)",
1660                                         ssd->descriptor_type);
1661                 }
1662
1663                 cur_descriptor += cur_len;
1664         }
1665
1666 analyze:
1667         if (!osi->key) {
1668                 /* scsi sense is Empty, the request was never issued to target
1669                  * linux return code might tell us what happened.
1670                  */
1671                 if (or->async_error == -ENOMEM)
1672                         osi->osd_err_pri = OSD_ERR_PRI_RESOURCE;
1673                 else
1674                         osi->osd_err_pri = OSD_ERR_PRI_UNREACHABLE;
1675                 ret = or->async_error;
1676         } else if (osi->key <= scsi_sk_recovered_error) {
1677                 osi->osd_err_pri = 0;
1678                 ret = 0;
1679         } else if (osi->additional_code == scsi_invalid_field_in_cdb) {
1680                 if (osi->cdb_field_offset == OSD_CFO_STARTING_BYTE) {
1681                         osi->osd_err_pri = OSD_ERR_PRI_CLEAR_PAGES;
1682                         ret = -EFAULT; /* caller should recover from this */
1683                 } else if (osi->cdb_field_offset == OSD_CFO_OBJECT_ID) {
1684                         osi->osd_err_pri = OSD_ERR_PRI_NOT_FOUND;
1685                         ret = -ENOENT;
1686                 } else if (osi->cdb_field_offset == OSD_CFO_PERMISSIONS) {
1687                         osi->osd_err_pri = OSD_ERR_PRI_NO_ACCESS;
1688                         ret = -EACCES;
1689                 } else {
1690                         osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
1691                         ret = -EINVAL;
1692                 }
1693         } else if (osi->additional_code == osd_quota_error) {
1694                 osi->osd_err_pri = OSD_ERR_PRI_NO_SPACE;
1695                 ret = -ENOSPC;
1696         } else if (_is_osd_security_code(osi->additional_code)) {
1697                 osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED;
1698                 ret = -EINVAL;
1699         } else {
1700                 osi->osd_err_pri = OSD_ERR_PRI_EIO;
1701                 ret = -EIO;
1702         }
1703
1704         if (!or->out.residual)
1705                 or->out.residual = or->out.total_bytes;
1706         if (!or->in.residual)
1707                 or->in.residual = or->in.total_bytes;
1708
1709         return ret;
1710 }
1711 EXPORT_SYMBOL(osd_req_decode_sense_full);
1712
1713 /*
1714  * Implementation of osd_sec.h API
1715  * TODO: Move to a separate osd_sec.c file at a later stage.
1716  */
1717
1718 enum { OSD_SEC_CAP_V1_ALL_CAPS =
1719         OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE   |
1720         OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR |
1721         OSD_SEC_CAP_WRITE  | OSD_SEC_CAP_READ     | OSD_SEC_CAP_POL_SEC  |
1722         OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT
1723 };
1724
1725 enum { OSD_SEC_CAP_V2_ALL_CAPS =
1726         OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT
1727 };
1728
1729 void osd_sec_init_nosec_doall_caps(void *caps,
1730         const struct osd_obj_id *obj, bool is_collection, const bool is_v1)
1731 {
1732         struct osd_capability *cap = caps;
1733         u8 type;
1734         u8 descriptor_type;
1735
1736         if (likely(obj->id)) {
1737                 if (unlikely(is_collection)) {
1738                         type = OSD_SEC_OBJ_COLLECTION;
1739                         descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ :
1740                                                   OSD_SEC_OBJ_DESC_COL;
1741                 } else {
1742                         type = OSD_SEC_OBJ_USER;
1743                         descriptor_type = OSD_SEC_OBJ_DESC_OBJ;
1744                 }
1745                 WARN_ON(!obj->partition);
1746         } else {
1747                 type = obj->partition ? OSD_SEC_OBJ_PARTITION :
1748                                         OSD_SEC_OBJ_ROOT;
1749                 descriptor_type = OSD_SEC_OBJ_DESC_PAR;
1750         }
1751
1752         memset(cap, 0, sizeof(*cap));
1753
1754         cap->h.format = OSD_SEC_CAP_FORMAT_VER1;
1755         cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */
1756         cap->h.security_method = OSD_SEC_NOSEC;
1757 /*      cap->expiration_time;
1758         cap->AUDIT[30-10];
1759         cap->discriminator[42-30];
1760         cap->object_created_time; */
1761         cap->h.object_type = type;
1762         osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS);
1763         cap->h.object_descriptor_type = descriptor_type;
1764         cap->od.obj_desc.policy_access_tag = 0;
1765         cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition);
1766         cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id);
1767 }
1768 EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
1769
1770 /* FIXME: Extract version from caps pointer.
1771  *        Also Pete's target only supports caps from OSDv1 for now
1772  */
1773 void osd_set_caps(struct osd_cdb *cdb, const void *caps)
1774 {
1775         bool is_ver1 = true;
1776         /* NOTE: They start at same address */
1777         memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN);
1778 }
1779
1780 bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
1781 {
1782         return false;
1783 }
1784
1785 void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused)
1786 {
1787 }
1788
1789 void osd_sec_sign_data(void *data_integ __unused,
1790                        struct bio *bio __unused, const u8 *cap_key __unused)
1791 {
1792 }
1793
1794 /*
1795  * Declared in osd_protocol.h
1796  * 4.12.5 Data-In and Data-Out buffer offsets
1797  * byte offset = mantissa * (2^(exponent+8))
1798  * Returns the smallest allowed encoded offset that contains given @offset
1799  * The actual encoded offset returned is @offset + *@padding.
1800  */
1801 osd_cdb_offset __osd_encode_offset(
1802         u64 offset, unsigned *padding, int min_shift, int max_shift)
1803 {
1804         u64 try_offset = -1, mod, align;
1805         osd_cdb_offset be32_offset;
1806         int shift;
1807
1808         *padding = 0;
1809         if (!offset)
1810                 return 0;
1811
1812         for (shift = min_shift; shift < max_shift; ++shift) {
1813                 try_offset = offset >> shift;
1814                 if (try_offset < (1 << OSD_OFFSET_MAX_BITS))
1815                         break;
1816         }
1817
1818         BUG_ON(shift == max_shift);
1819
1820         align = 1 << shift;
1821         mod = offset & (align - 1);
1822         if (mod) {
1823                 *padding = align - mod;
1824                 try_offset += 1;
1825         }
1826
1827         try_offset |= ((shift - 8) & 0xf) << 28;
1828         be32_offset = cpu_to_be32((u32)try_offset);
1829
1830         OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n",
1831                  _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift,
1832                  be32_offset, *padding);
1833         return be32_offset;
1834 }