diff mbox series

[V3,10/25] smartpqi: add stream detection

Message ID 160763251860.26927.14463337801880165741.stgit@brunhilda (mailing list archive)
State Changes Requested
Headers show
Series smartpqi updates | expand

Commit Message

Don Brace Dec. 10, 2020, 8:35 p.m. UTC
* Enhance performance by adding sequential stream detection.
  for R5/R6 sequential write requests.
  * Reduce stripe lock contention with full-stripe write
    operations.

Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
Reviewed-by: Scott Teel <scott.teel@microchip.com>
Signed-off-by: Don Brace <don.brace@microchip.com>
---
 drivers/scsi/smartpqi/smartpqi.h      |    8 +++
 drivers/scsi/smartpqi/smartpqi_init.c |   87 +++++++++++++++++++++++++++++++--
 2 files changed, 89 insertions(+), 6 deletions(-)

Comments

Martin Wilck Jan. 8, 2021, 12:14 a.m. UTC | #1
On Thu, 2020-12-10 at 14:35 -0600, Don Brace wrote:
> * Enhance performance by adding sequential stream detection.
>   for R5/R6 sequential write requests.
>   * Reduce stripe lock contention with full-stripe write
>     operations.

I suppose that "stripe lock" is used by the firmware? Could you
elaborate a bit more how this technique improves performance?

> 
> Reviewed-by: Scott Benesh <scott.benesh@microchip.com>
> Reviewed-by: Scott Teel <scott.teel@microchip.com>
> Signed-off-by: Don Brace <don.brace@microchip.com>
> ---
>  drivers/scsi/smartpqi/smartpqi.h      |    8 +++
>  drivers/scsi/smartpqi/smartpqi_init.c |   87
> +++++++++++++++++++++++++++++++--
>  2 files changed, 89 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/scsi/smartpqi/smartpqi.h
> b/drivers/scsi/smartpqi/smartpqi.h
> index a5e271dd2742..343f06e44220 100644
> --- a/drivers/scsi/smartpqi/smartpqi.h
> +++ b/drivers/scsi/smartpqi/smartpqi.h
> @@ -1042,6 +1042,12 @@ struct pqi_scsi_dev_raid_map_data {
>  
>  #define RAID_CTLR_LUNID                "\0\0\0\0\0\0\0\0"
>  
> +#define NUM_STREAMS_PER_LUN    8
> +
> +struct pqi_stream_data {
> +       u64     next_lba;
> +       u32     last_accessed;
> +};
>  
>  struct pqi_scsi_dev {
>         int     devtype;                /* as reported by INQUIRY
> commmand */
> @@ -1097,6 +1103,7 @@ struct pqi_scsi_dev {
>         struct list_head add_list_entry;
>         struct list_head delete_list_entry;
>  
> +       struct pqi_stream_data stream_data[NUM_STREAMS_PER_LUN];
>         atomic_t scsi_cmds_outstanding;
>         atomic_t raid_bypass_cnt;
>  };
> @@ -1296,6 +1303,7 @@ struct pqi_ctrl_info {
>         u8              enable_r5_writes : 1;
>         u8              enable_r6_writes : 1;
>         u8              lv_drive_type_mix_valid : 1;
> +       u8              enable_stream_detection : 1;
>  
>         u8              ciss_report_log_flags;
>         u32             max_transfer_encrypted_sas_sata;
> diff --git a/drivers/scsi/smartpqi/smartpqi_init.c
> b/drivers/scsi/smartpqi/smartpqi_init.c
> index fc8fafab480d..96383d047a88 100644
> --- a/drivers/scsi/smartpqi/smartpqi_init.c
> +++ b/drivers/scsi/smartpqi/smartpqi_init.c
> @@ -5721,8 +5721,82 @@ void pqi_prep_for_scsi_done(struct scsi_cmnd
> *scmd)
>         atomic_dec(&device->scsi_cmds_outstanding);
>  }
>  
> -static int pqi_scsi_queue_command(struct Scsi_Host *shost,
> +static bool pqi_is_parity_write_stream(struct pqi_ctrl_info
> *ctrl_info,
>         struct scsi_cmnd *scmd)
> +{
> +       u32 oldest_jiffies;
> +       u8 lru_index;
> +       int i;
> +       int rc;
> +       struct pqi_scsi_dev *device;
> +       struct pqi_stream_data *pqi_stream_data;
> +       struct pqi_scsi_dev_raid_map_data rmd;
> +
> +       if (!ctrl_info->enable_stream_detection)
> +               return false;
> +
> +       rc = pqi_get_aio_lba_and_block_count(scmd, &rmd);
> +       if (rc)
> +               return false;
> +
> +       /* Check writes only. */
> +       if (!rmd.is_write)
> +               return false;
> +
> +       device = scmd->device->hostdata;
> +
> +       /* Check for RAID 5/6 streams. */
> +       if (device->raid_level != SA_RAID_5 && device->raid_level !=
> SA_RAID_6)
> +               return false;
> +
> +       /*
> +        * If controller does not support AIO RAID{5,6} writes, need
> to send
> +        * requests down non-AIO path.
> +        */
> +       if ((device->raid_level == SA_RAID_5 && !ctrl_info-
> >enable_r5_writes) ||
> +               (device->raid_level == SA_RAID_6 && !ctrl_info-
> >enable_r6_writes))
> +               return true;
> +
> +       lru_index = 0;
> +       oldest_jiffies = INT_MAX;
> +       for (i = 0; i < NUM_STREAMS_PER_LUN; i++) {
> +               pqi_stream_data = &device->stream_data[i];
> +               /*
> +                * Check for adjacent request or request is within
> +                * the previous request.
> +                */
> +               if ((pqi_stream_data->next_lba &&
> +                       rmd.first_block >= pqi_stream_data->next_lba)
> &&
> +                       rmd.first_block <= pqi_stream_data->next_lba
> +
> +                               rmd.block_cnt) {

Here you seem to assume that the previous write had the same block_cnt.
What's the justification for that?

> +                       pqi_stream_data->next_lba = rmd.first_block +
> +                               rmd.block_cnt;
> +                       pqi_stream_data->last_accessed = jiffies;
> +                       return true;
> +               }
> +
> +               /* unused entry */
> +               if (pqi_stream_data->last_accessed == 0) {
> +                       lru_index = i;
> +                       break;
> +               }
> +
> +               /* Find entry with oldest last accessed time. */
> +               if (pqi_stream_data->last_accessed <= oldest_jiffies)
> {
> +                       oldest_jiffies = pqi_stream_data-
> >last_accessed;
> +                       lru_index = i;
> +               }
> +       }
> +
> +       /* Set LRU entry. */
> +       pqi_stream_data = &device->stream_data[lru_index];
> +       pqi_stream_data->last_accessed = jiffies;
> +       pqi_stream_data->next_lba = rmd.first_block + rmd.block_cnt;
> +
> +       return false;
> +}
> +
> +static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct
> scsi_cmnd *scmd)
>  {
>         int rc;
>         struct pqi_ctrl_info *ctrl_info;
> @@ -5768,11 +5842,12 @@ static int pqi_scsi_queue_command(struct
> Scsi_Host *shost,
>                 raid_bypassed = false;
>                 if (device->raid_bypass_enabled &&
>                         !blk_rq_is_passthrough(scmd->request)) {
> -                       rc =
> pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
> -                               scmd, queue_group);
> -                       if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY)
> {
> -                               raid_bypassed = true;
> -                               atomic_inc(&device->raid_bypass_cnt);
> +                       if (!pqi_is_parity_write_stream(ctrl_info,
> scmd)) {
> +                               rc =
> pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd,
> queue_group);
> +                               if (rc == 0 || rc ==
> SCSI_MLQUEUE_HOST_BUSY) {
> +                                       raid_bypassed = true;
> +                                       atomic_inc(&device-
> >raid_bypass_cnt);
> +                               }
>                         }
>                 }
>                 if (!raid_bypassed)
>
Don Brace Jan. 15, 2021, 9:58 p.m. UTC | #2
-----Original Message-----
From: Martin Wilck [mailto:mwilck@suse.com] 
Sent: Thursday, January 7, 2021 6:14 PM
To: Don Brace - C33706 <Don.Brace@microchip.com>; Kevin Barnett - C33748 <Kevin.Barnett@microchip.com>; Scott Teel - C33730 <Scott.Teel@microchip.com>; Justin Lindley - C33718 <Justin.Lindley@microchip.com>; Scott Benesh - C33703 <Scott.Benesh@microchip.com>; Gerry Morong - C33720 <Gerry.Morong@microchip.com>; Mahesh Rajashekhara - I30583 <Mahesh.Rajashekhara@microchip.com>; hch@infradead.org; jejb@linux.vnet.ibm.com; joseph.szczypek@hpe.com; POSWALD@suse.com
Cc: linux-scsi@vger.kernel.org
Subject: Re: [PATCH V3 10/25] smartpqi: add stream detection

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

On Thu, 2020-12-10 at 14:35 -0600, Don Brace wrote:
> * Enhance performance by adding sequential stream detection.
>   for R5/R6 sequential write requests.
>   * Reduce stripe lock contention with full-stripe write
>     operations.

I suppose that "stripe lock" is used by the firmware? Could you elaborate a bit more how this technique improves performance?

> +       /*
> +        * If controller does not support AIO RAID{5,6} writes, need
> to send
> +        * requests down non-AIO path.
> +        */
> +       if ((device->raid_level == SA_RAID_5 && !ctrl_info-
> >enable_r5_writes) ||
> +               (device->raid_level == SA_RAID_6 && !ctrl_info-
> >enable_r6_writes))
> +               return true;
> +
> +       lru_index = 0;
> +       oldest_jiffies = INT_MAX;
> +       for (i = 0; i < NUM_STREAMS_PER_LUN; i++) {
> +               pqi_stream_data = &device->stream_data[i];
> +               /*
> +                * Check for adjacent request or request is within
> +                * the previous request.
> +                */
> +               if ((pqi_stream_data->next_lba &&
> +                       rmd.first_block >= pqi_stream_data->next_lba)
> &&
> +                       rmd.first_block <= pqi_stream_data->next_lba
> +
> +                               rmd.block_cnt) {

Here you seem to assume that the previous write had the same block_cnt.
What's the justification for that?

Don:
There is a maximum request size for RAID 5/RAID 6 write requests. So we are assuming that if a sequential stream is detected, the stream is comprised of similar request sizes. In fact for coalescing, the LBAs need to be continuous or nearly contiguous, otherwise the RAID engine will not wait for a full-stripe.

I have updated the patch description accordingly.

> +                       pqi_stream_data->next_lba = rmd.first_block +
> +                               rmd.block_cnt;
> +                       pqi_stream_data->last_accessed = jiffies;
> +                       return true;
> +               }
> +
> +               /* unused entry */
> +               if (pqi_stream_data->last_accessed == 0) {
> +                       lru_index = i;
> +                       break;
> +               }
> +
> +               /* Find entry with oldest last accessed time. */
> +               if (pqi_stream_data->last_accessed <= oldest_jiffies)
> {
> +                       oldest_jiffies = pqi_stream_data-
> >last_accessed;
> +                       lru_index = i;
> +               }
> +       }
> +
> +       /* Set LRU entry. */
> +       pqi_stream_data = &device->stream_data[lru_index];
> +       pqi_stream_data->last_accessed = jiffies;
> +       pqi_stream_data->next_lba = rmd.first_block + rmd.block_cnt;
> +
> +       return false;
> +}
> +
> +static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct
> scsi_cmnd *scmd)
>  {
>         int rc;
>         struct pqi_ctrl_info *ctrl_info; @@ -5768,11 +5842,12 @@ 
> static int pqi_scsi_queue_command(struct Scsi_Host *shost,
>                 raid_bypassed = false;
>                 if (device->raid_bypass_enabled &&
>                         !blk_rq_is_passthrough(scmd->request)) {
> -                       rc =
> pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
> -                               scmd, queue_group);
> -                       if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY)
> {
> -                               raid_bypassed = true;
> -                               atomic_inc(&device->raid_bypass_cnt);
> +                       if (!pqi_is_parity_write_stream(ctrl_info,
> scmd)) {
> +                               rc =
> pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group);
> +                               if (rc == 0 || rc ==
> SCSI_MLQUEUE_HOST_BUSY) {
> +                                       raid_bypassed = true;
> +                                       atomic_inc(&device-
> >raid_bypass_cnt);
> +                               }
>                         }
>                 }
>                 if (!raid_bypassed)
>
diff mbox series

Patch

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index a5e271dd2742..343f06e44220 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -1042,6 +1042,12 @@  struct pqi_scsi_dev_raid_map_data {
 
 #define RAID_CTLR_LUNID		"\0\0\0\0\0\0\0\0"
 
+#define NUM_STREAMS_PER_LUN	8
+
+struct pqi_stream_data {
+	u64	next_lba;
+	u32	last_accessed;
+};
 
 struct pqi_scsi_dev {
 	int	devtype;		/* as reported by INQUIRY commmand */
@@ -1097,6 +1103,7 @@  struct pqi_scsi_dev {
 	struct list_head add_list_entry;
 	struct list_head delete_list_entry;
 
+	struct pqi_stream_data stream_data[NUM_STREAMS_PER_LUN];
 	atomic_t scsi_cmds_outstanding;
 	atomic_t raid_bypass_cnt;
 };
@@ -1296,6 +1303,7 @@  struct pqi_ctrl_info {
 	u8		enable_r5_writes : 1;
 	u8		enable_r6_writes : 1;
 	u8		lv_drive_type_mix_valid : 1;
+	u8		enable_stream_detection : 1;
 
 	u8		ciss_report_log_flags;
 	u32		max_transfer_encrypted_sas_sata;
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index fc8fafab480d..96383d047a88 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -5721,8 +5721,82 @@  void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)
 	atomic_dec(&device->scsi_cmds_outstanding);
 }
 
-static int pqi_scsi_queue_command(struct Scsi_Host *shost,
+static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info,
 	struct scsi_cmnd *scmd)
+{
+	u32 oldest_jiffies;
+	u8 lru_index;
+	int i;
+	int rc;
+	struct pqi_scsi_dev *device;
+	struct pqi_stream_data *pqi_stream_data;
+	struct pqi_scsi_dev_raid_map_data rmd;
+
+	if (!ctrl_info->enable_stream_detection)
+		return false;
+
+	rc = pqi_get_aio_lba_and_block_count(scmd, &rmd);
+	if (rc)
+		return false;
+
+	/* Check writes only. */
+	if (!rmd.is_write)
+		return false;
+
+	device = scmd->device->hostdata;
+
+	/* Check for RAID 5/6 streams. */
+	if (device->raid_level != SA_RAID_5 && device->raid_level != SA_RAID_6)
+		return false;
+
+	/*
+	 * If controller does not support AIO RAID{5,6} writes, need to send
+	 * requests down non-AIO path.
+	 */
+	if ((device->raid_level == SA_RAID_5 && !ctrl_info->enable_r5_writes) ||
+		(device->raid_level == SA_RAID_6 && !ctrl_info->enable_r6_writes))
+		return true;
+
+	lru_index = 0;
+	oldest_jiffies = INT_MAX;
+	for (i = 0; i < NUM_STREAMS_PER_LUN; i++) {
+		pqi_stream_data = &device->stream_data[i];
+		/*
+		 * Check for adjacent request or request is within
+		 * the previous request.
+		 */
+		if ((pqi_stream_data->next_lba &&
+			rmd.first_block >= pqi_stream_data->next_lba) &&
+			rmd.first_block <= pqi_stream_data->next_lba +
+				rmd.block_cnt) {
+			pqi_stream_data->next_lba = rmd.first_block +
+				rmd.block_cnt;
+			pqi_stream_data->last_accessed = jiffies;
+			return true;
+		}
+
+		/* unused entry */
+		if (pqi_stream_data->last_accessed == 0) {
+			lru_index = i;
+			break;
+		}
+
+		/* Find entry with oldest last accessed time. */
+		if (pqi_stream_data->last_accessed <= oldest_jiffies) {
+			oldest_jiffies = pqi_stream_data->last_accessed;
+			lru_index = i;
+		}
+	}
+
+	/* Set LRU entry. */
+	pqi_stream_data = &device->stream_data[lru_index];
+	pqi_stream_data->last_accessed = jiffies;
+	pqi_stream_data->next_lba = rmd.first_block + rmd.block_cnt;
+
+	return false;
+}
+
+static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
 {
 	int rc;
 	struct pqi_ctrl_info *ctrl_info;
@@ -5768,11 +5842,12 @@  static int pqi_scsi_queue_command(struct Scsi_Host *shost,
 		raid_bypassed = false;
 		if (device->raid_bypass_enabled &&
 			!blk_rq_is_passthrough(scmd->request)) {
-			rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device,
-				scmd, queue_group);
-			if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) {
-				raid_bypassed = true;
-				atomic_inc(&device->raid_bypass_cnt);
+			if (!pqi_is_parity_write_stream(ctrl_info, scmd)) {
+				rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group);
+				if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) {
+					raid_bypassed = true;
+					atomic_inc(&device->raid_bypass_cnt);
+				}
 			}
 		}
 		if (!raid_bypassed)