--- /dev/null
+Subject: block: fix setting of max_segment_size and seg_boundary mask
+From: Milan Broz <mbroz@redhat.com>
+Date: Wed Dec 3 12:55:55 2008 +0100:
+Git: 0e435ac26e3f951d83338ed3d4ab7dc0fe0055bc
+
+Fix setting of max_segment_size and seg_boundary mask for stacked md/dm
+devices.
+
+When stacking devices (LVM over MD over SCSI) some of the request queue
+parameters are not set up correctly in some cases by default, namely
+max_segment_size and and seg_boundary mask.
+
+If you create MD device over SCSI, these attributes are zeroed.
+
+Problem become when there is over this mapping next device-mapper mapping
+- queue attributes are set in DM this way:
+
+request_queue max_segment_size seg_boundary_mask
+SCSI 65536 0xffffffff
+MD RAID1 0 0
+LVM 65536 -1 (64bit)
+
+Unfortunately bio_add_page (resp. bio_phys_segments) calculates number of
+physical segments according to these parameters.
+
+During the generic_make_request() is segment cout recalculated and can
+increase bio->bi_phys_segments count over the allowed limit. (After
+bio_clone() in stack operation.)
+
+Thi is specially problem in CCISS driver, where it produce OOPS here
+
+ BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
+
+(MAXSEGENTRIES is 31 by default.)
+
+Sometimes even this command is enough to cause oops:
+
+ dd iflag=direct if=/dev/<vg>/<lv> of=/dev/null bs=128000 count=10
+
+This command generates bios with 250 sectors, allocated in 32 4k-pages
+(last page uses only 1024 bytes).
+
+For LVM layer, it allocates bio with 31 segments (still OK for CCISS),
+unfortunatelly on lower layer it is recalculated to 32 segments and this
+violates CCISS restriction and triggers BUG_ON().
+
+The patch tries to fix it by:
+
+ * initializing attributes above in queue request constructor
+ blk_queue_make_request()
+
+ * make sure that blk_queue_stack_limits() inherits setting
+
+ (DM uses its own function to set the limits because it
+ blk_queue_stack_limits() was introduced later. It should probably switch
+ to use generic stack limit function too.)
+
+ * sets the default seg_boundary value in one place (blkdev.h)
+
+ * use this mask as default in DM (instead of -1, which differs in 64bit)
+
+Bugs related to this:
+https://bugzilla.redhat.com/show_bug.cgi?id=471639
+http://bugzilla.kernel.org/show_bug.cgi?id=8672
+
+Signed-off-by: Milan Broz <mbroz@redhat.com>
+Reviewed-by: Alasdair G Kergon <agk@redhat.com>
+Cc: Neil Brown <neilb@suse.de>
+Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
+Cc: Tejun Heo <htejun@gmail.com>
+Cc: Mike Miller <mike.miller@hp.com>
+Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
+Signed-off-by: Hannes Reinecke <hare@suse.de>
+
+---
+ block/blk-core.c | 2 +-
+ block/blk-settings.c | 4 ++++
+ drivers/md/dm-table.c | 2 +-
+ include/linux/blkdev.h | 2 ++
+ 4 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -596,7 +596,7 @@ blk_init_queue_node(request_fn_proc *rfn
+ 1 << QUEUE_FLAG_STACKABLE);
+ q->queue_lock = lock;
+
+- blk_queue_segment_boundary(q, 0xffffffff);
++ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
+
+ blk_queue_make_request(q, __make_request);
+ blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
+--- a/block/blk-settings.c
++++ b/block/blk-settings.c
+@@ -125,6 +125,9 @@ void blk_queue_make_request(struct reque
+ q->nr_requests = BLKDEV_MAX_RQ;
+ blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+ blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
++ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
++ blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
++
+ q->make_request_fn = mfn;
+ q->backing_dev_info.ra_pages =
+ (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+@@ -314,6 +317,7 @@ void blk_queue_stack_limits(struct reque
+ /* zero is "infinity" */
+ t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
+ t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
++ t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask);
+
+ t->max_phys_segments = min(t->max_phys_segments, b->max_phys_segments);
+ t->max_hw_segments = min(t->max_hw_segments, b->max_hw_segments);
+--- a/drivers/md/dm-table.c
++++ b/drivers/md/dm-table.c
+@@ -687,7 +687,7 @@ static void check_for_valid_limits(struc
+ if (!rs->max_segment_size)
+ rs->max_segment_size = MAX_SEGMENT_SIZE;
+ if (!rs->seg_boundary_mask)
+- rs->seg_boundary_mask = -1;
++ rs->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
+ if (!rs->bounce_pfn)
+ rs->bounce_pfn = -1;
+ }
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -908,6 +908,8 @@ extern void blk_set_cmd_filter_defaults(
+
+ #define MAX_SEGMENT_SIZE 65536
+
++#define BLK_SEG_BOUNDARY_MASK 0xFFFFFFFFUL
++
+ #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
+
+ static inline int queue_hardsect_size(struct request_queue *q)