public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
From: "Stephen M. Cameron" <scameron@beardog.cce.hp.com>
To: jbottomley@parallels.com
Cc: stephenmcameron@gmail.com, mikem@beardog.cce.hp.com,
	matthew.gates@hp.com, linux-scsi@vger.kernel.org,
	scott.teel@hp.com
Subject: [PATCH 28/41] hpsa: complete the ioaccel raidmap code
Date: Wed, 15 Jan 2014 16:38:42 -0600	[thread overview]
Message-ID: <20140115223842.5061.33087.stgit@beardog.cce.hp.com> (raw)
In-Reply-To: <20140115223354.5061.50276.stgit@beardog.cce.hp.com>

From: Scott Teel <scott.teel@hp.com>

Load balance across members of a N-way mirror set, and
handle the meta-RAID levels: R10, R50, R60.

Signed-off-by: Scott Teel <scott.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
 drivers/scsi/hpsa.c |  174 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 168 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index cf208e5..0109bf7 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -423,6 +423,13 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
 static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
 	"1(ADM)", "UNKNOWN"
 };
+#define HPSA_RAID_0	0
+#define HPSA_RAID_4	1
+#define HPSA_RAID_1	2	/* also used for RAID 10 */
+#define HPSA_RAID_5	3	/* also used for RAID 50 */
+#define HPSA_RAID_51	4
+#define HPSA_RAID_6	5	/* also used for RAID 60 */
+#define HPSA_RAID_ADM	6	/* also used for RAID 1+0 ADM */
 #define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
 
 static ssize_t raid_level_show(struct device *dev,
@@ -2947,6 +2954,31 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
 						cdb, cdb_len, scsi3addr);
 }
 
+static void raid_map_helper(struct raid_map_data *map,
+		int offload_to_mirror, u32 *map_index, u32 *current_group)
+{
+	if (offload_to_mirror == 0)  {
+		/* use physical disk in the first mirrored group. */
+		*map_index %= map->data_disks_per_row;
+		return;
+	}
+	do {
+		/* determine mirror group that *map_index indicates */
+		*current_group = *map_index / map->data_disks_per_row;
+		if (offload_to_mirror == *current_group)
+			continue;
+		if (*current_group < (map->layout_map_count - 1)) {
+			/* select map index from next group */
+			*map_index += map->data_disks_per_row;
+			(*current_group)++;
+		} else {
+			/* select map index from first group */
+			*map_index %= map->data_disks_per_row;
+			*current_group = 0;
+		}
+	} while (offload_to_mirror != *current_group);
+}
+
 /*
  * Attempt to perform offload RAID mapping for a logical volume I/O.
  */
@@ -2965,6 +2997,14 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
 	u64 first_row, last_row;
 	u32 first_row_offset, last_row_offset;
 	u32 first_column, last_column;
+	u64 r0_first_row, r0_last_row;
+	u32 r5or6_blocks_per_row;
+	u64 r5or6_first_row, r5or6_last_row;
+	u32 r5or6_first_row_offset, r5or6_last_row_offset;
+	u32 r5or6_first_column, r5or6_last_column;
+	u32 total_disks_per_row;
+	u32 stripesize;
+	u32 first_group, last_group, current_group;
 	u32 map_row;
 	u32 disk_handle;
 	u64 disk_block;
@@ -2974,6 +3014,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
 #if BITS_PER_LONG == 32
 	u64 tmpdiv;
 #endif
+	int offload_to_mirror;
 
 	BUG_ON(!(dev->offload_config && dev->offload_enabled));
 
@@ -3076,19 +3117,140 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
 		return IO_ACCEL_INELIGIBLE;
 
 	/* proceeding with driver mapping */
+	total_disks_per_row = map->data_disks_per_row +
+				map->metadata_disks_per_row;
 	map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
 				map->row_cnt;
-	map_index = (map_row * (map->data_disks_per_row +
-				map->metadata_disks_per_row)) + first_column;
-	if (dev->raid_level == 2) {
-		/* simple round-robin balancing of RAID 1+0 reads across
-		 * primary and mirror members.  this is appropriate for SSD
-		 * but not optimal for HDD.
+	map_index = (map_row * total_disks_per_row) + first_column;
+
+	switch (dev->raid_level) {
+	case HPSA_RAID_0:
+		break; /* nothing special to do */
+	case HPSA_RAID_1:
+		/* Handles load balance across RAID 1 members.
+		 * (2-drive R1 and R10 with even # of drives.)
+		 * Appropriate for SSDs, not optimal for HDDs
 		 */
+		BUG_ON(map->layout_map_count != 2);
 		if (dev->offload_to_mirror)
 			map_index += map->data_disks_per_row;
 		dev->offload_to_mirror = !dev->offload_to_mirror;
+		break;
+	case HPSA_RAID_ADM:
+		/* Handles N-way mirrors  (R1-ADM)
+		 * and R10 with # of drives divisible by 3.)
+		 */
+		BUG_ON(map->layout_map_count != 3);
+
+		offload_to_mirror = dev->offload_to_mirror;
+		raid_map_helper(map, offload_to_mirror,
+				&map_index, &current_group);
+		/* set mirror group to use next time */
+		offload_to_mirror =
+			(offload_to_mirror >= map->layout_map_count - 1)
+			? 0 : offload_to_mirror + 1;
+		/* FIXME: remove after debug/dev */
+		BUG_ON(offload_to_mirror >= map->layout_map_count);
+		dev_warn(&h->pdev->dev,
+			"DEBUG: Using physical disk map index %d from mirror group %d\n",
+			map_index, offload_to_mirror);
+		dev->offload_to_mirror = offload_to_mirror;
+		/* Avoid direct use of dev->offload_to_mirror within this
+		 * function since multiple threads might simultaneously
+		 * increment it beyond the range of dev->layout_map_count -1.
+		 */
+		break;
+	case HPSA_RAID_5:
+	case HPSA_RAID_6:
+		if (map->layout_map_count <= 1)
+			break;
+
+		/* Verify first and last block are in same RAID group */
+		r5or6_blocks_per_row =
+			map->strip_size * map->data_disks_per_row;
+		BUG_ON(r5or6_blocks_per_row == 0);
+		stripesize = r5or6_blocks_per_row * map->layout_map_count;
+#if BITS_PER_LONG == 32
+		tmpdiv = first_block;
+		first_group = do_div(tmpdiv, stripesize);
+		tmpdiv = first_group;
+		(void) do_div(tmpdiv, r5or6_blocks_per_row);
+		first_group = tmpdiv;
+		tmpdiv = last_block;
+		last_group = do_div(tmpdiv, stripesize);
+		tmpdiv = last_group;
+		(void) do_div(tmpdiv, r5or6_blocks_per_row);
+		last_group = tmpdiv;
+#else
+		first_group = (first_block % stripesize) / r5or6_blocks_per_row;
+		last_group = (last_block % stripesize) / r5or6_blocks_per_row;
+		if (first_group != last_group)
+#endif
+			return IO_ACCEL_INELIGIBLE;
+
+		/* Verify request is in a single row of RAID 5/6 */
+#if BITS_PER_LONG == 32
+		tmpdiv = first_block;
+		(void) do_div(tmpdiv, stripesize);
+		first_row = r5or6_first_row = r0_first_row = tmpdiv;
+		tmpdiv = last_block;
+		(void) do_div(tmpdiv, stripesize);
+		r5or6_last_row = r0_last_row = tmpdiv;
+#else
+		first_row = r5or6_first_row = r0_first_row =
+						first_block / stripesize;
+		r5or6_last_row = r0_last_row = last_block / stripesize;
+#endif
+		if (r5or6_first_row != r5or6_last_row)
+			return IO_ACCEL_INELIGIBLE;
+
+
+		/* Verify request is in a single column */
+#if BITS_PER_LONG == 32
+		tmpdiv = first_block;
+		first_row_offset = do_div(tmpdiv, stripesize);
+		tmpdiv = first_row_offset;
+		first_row_offset = (u32) do_div(tmpdiv, r5or6_blocks_per_row);
+		r5or6_first_row_offset = first_row_offset;
+		tmpdiv = last_block;
+		r5or6_last_row_offset = do_div(tmpdiv, stripesize);
+		tmpdiv = r5or6_last_row_offset;
+		r5or6_last_row_offset = do_div(tmpdiv, r5or6_blocks_per_row);
+		tmpdiv = r5or6_first_row_offset;
+		(void) do_div(tmpdiv, map->strip_size);
+		first_column = r5or6_first_column = tmpdiv;
+		tmpdiv = r5or6_last_row_offset;
+		(void) do_div(tmpdiv, map->strip_size);
+		r5or6_last_column = tmpdiv;
+#else
+		first_row_offset = r5or6_first_row_offset =
+			(u32)((first_block % stripesize) %
+						r5or6_blocks_per_row);
+
+		r5or6_last_row_offset =
+			(u32)((last_block % stripesize) %
+						r5or6_blocks_per_row);
+
+		first_column = r5or6_first_column =
+			r5or6_first_row_offset / map->strip_size;
+		r5or6_last_column =
+			r5or6_last_row_offset / map->strip_size;
+#endif
+		if (r5or6_first_column != r5or6_last_column)
+			return IO_ACCEL_INELIGIBLE;
+
+		/* Request is eligible */
+		map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
+			map->row_cnt;
+
+		map_index = (first_group *
+			(map->row_cnt * total_disks_per_row)) +
+			(map_row * total_disks_per_row) + first_column;
+		break;
+	default:
+		return IO_ACCEL_INELIGIBLE;
 	}
+
 	disk_handle = dd[map_index].ioaccel_handle;
 	disk_block = map->disk_starting_blk + (first_row * map->strip_size) +
 			(first_row_offset - (first_column * map->strip_size));


  parent reply	other threads:[~2014-01-15 21:38 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-15 22:36 [PATCH 00/41] hpsa January 2014 driver updates Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 01/41] hpsa: revert bring logical drives online when format completes Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 02/41] hpsa: revert hide logical drives with format in progress from linux Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 03/41] hpsa: use workqueue instead of kernel thread for lockup detection Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 04/41] hpsa: rename scsi prefetch field Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 05/41] hpsa: enable unit attention reporting Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 06/41] hpsa: do not require board "not ready" status after hard reset Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 07/41] hpsa: allow SCSI mid layer to handle unit attention Stephen M. Cameron
2014-01-15 22:36 ` [PATCH 08/41] hpsa: use extended report luns command for HP SSD SmartPath Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 09/41] hpsa: mark last scatter gather element as the last Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 10/41] hpsa: add support for 'fastpath' i/o Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 11/41] hpsa: only allow REQ_TYPE_FS to use fast path Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 12/41] hpsa: fix task management for mode-1 ioaccell path Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 13/41] hpsa: add ioaccell mode 1 RAID offload support Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 14/41] hpsa: update raid offload status on device rescan Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 15/41] hpsa: poll controller to detect device change event Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 16/41] hpsa: do not rescan controllers known to be locked up Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 17/41] hpsa: add hp_ssd_smart_path_enabled sysfs attribute Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 18/41] hpsa: complain if physical or logical aborts are not supported Stephen M. Cameron
2014-01-15 22:37 ` [PATCH 19/41] hpsa: add ioaccel mode 2 structure definitions Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 20/41] hpsa: Acknowledge controller events in ioaccell mode 2 as well as mode 1 Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 21/41] hpsa: do ioaccel mode 2 resource allocations Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 22/41] hpsa: get physical device handles for io accel mode 2 as well as mode 1 Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 23/41] hpsa: initialize controller to perform io accelerator mode 2 Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 24/41] hpsa: get ioaccel mode 2 i/o working Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 25/41] hpsa: teach hpsa_device_reset to do either target or lun reset Stephen M. Cameron
2014-01-16  8:36   ` Hannes Reinecke
2014-01-16 13:33     ` Gates, Matt
2014-01-15 22:38 ` [PATCH 26/41] hpsa: add task management for ioaccel mode 2 Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 27/41] hpsa: make device update copy the raid map also Stephen M. Cameron
2014-01-15 22:38 ` Stephen M. Cameron [this message]
2014-01-15 22:38 ` [PATCH 29/41] hpsa: allow user to disable accelerated i/o path Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 30/41] hpsa: rescan devices on ioaccel2 error Stephen M. Cameron
2014-01-15 22:38 ` [PATCH 31/41] hpsa: allow VPD page zero to be queried Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 32/41] hpsa: do not inquire for unsupported ioaccel status vpd page Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 33/41] hpsa: retry certain ioaccel error cases on the RAID path Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 34/41] hpsa: update source file copyrights Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 35/41] hpsa: add controller base data-at-rest encryption compatibility ioaccel2 Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 36/41] hpsa: when switching out of accel mode await only accel command completions Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 37/41] hpsa: only do device rescan for certain events Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 38/41] hpsa: improve error messages for driver initiated commands Stephen M. Cameron
2014-01-16  8:42   ` Hannes Reinecke
2014-01-16 16:14     ` scameron
2014-01-15 22:39 ` [PATCH 39/41] hpsa add sysfs debug switch for raid map debugging messages Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 40/41] pci: add HP/3PAR vendor id to pci_ids.h Stephen M. Cameron
2014-01-15 22:39 ` [PATCH 41/41] hpsa: Add support for a few HP Storage controllers Stephen M. Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140115223842.5061.33087.stgit@beardog.cce.hp.com \
    --to=scameron@beardog.cce.hp.com \
    --cc=jbottomley@parallels.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=matthew.gates@hp.com \
    --cc=mikem@beardog.cce.hp.com \
    --cc=scott.teel@hp.com \
    --cc=stephenmcameron@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox