public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
From: Andrew Vasquez <andrew.vasquez@qlogic.com>
To: Linux-SCSI Mailing List <linux-scsi@vger.kernel.org>
Subject: [RFC] adding per scsi-host workqueues for defered processing
Date: Mon, 21 Feb 2005 16:09:37 -0800	[thread overview]
Message-ID: <20050222000937.GA7338@plap.qlogic.org> (raw)

Following discussions which resulted from the:

[RFC] target code updates to support scanned targets
http://marc.theaimsgroup.com/?l=linux-scsi&m=110850749515984&w=2

thread, the overall consensus seems to be that transport-classes
should support a 'true-hotplug' mechanism of device discovery and
removal (this involves both registration and lun-scanning).  In order
to facilitate this ability and to not constrain the LLDD from the
typical restrictions of the storage scanning process:

* must be done from process context -- depending on transport type,
  discovery can occur from a non-process context
* potentially _long_ scan times -- even if discovery is done from a
  'sleeping' capable context, halting a LLDD for discovery purposes
  is typically undesirable.

I'd like to propose the addition of a per-Scsi_Host work-queue to
manage these scanning as well as any other (relevant)
lower-level-driver differed requests.

The attached patch adds:

1) a new scsi-host template member 'create_work_queue' which when set
   will create a single-threaded (the per-CPU option seemed too
   heavyweight) work-queue.
2) an exported helper function scsi_queue_work() to queue the work to
   the scsi-host work-queue.

the interface was kept flexible -- queuing of a work_struct object
rather than adding small wrapper functions to perform distinct
operations (i.e. scsi_scan_target_deferred(...), etc) so that any
'deferred' action could be requested by a transport-class or LLDD.

Example usage:

  scsi_transport_fc.h:

	struct fc_rport {
		...
	
		struct work_struct scan_work;
	} __attribute__((aligned(sizeof(unsigned long))));

  scsi_transport_fc.c:

	...	
	static void fc_scan_rport_work(void *data)
	{
		struct fc_rport *rport = (struct fc_rport *)data;

		scsi_scan_target(&rport->dev, rport->channel,
			rport->scsi_target_id, SCAN_WILD_CARD, 0);
	}	

	struct fc_rport *
	fc_create_rport(struct Scsi_Host *shost, int channel,
		struct fc_rport_identifiers  *ids)
	{
		...
		INIT_WORK(&rport->scan_work,
			fc_scan_rport_work, rport);
		...

	
	void
	fc_remote_port_unblock(struct fc_rport *rport)
	{
		struct Scsi_Host *shost = rport_to_shost(rport);
		...
		if (rport->port_state == FC_PORTSTATE_OFFLINE)
			/* Initiate a full rescan, as all
			 * scsi_target objects have been previously
			 * torn-down. */
			scsi_queue_work(shost, &rport->scan_work);
		else
			scsi_target_unblock(&rport->dev);

Anyway, comments?

--
Andrew Vasquez

===== drivers/scsi/hosts.c 1.107 vs edited =====
--- 1.107/drivers/scsi/hosts.c	2005-01-18 11:15:06 -08:00
+++ edited/drivers/scsi/hosts.c	2005-02-21 15:10:38 -08:00
@@ -160,6 +160,9 @@ static void scsi_host_dev_release(struct
 		shost->eh_notify = NULL;
 	}
 
+	if (shost->create_work_queue)
+		destroy_workqueue(shost->work_q);
+
 	scsi_proc_hostdir_rm(shost->hostt);
 	scsi_destroy_command_freelist(shost);
 	kfree(shost->shost_data);
@@ -247,6 +250,7 @@ struct Scsi_Host *scsi_host_alloc(struct
 	shost->cmd_per_lun = sht->cmd_per_lun;
 	shost->unchecked_isa_dma = sht->unchecked_isa_dma;
 	shost->use_clustering = sht->use_clustering;
+	shost->create_work_queue = sht->create_work_queue;
 
 	if (sht->max_host_blocked)
 		shost->max_host_blocked = sht->max_host_blocked;
@@ -285,16 +289,27 @@ struct Scsi_Host *scsi_host_alloc(struct
 	snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
 		  shost->host_no);
 
+	if (shost->create_work_queue) {
+		snprintf(shost->work_q_name, KOBJ_NAME_LEN, "scsi_wq_%d",
+			shost->host_no);
+		shost->work_q = create_singlethread_workqueue(
+			shost->work_q_name);
+		if (!shost->work_q)
+			goto fail_destroy_freelist;
+	}
+
 	shost->eh_notify = &complete;
 	rval = kernel_thread(scsi_error_handler, shost, 0);
 	if (rval < 0)
-		goto fail_destroy_freelist;
+		goto fail_destroy_workqueue;
 	wait_for_completion(&complete);
 	shost->eh_notify = NULL;
 
 	scsi_proc_hostdir_add(shost->hostt);
 	return shost;
 
+ fail_destroy_workqueue:
+	destroy_workqueue(shost->work_q);
  fail_destroy_freelist:
 	scsi_destroy_command_freelist(shost);
  fail_kfree:
@@ -392,3 +407,26 @@ int scsi_is_host_device(const struct dev
 	return dev->release == scsi_host_dev_release;
 }
 EXPORT_SYMBOL(scsi_is_host_device);
+
+/**
+ * scsi_queue_work - Queue work to the Scsi_Host workqueue.
+ * @shost:	Pointer to Scsi_Host.
+ * @work:	Work to queue for execution.
+ *
+ * Return value: 
+ * 	0 on success / != 0 for error
+ **/
+int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
+{
+	if (unlikely(!shost->create_work_queue)) {
+		printk(KERN_ERR
+			"ERROR: Scsi host '%s' attempted to queue scsi-work, "
+			"when no workqueue created.\n", shost->hostt->name);
+		dump_stack();
+
+		return -EINVAL;
+	}
+
+	return queue_work(shost->work_q, work);
+}
+EXPORT_SYMBOL_GPL(scsi_queue_work);
===== include/scsi/scsi_host.h 1.26 vs edited =====
--- 1.26/include/scsi/scsi_host.h	2005-01-19 08:01:21 -08:00
+++ edited/include/scsi/scsi_host.h	2005-02-21 12:13:32 -08:00
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
 struct block_device;
 struct module;
@@ -363,6 +364,11 @@ struct scsi_host_template {
 	unsigned skip_settle_delay:1;
 
 	/*
+	 * True if a work-queue should be created for shost processing.
+	 */
+	unsigned create_work_queue:1;
+
+	/*
 	 * Countdown for host blocking with no commands outstanding
 	 */
 	unsigned int max_host_blocked;
@@ -501,6 +507,11 @@ struct Scsi_Host {
 	 */
 	unsigned reverse_ordering:1;
 
+	unsigned create_work_queue:1;
+
+	char work_q_name[KOBJ_NAME_LEN];
+	struct workqueue_struct *work_q;
+
 	/*
 	 * Host has rejected a command because it was busy.
 	 */
@@ -598,6 +609,7 @@ extern void scsi_free_host_dev(struct sc
 extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *);
 int scsi_is_host_device(const struct device *);
 
+extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *);
 
 /* legacy interfaces */
 extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int);

             reply	other threads:[~2005-02-22  0:09 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-02-22  0:09 Andrew Vasquez [this message]
2005-02-22  1:05 ` [RFC] adding per scsi-host workqueues for defered processing Matthew Wilcox
  -- strict thread matches above, loose matches on Subject: below --
2005-02-22  4:08 James.Smart
2005-03-05 13:07 James.Smart
2005-03-08  7:10 ` Andrew Vasquez
2005-03-05 17:30 James.Smart
2005-03-08  7:00 ` Andrew Vasquez
2005-03-08 13:11   ` Luben Tuikov
2005-03-09  5:19 James.Smart
2005-03-09  7:38 ` Andrew Vasquez
2005-03-09 14:25 ` Brian King

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=20050222000937.GA7338@plap.qlogic.org \
    --to=andrew.vasquez@qlogic.com \
    --cc=linux-scsi@vger.kernel.org \
    /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