Skip to contentSkip to conversation

RFC: handle queue_depth adjustments because of QUEUE_FULLs in scsi_error.c

RFC PATCH In review [email protected] 3 participants 10 messages May 19, 2009 – Jun 16, 2009

Subsystems (19)
SCSI PowerPC s390 libata +15 more subsystems
lore
Share & tools
lore
#0 lore raw

These patches were made over scsi-rc-fixes. They are only a RFC.

This is the first step to moving the QUEUE_FULL and then the ramp up code from drivers like qla2xxx and lpfc to scsi-ml. In the patches I am using the change_queue_depth callback to allow the drivers to adjust the queue depth, so LLDs do not have to worry about parsing the sense.

If these patches are ok, then we can move the ramp up code from qla2xxx and lpfc to scsi-ml. I was planning on using the change_queue_depth callback for this by calling it with the SCSI_QDEPTH_RAMP_UP reason.

Note:

I did not convert the non fc drivers that were only calling scsi_track_queue_full and did not have a change_queue_depth callback. I think the behavior would be slightly different so I did not want to mess with them. The patches I am sending will work fine if we leave these drivers a long and only convert newer drivers.

mpt2sas was an exception where it is a newer driver and had a change_queue_depth callback but I did not convert it. I wll work on this one some more if this patchset is ok.

#2 lore raw

RFC PATCH 1/4 scsi-ml: modify change_queue_depth to take in reason why it is being called

From: Mike Christie <[email protected]>

This patch modifies scsi_host_tematepl->change_queue_depth so that it takes an argument indicating why it is being called. This will be used so that if a LLD needs to do some extra processing when handling queue fulls or later ramp ups, it can do so.

To simplify the review, this patch only modifies scsi-ml. The next patches will convert each driver.

---
 drivers/scsi/scsi_sysfs.c |    3 ++-
 include/scsi/scsi_host.h  |    9 ++++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)
drivers/scsi/scsi_sysfs.c +2 -1
index fa4711d..2453948 100644
@@ -783,7 +783,8 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
 	if (depth < 1)
 		return -EINVAL;
 
-	retval = sht->change_queue_depth(sdev, depth);
+	retval = sht->change_queue_depth(sdev, depth,
+					 SCSI_QDEPTH_SYSFS_REQ);
 	if (retval < 0)
 		return retval;
 
include/scsi/scsi_host.h +8 -1
index d123ca8..60495f5 100644
@@ -43,6 +43,13 @@ struct blk_queue_tags;
 #define DISABLE_CLUSTERING 0
 #define ENABLE_CLUSTERING 1
 
+enum {
+	SCSI_QDEPTH_SYSFS_REQ,	/* user requested change through sysfs */
+	SCSI_QDEPTH_QFULL,	/* scsi-ml requested due to queue full */
+	SCSI_QDEPTH_RAMP_UP,	/* scsi-ml requested due to threshhold event */
+	SCSI_QDEPTH_RAMP_DOWN, 	/* LLD/class requested due to lld/class event */
+};
+
 struct scsi_host_template {
 	struct module *module;
 	const char *name;
@@ -294,7 +301,7 @@ struct scsi_host_template {
 	 *
 	 * Status: OPTIONAL
 	 */
-	int (* change_queue_depth)(struct scsi_device *, int);
+	int (* change_queue_depth)(struct scsi_device *, int, int);
 
 	/*
 	 * Fill in this function to allow the changing of tag types
Signature · 1 line
1.6.0.6
#3 lore raw

RFC PATCH 2/4 scsi error: have scsi-ml call change_queue_depth to handle QUEUE_FULL

From: Mike Christie <[email protected]>

This has scsi-ml call the change_queue_depth functions when we get a QUEUE_FULL. It will only change the queue depth if change_queue_depth is set because the LLD may have to modify some internal resources, so I thought this would be the safest route.

---
 drivers/scsi/scsi_error.c |   26 +++++++++++++++++++++++++-
 1 files changed, 25 insertions(+), 1 deletions(-)
drivers/scsi/scsi_error.c +25 -1
index 0c2c73b..792644e 100644
@@ -331,6 +331,27 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
 	}
 }
 
+static void scsi_handle_queue_full(struct scsi_device *sdev)
+{
+	struct scsi_host_template *sht = sdev->host->hostt;
+	struct scsi_device *tmp_sdev;
+
+	if (!sht->change_queue_depth)
+		return;
+
+	shost_for_each_device(tmp_sdev, sdev->host) {
+		if (tmp_sdev->id != sdev->id)
+			continue;
+		/*
+		 * We do not know the number of commands that were at
+		 * the device when we got the queue full so we start
+		 * from the highest possible value and work our way down.
+		 */
+		sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1,
+					SCSI_QDEPTH_QFULL);
+	}
+}
+
 /**
  * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
  * @scmd:	SCSI cmd to examine.
@@ -382,8 +403,10 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
 		 * who knows?  FIXME(eric)
 		 */
 		return SUCCESS;
-	case BUSY:
 	case QUEUE_FULL:
+		scsi_handle_queue_full(scmd->device);
+		/* fall through */
+	case BUSY:
 	case RESERVATION_CONFLICT:
 	default:
 		return FAILED;
@@ -1380,6 +1403,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
 	 */
 	switch (status_byte(scmd->result)) {
 	case QUEUE_FULL:
+		scsi_handle_queue_full(scmd->device);
 		/*
 		 * the case of trying to send too many commands to a
 		 * tagged queueing device.
Signature · 1 line
1.6.0.6
#4 lore raw

RFC PATCH 3/4 drivers: convert drivers setting the change_queue_depth callback

From: Mike Christie <[email protected]>

This is a simple port of the drivers setting a change_queue_depth callback but were not tracking queue fulls. In the patch I just have these LLDs adjust the queue depth if the user was requesting it.

Patch is only compile tested.

---
 drivers/ata/libata-scsi.c             |    6 +++++-
 drivers/ata/sata_nv.c                 |    2 +-
 drivers/message/fusion/mptscsih.c     |    8 ++++++--
 drivers/message/fusion/mptscsih.h     |    3 ++-
 drivers/scsi/3w-9xxx.c                |    5 ++++-
 drivers/scsi/3w-xxxx.c                |    5 ++++-
 drivers/scsi/53c700.c                 |    5 ++++-
 drivers/scsi/aacraid/linit.c          |    6 +++++-
 drivers/scsi/arcmsr/arcmsr_hba.c      |    5 ++++-
 drivers/scsi/hptiop.c                 |    5 ++++-
 drivers/scsi/ibmvscsi/ibmvfc.c        |    7 ++++++-
 drivers/scsi/ibmvscsi/ibmvscsi.c      |    7 ++++++-
 drivers/scsi/ipr.c                    |    7 ++++++-
 drivers/scsi/libsas/sas_scsi_host.c   |    6 +++++-
 drivers/scsi/megaraid/megaraid_mbox.c |    7 ++++++-
 drivers/scsi/mpt2sas/mpt2sas_scsih.c  |   10 +++++++---
 include/linux/libata.h                |    2 +-
 include/scsi/libsas.h                 |    3 ++-
 18 files changed, 78 insertions(+), 21 deletions(-)
drivers/ata/libata-scsi.c +5 -1
index 68d9132..45eecb9 100644
@@ -1223,12 +1223,16 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
  *	RETURNS:
  *	Newly configured queue depth.
  */
-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+				int reason)
 {
 	struct ata_port *ap = ata_shost_to_port(sdev->host);
 	struct ata_device *dev;
 	unsigned long flags;
 
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (queue_depth < 1 || queue_depth == sdev->queue_depth)
 		return sdev->queue_depth;
 
drivers/ata/sata_nv.c +1 -1
index 6cda12b..a1c09d9 100644
@@ -1931,7 +1931,7 @@ static int nv_swncq_slave_config(struct scsi_device *sdev)
 	ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
 
 	if (strncmp(model_num, "Maxtor", 6) == 0) {
-		ata_scsi_change_queue_depth(sdev, 1);
+		ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_SYSFS_REQ);
 		ata_dev_printk(dev, KERN_NOTICE,
 			"Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
 	}
drivers/message/fusion/mptscsih.c +6 -2
index e62c6bc..f201846 100644
@@ -2393,7 +2393,7 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
  *	Adding support for new 'change_queue_depth' api.
 */
 int
-mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
 {
 	MPT_SCSI_HOST		*hd = shost_priv(sdev->host);
 	VirtTarget 		*vtarget;
@@ -2405,6 +2405,9 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
 	starget = scsi_target(sdev);
 	vtarget = starget->hostdata;
 
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (ioc->bus_type == SPI) {
 		if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
 			max_depth = 1;
@@ -2457,7 +2460,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
 		    sdev->ppr, sdev->inquiry_len));
 
 	vdevice->configured_lun = 1;
-	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
+	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
+				    SCSI_QDEPTH_SYSFS_REQ);
 
 	dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		"Queue depth=%d, tflags=%x\n",
drivers/message/fusion/mptscsih.h +2 -1
index 319aa30..6404c10 100644
@@ -124,7 +124,8 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F
 extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
 extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
 extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
-extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
+extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth,
+				       int reason);
 extern void mptscsih_timer_expired(unsigned long data);
 extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
drivers/scsi/3w-9xxx.c +4 -1
index 36c21b1..c3d49b3 100644
@@ -186,8 +186,11 @@ static ssize_t twa_show_stats(struct device *dev,
 } /* End twa_show_stats() */
 
 /* This function will set a devices queue depth */
-static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+				  int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
 	if (queue_depth > TW_Q_LENGTH-2)
 		queue_depth = TW_Q_LENGTH-2;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
drivers/scsi/3w-xxxx.c +4 -1
index faa0fcf..5bc1251 100644
@@ -521,8 +521,11 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr,
 } /* End tw_show_stats() */
 
 /* This function will set a devices queue depth */
-static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth,
+				 int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
 	if (queue_depth > TW_Q_LENGTH-2)
 		queue_depth = TW_Q_LENGTH-2;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
drivers/scsi/53c700.c +4 -1
index f5a9add..8fea91a 100644
@@ -2082,8 +2082,11 @@ NCR_700_slave_destroy(struct scsi_device *SDp)
 }
 
 static int
-NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
+NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (depth > NCR_700_MAX_TAGS)
 		depth = NCR_700_MAX_TAGS;
 
drivers/scsi/aacraid/linit.c +5 -1
index 9b97c3e..0b4605a 100644
@@ -472,8 +472,12 @@ static int aac_slave_configure(struct scsi_device *sdev)
  *	total capacity and the queue depth supported by the target device.
  */
 
-static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
+static int aac_change_queue_depth(struct scsi_device *sdev, int depth,
+				  int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
 	    (sdev_channel(sdev) == CONTAINER_CHANNEL)) {
 		struct scsi_device * dev;
drivers/scsi/arcmsr/arcmsr_hba.c +4 -1
index 80aac01..a3d0ded 100644
@@ -98,8 +98,11 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
 static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
-								int queue_depth)
+					  int queue_depth, int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
 		queue_depth = ARCMSR_MAX_CMD_PERLUN;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
drivers/scsi/hptiop.c +4 -1
index c596ab5..a2f3c41 100644
@@ -847,10 +847,13 @@ static int hptiop_reset(struct scsi_cmnd *scp)
 }
 
 static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
-						int queue_depth)
+					  int queue_depth, int reason)
 {
 	struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
 
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (queue_depth > hba->max_requests)
 		queue_depth = hba->max_requests;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
drivers/scsi/ibmvscsi/ibmvfc.c +6 -1
index ea4abee..4e39afa 100644
@@ -2388,12 +2388,17 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev)
  * ibmvfc_change_queue_depth - Change the device's queue depth
  * @sdev:	scsi device struct
  * @qdepth:	depth to set
+ * @reason:	calling context
  *
  * Return value:
  * 	actual depth set
  **/
-static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth,
+				     int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (qdepth > IBMVFC_MAX_CMDS_PER_LUN)
 		qdepth = IBMVFC_MAX_CMDS_PER_LUN;
 
drivers/scsi/ibmvscsi/ibmvscsi.c +6 -1
index c9aa761..6ac1698 100644
@@ -1455,12 +1455,17 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
  * ibmvscsi_change_queue_depth - Change the device's queue depth
  * @sdev:	scsi device struct
  * @qdepth:	depth to set
+ * @reason:	calling context
  *
  * Return value:
  * 	actual depth set
  **/
-static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth,
+				       int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
 		qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
 
drivers/scsi/ipr.c +6 -1
index dd689de..aa04fb5 100644
@@ -3367,16 +3367,21 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
  * ipr_change_queue_depth - Change the device's queue depth
  * @sdev:	scsi device struct
  * @qdepth:	depth to set
+ * @reason:	calling context
  *
  * Return value:
  * 	actual depth set
  **/
-static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth,
+				  int reason)
 {
 	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
 	struct ipr_resource_entry *res;
 	unsigned long lock_flags = 0;
 
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
 	res = (struct ipr_resource_entry *)sdev->hostdata;
 
drivers/scsi/libsas/sas_scsi_host.c +5 -1
index 1c558d3..84230ae 100644
@@ -820,10 +820,14 @@ void sas_slave_destroy(struct scsi_device *scsi_dev)
 		ata_port_disable(dev->sata_dev.ap);
 }
 
-int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
+int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth,
+			   int reason)
 {
 	int res = min(new_depth, SAS_MAX_QD);
 
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (scsi_dev->tagged_supported)
 		scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
 					res);
drivers/scsi/megaraid/megaraid_mbox.c +6 -1
index 234f0b7..dc17d75 100644
@@ -335,12 +335,17 @@ static struct device_attribute *megaraid_sdev_attrs[] = {
  * megaraid_change_queue_depth - Change the device's queue depth
  * @sdev:	scsi device struct
  * @qdepth:	depth to set
+ * @reason:	calling context
  *
  * Return value:
  * 	actual depth set
  */
-static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
+static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth,
+				       int reason)
 {
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	if (qdepth > MBOX_MAX_SCSI_CMDS)
 		qdepth = MBOX_MAX_SCSI_CMDS;
 	scsi_adjust_queue_depth(sdev, 0, qdepth);
drivers/scsi/mpt2sas/mpt2sas_scsih.c +7 -3
index e3a7967..d5e1a3d 100644
@@ -1050,16 +1050,20 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
  * scsih_change_queue_depth - setting device queue depth
  * @sdev: scsi device struct
  * @qdepth: requested queue depth
+ * @reason: calling context
  *
  * Returns queue depth.
  */
 static int
-scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
 {
 	struct Scsi_Host *shost = sdev->host;
 	int max_depth;
 	int tag_type;
 
+	if (reason != SCSI_QDEPTH_SYSFS_REQ)
+		return -EOPNOTSUPP;
+
 	max_depth = shost->can_queue;
 	if (!sdev->tagged_supported)
 		max_depth = 1;
@@ -1489,7 +1493,7 @@ scsih_slave_configure(struct scsi_device *sdev)
 		    r_level, raid_device->handle,
 		    (unsigned long long)raid_device->wwid,
 		    raid_device->num_pds, ds);
-		scsih_change_queue_depth(sdev, qdepth);
+		scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_SYSFS_REQ);
 		return 0;
 	}
 
@@ -1535,7 +1539,7 @@ scsih_slave_configure(struct scsi_device *sdev)
 			scsih_display_sata_capabilities(ioc, sas_device, sdev);
 	}
 
-	scsih_change_queue_depth(sdev, qdepth);
+	scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_SYSFS_REQ);
 
 	if (ssp_target)
 		sas_read_port_mode_page(sdev);
include/linux/libata.h +1 -1
index 3d501db..026cf2e 100644
@@ -1008,7 +1008,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev,
 extern int ata_scsi_slave_config(struct scsi_device *sdev);
 extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
 extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
-				       int queue_depth);
+				       int queue_depth, int reason);
 extern struct ata_device *ata_dev_pair(struct ata_device *adev);
 extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 
include/scsi/libsas.h +2 -1
index e78d3b6..9eaa3f0 100644
@@ -634,7 +634,8 @@ extern int sas_target_alloc(struct scsi_target *);
 extern int sas_slave_alloc(struct scsi_device *);
 extern int sas_slave_configure(struct scsi_device *);
 extern void sas_slave_destroy(struct scsi_device *);
-extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
+extern int sas_change_queue_depth(struct scsi_device *, int new_depth,
+				  int reason);
 extern int sas_change_queue_type(struct scsi_device *, int qt);
 extern int sas_bios_param(struct scsi_device *,
 			  struct block_device *,
Signature · 1 line
1.6.0.6
#5 lore raw

RFC PATCH 4/4 drivers: convert fc drivers calling scsi_track_queue_full

From: Mike Christie <[email protected]>

This converts the fc drivers that were using scsi_track_queue_full to track the queue full from the change_queue_depth callback.

I have not yet tested the qla2xxx or lpfc parts.

---
 drivers/scsi/libfc/fc_fcp.c    |   28 ++++++---------
 drivers/scsi/lpfc/lpfc_scsi.c  |   75 ++++++++++++++++++++++------------------
 drivers/scsi/qla2xxx/qla_isr.c |   28 ---------------
 drivers/scsi/qla2xxx/qla_os.c  |   29 ++++++++++++++-
 include/scsi/libfc.h           |    2 +-
 5 files changed, 80 insertions(+), 82 deletions(-)
drivers/scsi/libfc/fc_fcp.c +11 -17
index 521f996..5b10f37 100644
@@ -1848,21 +1848,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 			sc_cmd->result = DID_OK << 16;
 			if (fsp->scsi_resid)
 				CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid;
-		} else if (fsp->cdb_status == QUEUE_FULL) {
-			struct scsi_device *tmp_sdev;
-			struct scsi_device *sdev = sc_cmd->device;
-
-			shost_for_each_device(tmp_sdev, sdev->host) {
-				if (tmp_sdev->id != sdev->id)
-					continue;
-
-				if (tmp_sdev->queue_depth > 1) {
-					scsi_track_queue_full(tmp_sdev,
-							      tmp_sdev->
-							      queue_depth - 1);
-				}
-			}
-			sc_cmd->result = (DID_OK << 16) | fsp->cdb_status;
 		} else {
 			/*
 			 * transport level I/O was ok but scsi
@@ -2090,9 +2075,18 @@ int fc_slave_alloc(struct scsi_device *sdev)
 }
 EXPORT_SYMBOL(fc_slave_alloc);
 
-int fc_change_queue_depth(struct scsi_device *sdev, int qdepth)
+int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
 {
-	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+	switch (reason) {
+	case SCSI_QDEPTH_SYSFS_REQ:
+		scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+		break;
+	case SCSI_QDEPTH_QFULL:
+		scsi_track_queue_full(sdev, qdepth);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
 	return sdev->queue_depth;
 }
 EXPORT_SYMBOL(fc_change_queue_depth);
drivers/scsi/lpfc/lpfc_scsi.c +41 -34

105 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_isr.c +0 -28
index d049818..fd359b3 100644
@@ -787,20 +787,6 @@ qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
 	    sdev->queue_depth));
 }
 
-static void
-qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
-{
-	fc_port_t *fcport = data;
-
-	if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
-		return;
-
-	DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
-	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
-	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
-	    sdev->queue_depth));
-}
-
 static inline void
 qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req,
 								srb_t *sp)
@@ -1119,11 +1105,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 			    "scsi(%ld): QUEUE FULL status detected "
 			    "0x%x-0x%x.\n", vha->host_no, comp_status,
 			    scsi_status));
-
-			/* Adjust queue depth for all luns on the port. */
-			fcport->last_queue_full = jiffies;
-			starget_for_each_device(cp->device->sdev_target,
-			    fcport, qla2x00_adjust_sdev_qdepth_down);
 			break;
 		}
 		if (lscsi_status != SS_CHECK_CONDITION)
@@ -1174,15 +1155,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
 				    "scsi(%ld): QUEUE FULL status detected "
 				    "0x%x-0x%x.\n", vha->host_no, comp_status,
 				    scsi_status));
-
-				/*
-				 * Adjust queue depth for all luns on the
-				 * port.
-				 */
-				fcport->last_queue_full = jiffies;
-				starget_for_each_device(
-				    cp->device->sdev_target, fcport,
-				    qla2x00_adjust_sdev_qdepth_down);
 				break;
 			}
 			if (lscsi_status != SS_CHECK_CONDITION)
drivers/scsi/qla2xxx/qla_os.c +27 -2
index e4fdcda..e9af1bc 100644
@@ -1141,10 +1141,35 @@ qla2xxx_slave_destroy(struct scsi_device *sdev)
 	sdev->hostdata = NULL;
 }
 
+static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth)
+{
+	fc_port_t *fcport = (struct fc_port *) sdev->device->hostdata;
+
+	fcport->last_queue_full = jiffies;
+
+	if (!scsi_track_queue_full(sdev, qdepth))
+		return;
+
+	DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
+		"scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
+		fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
+		sdev->queue_depth));
+}
+
 static int
-qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth)
+qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
 {
-	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+	switch (reason) {
+	case SCSI_QDEPTH_SYSFS_REQ:
+		scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+		break;
+	case SCSI_QDEPTH_QFULL:
+		qla2x00_handle_queue_full(sdev, qdepth);
+		break;
+	default:
+		return EOPNOTSUPP;
+	}
+
 	return sdev->queue_depth;
 }
 
include/scsi/libfc.h +1 -1
index 45f9cc6..ae1a07f 100644
@@ -868,7 +868,7 @@ int fc_slave_alloc(struct scsi_device *sdev);
 /*
  * Adjust the queue depth.
  */
-int fc_change_queue_depth(struct scsi_device *sdev, int qdepth);
+int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason);
 
 /*
  * Change the tag type.
Signature · 1 line
1.6.0.6
#6 lore raw

Re: [RFC PATCH 4/4] drivers: convert fc drivers calling scsi_track_queue_full

Quoted 8 lines · On Tue, May 19, 2009 at 12:52:47AM -0500, [email protected] wrote:

From: Mike Christie <[email protected]>

This converts the fc drivers that were using scsi_track_queue_full to track the queue full from the change_queue_depth callback.

I have not yet tested the qla2xxx or lpfc parts.

In scsi-misc zfcp also implements the change_queue_depth callback, so this has to be adjusted, too:
--
zfcp: Add reason attribute to scsi_change_queue_depth callback

From: Christof Schmitt <[email protected]>

Now that zfcp implements the scsi_change_queue_depth callback, the reason attribute is also required here.

---
 drivers/s390/scsi/zfcp_scsi.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/s390/scsi/zfcp_scsi.c +2 -1
@@ -28,7 +28,8 @@ char *zfcp_get_fcp_sns_info_ptr(struct f
 	return fcp_sns_info_ptr;
 }
 
-static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth)
+static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
+					int reason)
 {
 	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
 	return sdev->queue_depth;
#7 lore raw

Re: [RFC PATCH 2/4] scsi error: have scsi-ml call change_queue_depth to handle QUEUE_FULL

In reply to [email protected]
Quoted 33 lines · On Tue, May 19, 2009 at 12:52:45AM -0500, [email protected] wrote:

From: Mike Christie <[email protected]>

This has scsi-ml call the change_queue_depth functions when we get a QUEUE_FULL. It will only change the queue depth if change_queue_depth is set because the LLD may have to modify some internal resources, so I thought this would be the safest route.

---
 drivers/scsi/scsi_error.c |   26 +++++++++++++++++++++++++-
 1 files changed, 25 insertions(+), 1 deletions(-)
drivers/scsi/scsi_error.c +11 -0
index 0c2c73b..792644e 100644
@@ -331,6 +331,27 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
 	}
 }
 
+static void scsi_handle_queue_full(struct scsi_device *sdev)
+{
+	struct scsi_host_template *sht = sdev->host->hostt;
+	struct scsi_device *tmp_sdev;
+
+	if (!sht->change_queue_depth)
+		return;
+
+	shost_for_each_device(tmp_sdev, sdev->host) {
+		if (tmp_sdev->id != sdev->id)
+			continue;

drivers/scsi/scsi_error.c static int scsi_check_sense(struct scsi_cmnd *scmd) · line 354

Quoted 10 lines
drivers/scsi/scsi_error.c +10 -0
+		/*
+		 * We do not know the number of commands that were at
+		 * the device when we got the queue full so we start
+		 * from the highest possible value and work our way down.
+		 */
+		sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1,
+					SCSI_QDEPTH_QFULL);
+	}
+}
+

This was called because of a "queue full" for one SCSI device. Why do you decrement the queue depth for all SCSI devices on the same host and not only for one device?

I think the overall approach looks good.

Thanks for working on this,

Christof

#8 lore raw

Re: [RFC PATCH 2/4] scsi error: have scsi-ml call change_queue_depth to handle QUEUE_FULL

Quoted 40 lines · Christof Schmitt
Quoted 39 lines · On Tue, May 19, 2009 at 12:52:45AM -0500, [email protected] wrote:

From: Mike Christie<[email protected]>

This has scsi-ml call the change_queue_depth functions when we get a QUEUE_FULL. It will only change the queue depth if change_queue_depth is set because the LLD may have to modify some internal resources, so I thought this would be the safest route.

---
  drivers/scsi/scsi_error.c |   26 +++++++++++++++++++++++++-
  1 files changed, 25 insertions(+), 1 deletions(-)
drivers/scsi/scsi_error.c +17 -0
index 0c2c73b..792644e 100644
@@ -331,6 +331,27 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
  	}
  }
 
+static void scsi_handle_queue_full(struct scsi_device *sdev)
+{
+	struct scsi_host_template *sht = sdev->host->hostt;
+	struct scsi_device *tmp_sdev;
+
+	if (!sht->change_queue_depth)
+		return;
+
+	shost_for_each_device(tmp_sdev, sdev->host) {
+		if (tmp_sdev->id != sdev->id)
+			continue;
+		/*
+		 * We do not know the number of commands that were at
+		 * the device when we got the queue full so we start
+		 * from the highest possible value and work our way down.
+		 */
+		sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1,
Quoted 8 lines

drivers/scsi/scsi_error.c static int scsi_check_sense(struct scsi_cmnd *scmd) · line 354

Quoted 4 lines
drivers/scsi/scsi_error.c +4 -0
+					SCSI_QDEPTH_QFULL);
+	}
+}
+

This was called because of a "queue full" for one SCSI device. Why do you decrement the queue depth for all SCSI devices on the same host and not only for one device?

It should actually do it for only the devices on the same target where the problem occurred. I copied the code from lpfc and qla2xxx and cannot remember the reason why this is done now. I am ccing AndrewV and JamesS.

#9 lore raw

Re: [RFC PATCH 2/4] scsi error: have scsi-ml call change_queue_depth to handle QUEUE_FULL

Quoted 8 lines · Mike Christie
Quoted 4 lines

This was called because of a "queue full" for one SCSI device. Why do you decrement the queue depth for all SCSI devices on the same host and not only for one device?

It should actually do it for only the devices on the same target where the problem occurred. I copied the code from lpfc and qla2xxx and cannot remember the reason why this is done now. I am ccing AndrewV and JamesS.

Agree that it should be localized to the target and not propagated to all targets. Our design issue was choosing how to apply the backoff - did a queue full on a single lun imply the entire target is full ? Thus, should we reduce all luns at that point, or only the lun that saw the queue full. All depends on how fast you want to ramp down the overall situation and how biased things get on multiple luns.. And the same decision on the ramp up - to we raise everyone, or let the luns function independently. Raising everyone too quickly recauses the issue, and why would one hot lun steal capacity/queuing depth for a slow lun ? There's a lot of assumptions being made in this choice on what is the gating resource (the io capacity of the target being equally shared by all luns).

-- james s