[SCSI] megaraid_sas: Add support for Uneven Span PRL11

MegaRAID older Firmware does not support uneven span configuration for PRL11.
E.g User wants to create 34 Driver PRL11 config, it was not possible using old
firmware, since it was not supported configuration in old firmware

Old Firmware expect even number of Drives in each span and same number of
physical drives at each span.  Considering above design, 17 Drives at Span-0
and 17 drives at span-1 was not possible.

Now, using this new feature Firmware and Driver both required changes.  New
Firmware can allow user to create 16 Drives at span-0 and 18 Drives at
span-1. This will allow user to create 34 Drives Uneven span PRL11.

RAID map is interface between Driver and FW to fetch all required
fields(attributes) for each Virtual Drives.  Since legacy RAID map consider
Even Span design, there was no place to keep Uneven span information in
existing Raid map.  Because of this limitation, for Uneven span VD, driver can
not use RAID map.

This patch address the changes required in Driver to support Uneven span PRL11
support.

1. Driver will find if Firmware has UnevenSpanSupport or not by reading
   Controller Info.
2. If Firmware has UnvenSpan PRL11 support, then Driver will inform about its
   capability of handling UnevenSpan PRL11 to the firmware.
3. Driver will update its copy of span info on each time Raid map update is
   called.
4. Follow different IO path if it is Uneven Span. (For Uneven Span, Driver
   uses Span Set info to find relavent fields for that particular Virtual
   Disk)

More verbose prints will be available by setting "SPAN_DEBUG" to 1 at
compilation time.

Signed-off-by: Sumit Saxena <sumit.saxena@lsi.com>
Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 004c18e..12ff01c 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -463,6 +463,7 @@
 /* mrpriv defines */
 #define MR_PD_INVALID 0xFFFF
 #define MAX_SPAN_DEPTH 8
+#define MAX_QUAD_DEPTH	MAX_SPAN_DEPTH
 #define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH)
 #define MAX_ROW_SIZE 32
 #define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE)
@@ -504,7 +505,9 @@
 	u64      startBlk;
 	u64      numBlks;
 	u16      arrayRef;
-	u8       reserved[6];
+	u8       spanRowSize;
+	u8       spanRowDataSize;
+	u8       reserved[4];
 };
 
 struct MR_SPAN_BLOCK_INFO {
@@ -590,6 +593,10 @@
 	u16 devHandle;
 	u64 pdBlock;
 	u8 fpOkForIo;
+	u8 IoforUnevenSpan;
+	u8 start_span;
+	u8 reserved;
+	u64 start_row;
 };
 
 struct MR_LD_TARGET_SYNC {
@@ -651,6 +658,26 @@
 	u64     last_accessed_block[2];
 };
 
+/* SPAN_SET is info caclulated from span info from Raid map per LD */
+typedef struct _LD_SPAN_SET {
+	u64  log_start_lba;
+	u64  log_end_lba;
+	u64  span_row_start;
+	u64  span_row_end;
+	u64  data_strip_start;
+	u64  data_strip_end;
+	u64  data_row_start;
+	u64  data_row_end;
+	u8   strip_offset[MAX_SPAN_DEPTH];
+	u32    span_row_data_width;
+	u32    diff;
+	u32    reserved[2];
+} LD_SPAN_SET, *PLD_SPAN_SET;
+
+typedef struct LOG_BLOCK_SPAN_INFO {
+	LD_SPAN_SET  span_set[MAX_SPAN_DEPTH];
+} LD_SPAN_INFO, *PLD_SPAN_INFO;
+
 struct MR_FW_RAID_MAP_ALL {
 	struct MR_FW_RAID_MAP raidMap;
 	struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1];
@@ -695,6 +722,7 @@
 	u32 map_sz;
 	u8 fast_path_io;
 	struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES];
+	LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES];
 };
 
 union desc_value {