All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.