Skip to contentSkip to conversation

scsi host / scsi target state model update

PATCH In review Mike Anderson 2 participants 7 messages Jun 16, 2005 – Jul 12, 2005

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover scsi host / scsi target state model update

This patch sequence converts the SCSI host state model to a model like SCSI device is using and adds a state model for SCSI targets. These new state models are then used to help in the removal of targets and devices during removal of a SCSI host.

I have done some simple add and delete testing. The target state model should have more of the targets states covered. The list_for_each_entry_safe in __scsi_remove_target needs to be cleaned up.

For background context please refer to previous mail.

http://marc.theaimsgroup.com/?t=111878458800003&r=1&w=2

http://marc.theaimsgroup.com/?t=111833447800002&r=1&w=2

-andmike
--
Michael Anderson
[email protected]

#1 lore raw

PATCH 1/5 scsi host / scsi target state model update

Migrate the current SCSI host state model to a model like SCSI device is using.

---

 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/hosts.c      |   88 +++++++++++++++--
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi.c       |    2 
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_error.c |    7 -
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_ioctl.c |    3 
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_lib.c   |    4 
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_sysfs.c |   62 +++++++++++
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/sg.c         |    3 
 linux-2.6.12-rc6-mm1-andmike/include/scsi/scsi_host.h  |   14 +-
 8 files changed, 162 insertions(+), 21 deletions(-)
include/scsi/scsi_host.h renamed from include/scsi/scsi_host.h~host_state +9 -5
diff -puN include/scsi/scsi_host.h~host_state include/scsi/scsi_host.h
@@ -429,12 +429,15 @@ struct scsi_host_template {
 };
 
 /*
- * shost states
+ * shost state: If you alter this, you also need to alter scsi_sysfs.c
+ * (for the ascii descriptions) and the state model enforcer:
+ * scsi_host_set_state()
  */
-enum {
-	SHOST_ADD,
-	SHOST_DEL,
+enum scsi_host_state {
+	SHOST_CREATED = 1,
+	SHOST_RUNNING,
 	SHOST_CANCEL,
+	SHOST_DEL,
 	SHOST_RECOVERY,
 };
 
@@ -575,7 +578,7 @@ struct Scsi_Host {
 	unsigned int  irq;
 	
 
-	unsigned long shost_state;
+	enum scsi_host_state shost_state;
 
 	/* ldm bits */
 	struct device		shost_gendev;
@@ -633,6 +636,7 @@ extern void scsi_remove_host(struct Scsi
 extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
 extern void scsi_host_put(struct Scsi_Host *t);
 extern struct Scsi_Host *scsi_host_lookup(unsigned short);
+extern const char *scsi_host_state_name(enum scsi_host_state);
 
 extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
 
drivers/scsi/scsi_sysfs.c renamed from drivers/scsi/scsi_sysfs.c~host_state +62 -0

80 lines not on this page · raw message

drivers/scsi/hosts.c renamed from drivers/scsi/hosts.c~host_state +82 -6

127 lines not on this page · raw message

drivers/scsi/scsi.c renamed from drivers/scsi/scsi.c~host_state +1 -1
diff -puN drivers/scsi/scsi.c~host_state drivers/scsi/scsi.c
@@ -632,7 +632,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	spin_lock_irqsave(host->host_lock, flags);
 	scsi_cmd_get_serial(host, cmd); 
 
-	if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
+	if (unlikely(host->shost_state == SHOST_CANCEL)) {
 		cmd->result = (DID_NO_CONNECT << 16);
 		scsi_done(cmd);
 	} else {
drivers/scsi/scsi_error.c renamed from drivers/scsi/scsi_error.c~host_state +4 -3
diff -puN drivers/scsi/scsi_error.c~host_state drivers/scsi/scsi_error.c
@@ -80,7 +80,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
 	scmd->owner = SCSI_OWNER_ERROR_HANDLER;
 	scmd->state = SCSI_STATE_FAILED;
 	list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
-	set_bit(SHOST_RECOVERY, &shost->shost_state);
+	scsi_host_set_state(shost, SHOST_RECOVERY);
 	shost->host_failed++;
 	scsi_eh_wakeup(shost);
 	spin_unlock_irqrestore(shost->host_lock, flags);
@@ -202,7 +202,8 @@ int scsi_block_when_processing_errors(st
 {
 	int online;
 
-	wait_event(sdev->host->host_wait, (!test_bit(SHOST_RECOVERY, &sdev->host->shost_state)));
+	wait_event(sdev->host->host_wait, (sdev->host->shost_state !=
+					   SHOST_RECOVERY));
 
 	online = scsi_device_online(sdev);
 
@@ -1513,7 +1514,7 @@ static void scsi_restart_operations(stru
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
 					  __FUNCTION__));
 
-	clear_bit(SHOST_RECOVERY, &shost->shost_state);
+	scsi_host_set_state(shost, SHOST_RUNNING);
 
 	wake_up(&shost->host_wait);
 
drivers/scsi/scsi_ioctl.c renamed from drivers/scsi/scsi_ioctl.c~host_state +1 -2
diff -puN drivers/scsi/scsi_ioctl.c~host_state drivers/scsi/scsi_ioctl.c
@@ -475,8 +475,7 @@ int scsi_nonblockable_ioctl(struct scsi_
 	 * error processing, as long as the device was opened
 	 * non-blocking */
 	if (filp && filp->f_flags & O_NONBLOCK) {
-		if (test_bit(SHOST_RECOVERY,
-			     &sdev->host->shost_state))
+		if (sdev->host->shost_state == SHOST_RECOVERY)
 			return -ENODEV;
 	} else if (!scsi_block_when_processing_errors(sdev))
 		return -ENODEV;
drivers/scsi/scsi_lib.c renamed from drivers/scsi/scsi_lib.c~host_state +2 -2
diff -puN drivers/scsi/scsi_lib.c~host_state drivers/scsi/scsi_lib.c
@@ -357,7 +357,7 @@ void scsi_device_unbusy(struct scsi_devi
 
 	spin_lock_irqsave(shost->host_lock, flags);
 	shost->host_busy--;
-	if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) &&
+	if (unlikely((shost->shost_state == SHOST_RECOVERY) &&
 		     shost->host_failed))
 		scsi_eh_wakeup(shost);
 	spin_unlock(shost->host_lock);
@@ -1218,7 +1218,7 @@ static inline int scsi_host_queue_ready(
 				   struct Scsi_Host *shost,
 				   struct scsi_device *sdev)
 {
-	if (test_bit(SHOST_RECOVERY, &shost->shost_state))
+	if (shost->shost_state == SHOST_RECOVERY)
 		return 0;
 	if (shost->host_busy == 0 && shost->host_blocked) {
 		/*
drivers/scsi/sg.c renamed from drivers/scsi/sg.c~host_state +1 -2
diff -puN drivers/scsi/sg.c~host_state drivers/scsi/sg.c
@@ -1027,8 +1027,7 @@ sg_ioctl(struct inode *inode, struct fil
 		if (sdp->detached)
 			return -ENODEV;
 		if (filp->f_flags & O_NONBLOCK) {
-			if (test_bit(SHOST_RECOVERY,
-				     &sdp->device->host->shost_state))
+			if (sdp->device->host->shost_state == SHOST_RECOVERY)
 				return -EBUSY;
 		} else if (!scsi_block_when_processing_errors(sdp->device))
 			return -EBUSY;

_

#2 lore raw

PATCH 2/5 scsi host / scsi target state model update

Remove the old scsi_host_cancel function as it has not been working for sometime do to the device list possibly being empty when it is called and possible race issues. Add setting of SHOST_CANCEL at the state of beginning of scsi_remove_host.

---

 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/hosts.c |   18 +-----------------
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi.c  |    2 +-
 2 files changed, 2 insertions(+), 18 deletions(-)
drivers/scsi/hosts.c renamed from drivers/scsi/hosts.c~host_cancel +1 -17
diff -puN drivers/scsi/hosts.c~host_cancel drivers/scsi/hosts.c
@@ -128,29 +128,13 @@ int scsi_host_set_state(struct Scsi_Host
 EXPORT_SYMBOL(scsi_host_set_state);
 
 /**
- * scsi_host_cancel - cancel outstanding IO to this host
- * @shost:	pointer to struct Scsi_Host
- * recovery:	recovery requested to run.
- **/
-static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
-{
-	struct scsi_device *sdev;
-
-	scsi_host_set_state(shost, SHOST_CANCEL);
-	shost_for_each_device(sdev, shost) {
-		scsi_device_cancel(sdev, recovery);
-	}
-	wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY));
-}
-
-/**
  * scsi_remove_host - remove a scsi host
  * @shost:	a pointer to a scsi host to remove
  **/
 void scsi_remove_host(struct Scsi_Host *shost)
 {
+	scsi_host_set_state(shost, SHOST_CANCEL);
 	scsi_forget_host(shost);
-	scsi_host_cancel(shost, 0);
 	scsi_proc_host_rm(shost);
 
 	scsi_host_set_state(shost, SHOST_DEL);
drivers/scsi/scsi.c renamed from drivers/scsi/scsi.c~host_cancel +1 -1
diff -puN drivers/scsi/scsi.c~host_cancel drivers/scsi/scsi.c
@@ -632,7 +632,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	spin_lock_irqsave(host->host_lock, flags);
 	scsi_cmd_get_serial(host, cmd); 
 
-	if (unlikely(host->shost_state == SHOST_CANCEL)) {
+	if (unlikely(host->shost_state == SHOST_DEL)) {
 		cmd->result = (DID_NO_CONNECT << 16);
 		scsi_done(cmd);
 	} else {

_

#3 lore raw

PATCH 3/5 scsi host / scsi target state model update

Add support to not allow additions to a host when it is being removed.

---

 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/hosts.c     |    2 +
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_scan.c |   21 ++++++++++++------
 linux-2.6.12-rc6-mm1-andmike/include/scsi/scsi_host.h |    9 +++++++
 3 files changed, 25 insertions(+), 7 deletions(-)
drivers/scsi/hosts.c renamed from drivers/scsi/hosts.c~host_scan +2 -0
diff -puN drivers/scsi/hosts.c~host_scan drivers/scsi/hosts.c
@@ -133,7 +133,9 @@ EXPORT_SYMBOL(scsi_host_set_state);
  **/
 void scsi_remove_host(struct Scsi_Host *shost)
 {
+	down(&shost->scan_mutex);
 	scsi_host_set_state(shost, SHOST_CANCEL);
+	up(&shost->scan_mutex);
 	scsi_forget_host(shost);
 	scsi_proc_host_rm(shost);
 
include/scsi/scsi_host.h renamed from include/scsi/scsi_host.h~host_scan +9 -0
diff -puN include/scsi/scsi_host.h~host_scan include/scsi/scsi_host.h
@@ -656,6 +656,15 @@ static inline struct device *scsi_get_de
         return shost->shost_gendev.parent;
 }
 
+/**
+ * scsi_host_scan_allowed - Is scanning of this host allowed
+ * @shost:	Pointer to Scsi_Host.
+ **/
+static inline int scsi_host_scan_allowed(struct Scsi_Host *shost)
+{
+	return shost->shost_state == SHOST_RUNNING;
+}
+
 extern void scsi_unblock_requests(struct Scsi_Host *);
 extern void scsi_block_requests(struct Scsi_Host *);
 
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c~host_scan +14 -7
diff -puN drivers/scsi/scsi_scan.c~host_scan drivers/scsi/scsi_scan.c
@@ -1218,9 +1218,12 @@ struct scsi_device *__scsi_add_device(st
 
 	get_device(&starget->dev);
 	down(&shost->scan_mutex);
-	res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
-	if (res != SCSI_SCAN_LUN_PRESENT)
-		sdev = ERR_PTR(-ENODEV);
+	if (scsi_host_scan_allowed(shost)) {
+		res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
+					     hostdata);
+		if (res != SCSI_SCAN_LUN_PRESENT)
+			sdev = ERR_PTR(-ENODEV);
+	}
 	up(&shost->scan_mutex);
 	scsi_target_reap(starget);
 	put_device(&starget->dev);
@@ -1370,11 +1373,15 @@ int scsi_scan_host_selected(struct Scsi_
 		return -EINVAL;
 
 	down(&shost->scan_mutex);
-	if (channel == SCAN_WILD_CARD) 
-		for (channel = 0; channel <= shost->max_channel; channel++)
+	if (scsi_host_scan_allowed(shost)) {
+		if (channel == SCAN_WILD_CARD)
+			for (channel = 0; channel <= shost->max_channel;
+			     channel++)
+				scsi_scan_channel(shost, channel, id, lun,
+						  rescan);
+		else
 			scsi_scan_channel(shost, channel, id, lun, rescan);
-	else
-		scsi_scan_channel(shost, channel, id, lun, rescan);
+	}
 	up(&shost->scan_mutex);
 
 	return 0;

_

#4 lore raw

PATCH 4/5 scsi host / scsi target state model update

Add a SCSI target state model similar to the SCSI device state model.

---

 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_lib.c    |   57 ++++++++++++++++
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_scan.c   |    1 
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_sysfs.c  |   23 ++++++
 linux-2.6.12-rc6-mm1-andmike/include/scsi/scsi_device.h |   13 +++
 4 files changed, 94 insertions(+)
include/scsi/scsi_device.h renamed from include/scsi/scsi_device.h~tgt_state +13 -0
diff -puN include/scsi/scsi_device.h~tgt_state include/scsi/scsi_device.h
@@ -140,6 +140,16 @@ struct scsi_device {
 	to_scsi_device(class_dev->dev)
 
 /*
+ * stgt state:
+ * scsi_lib:scsi_device_set_state().
+ */
+enum scsi_target_state {
+	STGT_RUNNING = 1,	/* Target properly configured */
+	STGT_CANCEL,		/* Beginning to delete Target */
+	STGT_DEL,		/* Target deleted */
+};
+
+/*
  * scsi_target: representation of a scsi target, for now, this is only
  * used for single_lun devices. If no one has active IO to the target,
  * starget_sdev_user is NULL, else it points to the active sdev.
@@ -155,6 +165,7 @@ struct scsi_target {
 				     * scsi_device.id eventually */
 	unsigned long		create:1; /* signal that it needs to be added */
 	void 			*hostdata; /* available to low-level driver */
+	enum scsi_target_state	stgt_state;
 	unsigned long		starget_data[0]; /* for the transport */
 	/* starget_data must be the last element!!!! */
 } __attribute__((aligned(sizeof(unsigned long))));
@@ -233,6 +244,8 @@ extern int scsi_test_unit_ready(struct s
 				int retries);
 extern int scsi_device_set_state(struct scsi_device *sdev,
 				 enum scsi_device_state state);
+extern int scsi_target_set_state(struct scsi_target *,
+				 enum scsi_device_state);
 extern int scsi_device_quiesce(struct scsi_device *sdev);
 extern void scsi_device_resume(struct scsi_device *sdev);
 extern void scsi_target_quiesce(struct scsi_target *);
drivers/scsi/scsi_lib.c renamed from drivers/scsi/scsi_lib.c~tgt_state +57 -0

63 lines not on this page · raw message

drivers/scsi/scsi_sysfs.c renamed from drivers/scsi/scsi_sysfs.c~tgt_state +23 -0
diff -puN drivers/scsi/scsi_sysfs.c~tgt_state drivers/scsi/scsi_sysfs.c
@@ -49,6 +49,29 @@ const char *scsi_device_state_name(enum 
 }
 
 static struct {
+	enum scsi_target_state	value;
+	char			*name;
+} stgt_states[] = {
+	{ STGT_RUNNING, "running" },
+	{ STGT_CANCEL, "cancel" },
+	{ STGT_DEL, "deleted" },
+};
+
+const char *scsi_target_state_name(enum scsi_target_state state)
+{
+	int i;
+	char *name = NULL;
+
+	for (i = 0; i < sizeof(stgt_states)/sizeof(stgt_states[0]); i++) {
+		if (stgt_states[i].value == state) {
+			name = stgt_states[i].name;
+			break;
+		}
+	}
+	return name;
+}
+
+static struct {
 	enum scsi_host_state	value;
 	char			*name;
 } shost_states[] = {
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c~tgt_state +1 -0
diff -puN drivers/scsi/scsi_scan.c~tgt_state drivers/scsi/scsi_scan.c
@@ -361,6 +361,7 @@ static struct scsi_target *scsi_alloc_ta
 	if (found_target)
 		goto found;
 
+	starget->stgt_state = STGT_RUNNING;
 	list_add_tail(&starget->siblings, &shost->__targets);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	/* allocate and add */

_

#5 lore raw

PATCH 5/5 scsi host / scsi target state model update

Use new SCSI target state model in scsi_forget_host to help with list traversal and deletion of devices.

---

 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_scan.c  |   32 +++++++++--------
 linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_sysfs.c |    1 
 2 files changed, 18 insertions(+), 15 deletions(-)
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c~tgt_remove +17 -15
diff -puN drivers/scsi/scsi_scan.c~tgt_remove drivers/scsi/scsi_scan.c
@@ -1414,25 +1414,27 @@ EXPORT_SYMBOL(scsi_scan_single_target);
 
 void scsi_forget_host(struct Scsi_Host *shost)
 {
-	struct scsi_target *starget, *tmp;
+	struct scsi_target *starget;
 	unsigned long flags;
 
-	/*
-	 * Ok, this look a bit strange.  We always look for the first device
-	 * on the list as scsi_remove_device removes them from it - thus we
-	 * also have to release the lock.
-	 * We don't need to get another reference to the device before
-	 * releasing the lock as we already own the reference from
-	 * scsi_register_device that's release in scsi_remove_device.  And
-	 * after that we don't look at sdev anymore.
-	 */
-	spin_lock_irqsave(shost->host_lock, flags);
-	list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
-		spin_unlock_irqrestore(shost->host_lock, flags);
-		scsi_remove_target(&starget->dev);
+	while (1) {
+		starget = NULL;
 		spin_lock_irqsave(shost->host_lock, flags);
+		list_for_each_entry(starget, &shost->__targets, siblings) {
+			if (starget->stgt_state == STGT_DEL)
+				continue;
+			if (starget->stgt_state != STGT_CANCEL) {
+				scsi_target_set_state(starget, STGT_CANCEL);
+				break;
+			}
+		}
+		spin_unlock_irqrestore(shost->host_lock, flags);
+
+		if (starget && starget->stgt_state != STGT_DEL)
+			scsi_remove_target(&starget->dev);
+		else
+			return;
 	}
-	spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
 /*
drivers/scsi/scsi_sysfs.c renamed from drivers/scsi/scsi_sysfs.c~tgt_remove +1 -0
diff -puN drivers/scsi/scsi_sysfs.c~tgt_remove drivers/scsi/scsi_sysfs.c
@@ -750,6 +750,7 @@ void __scsi_remove_target(struct scsi_ta
 		scsi_remove_device(sdev);
 		spin_lock_irqsave(shost->host_lock, flags);
 	}
+	scsi_target_set_state(starget, STGT_DEL);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	scsi_target_reap(starget);
 }

_

#6 lore raw
In reply to Mike Anderson
Quoted 1 line · Mike Anderson

Add a SCSI target state model similar to the SCSI device state model.

The first three patches look good (sorry been a hectic month, just getting around to looking through them) so I'll stick them in scsi-misc and see how they work out.

Currently, the target is really slaved to the devices, so we have no actual need of a target state model (if you destroy the last device on a target, the target is also destroyed).

However, ressurecting this could be part of a more comprehensive target model if someone actually proves a need for it.

James