aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-01-25 09:59:50 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-12 13:58:07 -0400
commit4ef1a3d70d02663f6bfe901db629e8e608da15b1 (patch)
treef3b7f1f6ad65fcbc81af1dbdd0b0080d315e4df2 /drivers/scsi
parentb799bc7da0ce5ba4a988c521a8fb10452eb419f0 (diff)
[SCSI] libosd: attributes Support
Support for both List-Mode and Page-Mode osd attributes. One of these operations may be added to most other operations. Define the OSD standard's attribute pages constants and structures (osd_attributes.h) Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Reviewed-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/osd/osd_initiator.c579
1 files changed, 579 insertions, 0 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 0e6d906f1113..b982d767bf99 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -45,6 +45,10 @@
45 45
46#include "osd_debug.h" 46#include "osd_debug.h"
47 47
48#ifndef __unused
49# define __unused __attribute__((unused))
50#endif
51
48enum { OSD_REQ_RETRIES = 1 }; 52enum { OSD_REQ_RETRIES = 1 };
49 53
50MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>"); 54MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
@@ -63,6 +67,50 @@ static unsigned _osd_req_cdb_len(struct osd_request *or)
63 return OSDv1_TOTAL_CDB_LEN; 67 return OSDv1_TOTAL_CDB_LEN;
64} 68}
65 69
70static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len)
71{
72 return osdv1_attr_list_elem_size(len);
73}
74
75static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head)
76{
77 return osdv1_list_size(list_head);
78}
79
80static unsigned _osd_req_sizeof_alist_header(struct osd_request *or)
81{
82 return sizeof(struct osdv1_attributes_list_header);
83}
84
85static void _osd_req_set_alist_type(struct osd_request *or,
86 void *list, int list_type)
87{
88 struct osdv1_attributes_list_header *attr_list = list;
89
90 memset(attr_list, 0, sizeof(*attr_list));
91 attr_list->type = list_type;
92}
93
94static bool _osd_req_is_alist_type(struct osd_request *or,
95 void *list, int list_type)
96{
97 if (!list)
98 return false;
99
100 if (1) {
101 struct osdv1_attributes_list_header *attr_list = list;
102
103 return attr_list->type == list_type;
104 }
105}
106
107static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
108 u64 offset, unsigned *padding)
109{
110 return __osd_encode_offset(offset, padding,
111 OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
112}
113
66void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device) 114void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
67{ 115{
68 memset(osdd, 0, sizeof(*osdd)); 116 memset(osdd, 0, sizeof(*osdd));
@@ -125,10 +173,25 @@ static void _abort_unexecuted_bios(struct request *rq)
125 } 173 }
126} 174}
127 175
176static void _osd_free_seg(struct osd_request *or __unused,
177 struct _osd_req_data_segment *seg)
178{
179 if (!seg->buff || !seg->alloc_size)
180 return;
181
182 kfree(seg->buff);
183 seg->buff = NULL;
184 seg->alloc_size = 0;
185}
186
128void osd_end_request(struct osd_request *or) 187void osd_end_request(struct osd_request *or)
129{ 188{
130 struct request *rq = or->request; 189 struct request *rq = or->request;
131 190
191 _osd_free_seg(or, &or->set_attr);
192 _osd_free_seg(or, &or->enc_get_attr);
193 _osd_free_seg(or, &or->get_attr);
194
132 if (rq) { 195 if (rq) {
133 if (rq->next_rq) { 196 if (rq->next_rq) {
134 _abort_unexecuted_bios(rq->next_rq); 197 _abort_unexecuted_bios(rq->next_rq);
@@ -176,6 +239,54 @@ int osd_execute_request_async(struct osd_request *or,
176} 239}
177EXPORT_SYMBOL(osd_execute_request_async); 240EXPORT_SYMBOL(osd_execute_request_async);
178 241
242u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
243u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
244
245static int _osd_realloc_seg(struct osd_request *or,
246 struct _osd_req_data_segment *seg, unsigned max_bytes)
247{
248 void *buff;
249
250 if (seg->alloc_size >= max_bytes)
251 return 0;
252
253 buff = krealloc(seg->buff, max_bytes, or->alloc_flags);
254 if (!buff) {
255 OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes,
256 seg->alloc_size);
257 return -ENOMEM;
258 }
259
260 memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size);
261 seg->buff = buff;
262 seg->alloc_size = max_bytes;
263 return 0;
264}
265
266static int _alloc_set_attr_list(struct osd_request *or,
267 const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
268{
269 unsigned total_bytes = add_bytes;
270
271 for (; nelem; --nelem, ++oa)
272 total_bytes += _osd_req_alist_elem_size(or, oa->len);
273
274 OSD_DEBUG("total_bytes=%d\n", total_bytes);
275 return _osd_realloc_seg(or, &or->set_attr, total_bytes);
276}
277
278static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes)
279{
280 OSD_DEBUG("total_bytes=%d\n", max_bytes);
281 return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes);
282}
283
284static int _alloc_get_attr_list(struct osd_request *or)
285{
286 OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes);
287 return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes);
288}
289
179/* 290/*
180 * Common to all OSD commands 291 * Common to all OSD commands
181 */ 292 */
@@ -284,6 +395,410 @@ void osd_req_read(struct osd_request *or,
284} 395}
285EXPORT_SYMBOL(osd_req_read); 396EXPORT_SYMBOL(osd_req_read);
286 397
398void osd_req_get_attributes(struct osd_request *or,
399 const struct osd_obj_id *obj)
400{
401 _osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0);
402}
403EXPORT_SYMBOL(osd_req_get_attributes);
404
405void osd_req_set_attributes(struct osd_request *or,
406 const struct osd_obj_id *obj)
407{
408 _osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0);
409}
410EXPORT_SYMBOL(osd_req_set_attributes);
411
412/*
413 * Attributes List-mode
414 */
415
416int osd_req_add_set_attr_list(struct osd_request *or,
417 const struct osd_attr *oa, unsigned nelem)
418{
419 unsigned total_bytes = or->set_attr.total_bytes;
420 void *attr_last;
421 int ret;
422
423 if (or->attributes_mode &&
424 or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
425 WARN_ON(1);
426 return -EINVAL;
427 }
428 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
429
430 if (!total_bytes) { /* first-time: allocate and put list header */
431 total_bytes = _osd_req_sizeof_alist_header(or);
432 ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
433 if (ret)
434 return ret;
435 _osd_req_set_alist_type(or, or->set_attr.buff,
436 OSD_ATTR_LIST_SET_RETRIEVE);
437 }
438 attr_last = or->set_attr.buff + total_bytes;
439
440 for (; nelem; --nelem) {
441 struct osd_attributes_list_element *attr;
442 unsigned elem_size = _osd_req_alist_elem_size(or, oa->len);
443
444 total_bytes += elem_size;
445 if (unlikely(or->set_attr.alloc_size < total_bytes)) {
446 or->set_attr.total_bytes = total_bytes - elem_size;
447 ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
448 if (ret)
449 return ret;
450 attr_last =
451 or->set_attr.buff + or->set_attr.total_bytes;
452 }
453
454 attr = attr_last;
455 attr->attr_page = cpu_to_be32(oa->attr_page);
456 attr->attr_id = cpu_to_be32(oa->attr_id);
457 attr->attr_bytes = cpu_to_be16(oa->len);
458 memcpy(attr->attr_val, oa->val_ptr, oa->len);
459
460 attr_last += elem_size;
461 ++oa;
462 }
463
464 or->set_attr.total_bytes = total_bytes;
465 return 0;
466}
467EXPORT_SYMBOL(osd_req_add_set_attr_list);
468
469static int _append_map_kern(struct request *req,
470 void *buff, unsigned len, gfp_t flags)
471{
472 struct bio *bio;
473 int ret;
474
475 bio = bio_map_kern(req->q, buff, len, flags);
476 if (IS_ERR(bio)) {
477 OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len,
478 PTR_ERR(bio));
479 return PTR_ERR(bio);
480 }
481 ret = blk_rq_append_bio(req->q, req, bio);
482 if (ret) {
483 OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret);
484 bio_put(bio);
485 }
486 return ret;
487}
488
489static int _req_append_segment(struct osd_request *or,
490 unsigned padding, struct _osd_req_data_segment *seg,
491 struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
492{
493 void *pad_buff;
494 int ret;
495
496 if (padding) {
497 /* check if we can just add it to last buffer */
498 if (last_seg &&
499 (padding <= last_seg->alloc_size - last_seg->total_bytes))
500 pad_buff = last_seg->buff + last_seg->total_bytes;
501 else
502 pad_buff = io->pad_buff;
503
504 ret = _append_map_kern(io->req, pad_buff, padding,
505 or->alloc_flags);
506 if (ret)
507 return ret;
508 io->total_bytes += padding;
509 }
510
511 ret = _append_map_kern(io->req, seg->buff, seg->total_bytes,
512 or->alloc_flags);
513 if (ret)
514 return ret;
515
516 io->total_bytes += seg->total_bytes;
517 OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff,
518 seg->total_bytes);
519 return 0;
520}
521
522static int _osd_req_finalize_set_attr_list(struct osd_request *or)
523{
524 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
525 unsigned padding;
526 int ret;
527
528 if (!or->set_attr.total_bytes) {
529 cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED;
530 return 0;
531 }
532
533 cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes);
534 cdbh->attrs_list.set_attr_offset =
535 osd_req_encode_offset(or, or->out.total_bytes, &padding);
536
537 ret = _req_append_segment(or, padding, &or->set_attr,
538 or->out.last_seg, &or->out);
539 if (ret)
540 return ret;
541
542 or->out.last_seg = &or->set_attr;
543 return 0;
544}
545
546int osd_req_add_get_attr_list(struct osd_request *or,
547 const struct osd_attr *oa, unsigned nelem)
548{
549 unsigned total_bytes = or->enc_get_attr.total_bytes;
550 void *attr_last;
551 int ret;
552
553 if (or->attributes_mode &&
554 or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
555 WARN_ON(1);
556 return -EINVAL;
557 }
558 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
559
560 /* first time calc data-in list header size */
561 if (!or->get_attr.total_bytes)
562 or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or);
563
564 /* calc data-out info */
565 if (!total_bytes) { /* first-time: allocate and put list header */
566 unsigned max_bytes;
567
568 total_bytes = _osd_req_sizeof_alist_header(or);
569 max_bytes = total_bytes +
570 nelem * sizeof(struct osd_attributes_list_attrid);
571 ret = _alloc_get_attr_desc(or, max_bytes);
572 if (ret)
573 return ret;
574
575 _osd_req_set_alist_type(or, or->enc_get_attr.buff,
576 OSD_ATTR_LIST_GET);
577 }
578 attr_last = or->enc_get_attr.buff + total_bytes;
579
580 for (; nelem; --nelem) {
581 struct osd_attributes_list_attrid *attrid;
582 const unsigned cur_size = sizeof(*attrid);
583
584 total_bytes += cur_size;
585 if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) {
586 or->enc_get_attr.total_bytes = total_bytes - cur_size;
587 ret = _alloc_get_attr_desc(or,
588 total_bytes + nelem * sizeof(*attrid));
589 if (ret)
590 return ret;
591 attr_last = or->enc_get_attr.buff +
592 or->enc_get_attr.total_bytes;
593 }
594
595 attrid = attr_last;
596 attrid->attr_page = cpu_to_be32(oa->attr_page);
597 attrid->attr_id = cpu_to_be32(oa->attr_id);
598
599 attr_last += cur_size;
600
601 /* calc data-in size */
602 or->get_attr.total_bytes +=
603 _osd_req_alist_elem_size(or, oa->len);
604 ++oa;
605 }
606
607 or->enc_get_attr.total_bytes = total_bytes;
608
609 OSD_DEBUG(
610 "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n",
611 or->get_attr.total_bytes,
612 or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or),
613 or->enc_get_attr.total_bytes,
614 (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or))
615 / sizeof(struct osd_attributes_list_attrid));
616
617 return 0;
618}
619EXPORT_SYMBOL(osd_req_add_get_attr_list);
620
621static int _osd_req_finalize_get_attr_list(struct osd_request *or)
622{
623 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
624 unsigned out_padding;
625 unsigned in_padding;
626 int ret;
627
628 if (!or->enc_get_attr.total_bytes) {
629 cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED;
630 cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED;
631 return 0;
632 }
633
634 ret = _alloc_get_attr_list(or);
635 if (ret)
636 return ret;
637
638 /* The out-going buffer info update */
639 OSD_DEBUG("out-going\n");
640 cdbh->attrs_list.get_attr_desc_bytes =
641 cpu_to_be32(or->enc_get_attr.total_bytes);
642
643 cdbh->attrs_list.get_attr_desc_offset =
644 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
645
646 ret = _req_append_segment(or, out_padding, &or->enc_get_attr,
647 or->out.last_seg, &or->out);
648 if (ret)
649 return ret;
650 or->out.last_seg = &or->enc_get_attr;
651
652 /* The incoming buffer info update */
653 OSD_DEBUG("in-coming\n");
654 cdbh->attrs_list.get_attr_alloc_length =
655 cpu_to_be32(or->get_attr.total_bytes);
656
657 cdbh->attrs_list.get_attr_offset =
658 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
659
660 ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
661 &or->in);
662 if (ret)
663 return ret;
664 or->in.last_seg = &or->get_attr;
665
666 return 0;
667}
668
669int osd_req_decode_get_attr_list(struct osd_request *or,
670 struct osd_attr *oa, int *nelem, void **iterator)
671{
672 unsigned cur_bytes, returned_bytes;
673 int n;
674 const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or);
675 void *cur_p;
676
677 if (!_osd_req_is_alist_type(or, or->get_attr.buff,
678 OSD_ATTR_LIST_SET_RETRIEVE)) {
679 oa->attr_page = 0;
680 oa->attr_id = 0;
681 oa->val_ptr = NULL;
682 oa->len = 0;
683 *iterator = NULL;
684 return 0;
685 }
686
687 if (*iterator) {
688 BUG_ON((*iterator < or->get_attr.buff) ||
689 (or->get_attr.buff + or->get_attr.alloc_size < *iterator));
690 cur_p = *iterator;
691 cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list;
692 returned_bytes = or->get_attr.total_bytes;
693 } else { /* first time decode the list header */
694 cur_bytes = sizeof_attr_list;
695 returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) +
696 sizeof_attr_list;
697
698 cur_p = or->get_attr.buff + sizeof_attr_list;
699
700 if (returned_bytes > or->get_attr.alloc_size) {
701 OSD_DEBUG("target report: space was not big enough! "
702 "Allocate=%u Needed=%u\n",
703 or->get_attr.alloc_size,
704 returned_bytes + sizeof_attr_list);
705
706 returned_bytes =
707 or->get_attr.alloc_size - sizeof_attr_list;
708 }
709 or->get_attr.total_bytes = returned_bytes;
710 }
711
712 for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) {
713 struct osd_attributes_list_element *attr = cur_p;
714 unsigned inc;
715
716 oa->len = be16_to_cpu(attr->attr_bytes);
717 inc = _osd_req_alist_elem_size(or, oa->len);
718 OSD_DEBUG("oa->len=%d inc=%d cur_bytes=%d\n",
719 oa->len, inc, cur_bytes);
720 cur_bytes += inc;
721 if (cur_bytes > returned_bytes) {
722 OSD_ERR("BAD FOOD from target. list not valid!"
723 "c=%d r=%d n=%d\n",
724 cur_bytes, returned_bytes, n);
725 oa->val_ptr = NULL;
726 break;
727 }
728
729 oa->attr_page = be32_to_cpu(attr->attr_page);
730 oa->attr_id = be32_to_cpu(attr->attr_id);
731 oa->val_ptr = attr->attr_val;
732
733 cur_p += inc;
734 ++oa;
735 }
736
737 *iterator = (returned_bytes - cur_bytes) ? cur_p : NULL;
738 *nelem = n;
739 return returned_bytes - cur_bytes;
740}
741EXPORT_SYMBOL(osd_req_decode_get_attr_list);
742
743/*
744 * Attributes Page-mode
745 */
746
747int osd_req_add_get_attr_page(struct osd_request *or,
748 u32 page_id, void *attar_page, unsigned max_page_len,
749 const struct osd_attr *set_one_attr)
750{
751 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
752
753 if (or->attributes_mode &&
754 or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
755 WARN_ON(1);
756 return -EINVAL;
757 }
758 or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE;
759
760 or->get_attr.buff = attar_page;
761 or->get_attr.total_bytes = max_page_len;
762
763 or->set_attr.buff = set_one_attr->val_ptr;
764 or->set_attr.total_bytes = set_one_attr->len;
765
766 cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
767 cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
768 /* ocdb->attrs_page.get_attr_offset; */
769
770 cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
771 cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
772 cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
773 /* ocdb->attrs_page.set_attr_offset; */
774 return 0;
775}
776EXPORT_SYMBOL(osd_req_add_get_attr_page);
777
778static int _osd_req_finalize_attr_page(struct osd_request *or)
779{
780 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
781 unsigned in_padding, out_padding;
782 int ret;
783
784 /* returned page */
785 cdbh->attrs_page.get_attr_offset =
786 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
787
788 ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
789 &or->in);
790 if (ret)
791 return ret;
792
793 /* set one value */
794 cdbh->attrs_page.set_attr_offset =
795 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
796
797 ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
798 &or->out);
799 return ret;
800}
801
287/* 802/*
288 * osd_finalize_request and helpers 803 * osd_finalize_request and helpers
289 */ 804 */
@@ -378,9 +893,31 @@ int osd_finalize_request(struct osd_request *or,
378 _LLU(or->in.total_bytes), or->in.req->data_len); 893 _LLU(or->in.total_bytes), or->in.req->data_len);
379 } 894 }
380 895
896 or->out.pad_buff = sg_out_pad_buffer;
897 or->in.pad_buff = sg_in_pad_buffer;
898
381 if (!or->attributes_mode) 899 if (!or->attributes_mode)
382 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; 900 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
383 cdbh->command_specific_options |= or->attributes_mode; 901 cdbh->command_specific_options |= or->attributes_mode;
902 if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
903 ret = _osd_req_finalize_attr_page(or);
904 } else {
905 /* TODO: I think that for the GET_ATTR command these 2 should
906 * be reversed to keep them in execution order (for embeded
907 * targets with low memory footprint)
908 */
909 ret = _osd_req_finalize_set_attr_list(or);
910 if (ret) {
911 OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n");
912 return ret;
913 }
914
915 ret = _osd_req_finalize_get_attr_list(or);
916 if (ret) {
917 OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n");
918 return ret;
919 }
920 }
384 921
385 or->request->cmd = or->cdb.buff; 922 or->request->cmd = or->cdb.buff;
386 or->request->cmd_len = _osd_req_cdb_len(or); 923 or->request->cmd_len = _osd_req_cdb_len(or);
@@ -446,3 +983,45 @@ void osd_set_caps(struct osd_cdb *cdb, const void *caps)
446{ 983{
447 memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN); 984 memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
448} 985}
986
987/*
988 * Declared in osd_protocol.h
989 * 4.12.5 Data-In and Data-Out buffer offsets
990 * byte offset = mantissa * (2^(exponent+8))
991 * Returns the smallest allowed encoded offset that contains given @offset
992 * The actual encoded offset returned is @offset + *@padding.
993 */
994osd_cdb_offset __osd_encode_offset(
995 u64 offset, unsigned *padding, int min_shift, int max_shift)
996{
997 u64 try_offset = -1, mod, align;
998 osd_cdb_offset be32_offset;
999 int shift;
1000
1001 *padding = 0;
1002 if (!offset)
1003 return 0;
1004
1005 for (shift = min_shift; shift < max_shift; ++shift) {
1006 try_offset = offset >> shift;
1007 if (try_offset < (1 << OSD_OFFSET_MAX_BITS))
1008 break;
1009 }
1010
1011 BUG_ON(shift == max_shift);
1012
1013 align = 1 << shift;
1014 mod = offset & (align - 1);
1015 if (mod) {
1016 *padding = align - mod;
1017 try_offset += 1;
1018 }
1019
1020 try_offset |= ((shift - 8) & 0xf) << 28;
1021 be32_offset = cpu_to_be32((u32)try_offset);
1022
1023 OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n",
1024 _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift,
1025 be32_offset, *padding);
1026 return be32_offset;
1027}