tree ceb564fe0a965588f14b441ef0dc93b36953b6b2
parent 5dbffcd83d826a9b42a10afb89b13156dc5b9539
author Mike Anderson <[EMAIL PROTECTED]> Fri, 17 Jun 2005 01:12:38 -0700
committer James Bottomley <[EMAIL PROTECTED](none)> Sat, 30 Jul 2005 21:10:24 
-0500

[SCSI] host state model update: replace old host bitmap state

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

Signed-off-by: Mike Anderson <[EMAIL PROTECTED]>

Rejections fixed up and

Signed-off-by: James Bottomley <[EMAIL PROTECTED]>

 drivers/scsi/hosts.c      |   88 ++++++++++++++++++++++++++++++++++++++++++----
 drivers/scsi/scsi.c       |    2 -
 drivers/scsi/scsi_error.c |    7 ++-
 drivers/scsi/scsi_ioctl.c |    3 -
 drivers/scsi/scsi_lib.c   |    4 +-
 drivers/scsi/scsi_sysfs.c |   62 ++++++++++++++++++++++++++++++++
 drivers/scsi/sg.c         |    3 -
 include/scsi/scsi_host.h  |   14 ++++---
 8 files changed, 162 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -52,6 +52,82 @@ static struct class shost_class = {
 };
 
 /**
+ *     scsi_host_set_state - Take the given host through the host
+ *             state model.
+ *     @shost: scsi host to change the state of.
+ *     @state: state to change to.
+ *
+ *     Returns zero if unsuccessful or an error if the requested
+ *     transition is illegal.
+ **/
+int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
+{
+       enum scsi_host_state oldstate = shost->shost_state;
+
+       if (state == oldstate)
+               return 0;
+
+       switch (state) {
+       case SHOST_CREATED:
+               /* There are no legal states that come back to
+                * created.  This is the manually initialised start
+                * state */
+               goto illegal;
+
+       case SHOST_RUNNING:
+               switch (oldstate) {
+               case SHOST_CREATED:
+               case SHOST_RECOVERY:
+                       break;
+               default:
+                       goto illegal;
+               }
+               break;
+
+       case SHOST_RECOVERY:
+               switch (oldstate) {
+               case SHOST_RUNNING:
+                       break;
+               default:
+                       goto illegal;
+               }
+               break;
+
+       case SHOST_CANCEL:
+               switch (oldstate) {
+               case SHOST_CREATED:
+               case SHOST_RUNNING:
+                       break;
+               default:
+                       goto illegal;
+               }
+               break;
+
+       case SHOST_DEL:
+               switch (oldstate) {
+               case SHOST_CANCEL:
+                       break;
+               default:
+                       goto illegal;
+               }
+               break;
+
+       }
+       shost->shost_state = state;
+       return 0;
+
+ illegal:
+       SCSI_LOG_ERROR_RECOVERY(1,
+                               dev_printk(KERN_ERR, &shost->shost_gendev,
+                                          "Illegal host state transition"
+                                          "%s->%s\n",
+                                          scsi_host_state_name(oldstate),
+                                          scsi_host_state_name(state)));
+       return -EINVAL;
+}
+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.
@@ -60,12 +136,11 @@ static void scsi_host_cancel(struct Scsi
 {
        struct scsi_device *sdev;
 
-       set_bit(SHOST_CANCEL, &shost->shost_state);
+       scsi_host_set_state(shost, SHOST_CANCEL);
        shost_for_each_device(sdev, shost) {
                scsi_device_cancel(sdev, recovery);
        }
-       wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY,
-                                               &shost->shost_state)));
+       wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY));
 }
 
 /**
@@ -78,7 +153,7 @@ void scsi_remove_host(struct Scsi_Host *
        scsi_host_cancel(shost, 0);
        scsi_proc_host_rm(shost);
 
-       set_bit(SHOST_DEL, &shost->shost_state);
+       scsi_host_set_state(shost, SHOST_DEL);
 
        transport_unregister_device(&shost->shost_gendev);
        class_device_unregister(&shost->shost_classdev);
@@ -115,7 +190,7 @@ int scsi_add_host(struct Scsi_Host *shos
        if (error)
                goto out;
 
-       set_bit(SHOST_ADD, &shost->shost_state);
+       scsi_host_set_state(shost, SHOST_RUNNING);
        get_device(shost->shost_gendev.parent);
 
        error = class_device_add(&shost->shost_classdev);
@@ -226,6 +301,7 @@ struct Scsi_Host *scsi_host_alloc(struct
 
        spin_lock_init(&shost->default_lock);
        scsi_assign_lock(shost, &shost->default_lock);
+       shost->shost_state = SHOST_CREATED;
        INIT_LIST_HEAD(&shost->__devices);
        INIT_LIST_HEAD(&shost->__targets);
        INIT_LIST_HEAD(&shost->eh_cmd_q);
@@ -382,7 +458,7 @@ EXPORT_SYMBOL(scsi_host_lookup);
  **/
 struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
 {
-       if (test_bit(SHOST_DEL, &shost->shost_state) ||
+       if ((shost->shost_state == SHOST_DEL) ||
                !get_device(&shost->shost_gendev))
                return NULL;
        return shost;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -627,7 +627,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 {
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -75,7 +75,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
 
        scmd->eh_eflags |= eh_flag;
        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);
@@ -197,7 +197,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);
 
@@ -1458,7 +1459,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);
 
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
--- a/drivers/scsi/scsi_ioctl.c
+++ b/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;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -348,7 +348,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);
@@ -1207,7 +1207,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) {
                /*
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -48,6 +48,30 @@ const char *scsi_device_state_name(enum 
        return name;
 }
 
+static struct {
+       enum scsi_host_state    value;
+       char                    *name;
+} shost_states[] = {
+       { SHOST_CREATED, "created" },
+       { SHOST_RUNNING, "running" },
+       { SHOST_CANCEL, "cancel" },
+       { SHOST_DEL, "deleted" },
+       { SHOST_RECOVERY, "recovery" },
+};
+const char *scsi_host_state_name(enum scsi_host_state state)
+{
+       int i;
+       char *name = NULL;
+
+       for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) {
+               if (shost_states[i].value == state) {
+                       name = shost_states[i].name;
+                       break;
+               }
+       }
+       return name;
+}
+
 static int check_set(unsigned int *val, char *src)
 {
        char *last;
@@ -124,6 +148,43 @@ static ssize_t store_scan(struct class_d
 };
 static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
 
+static ssize_t
+store_shost_state(struct class_device *class_dev, const char *buf, size_t 
count)
+{
+       int i;
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       enum scsi_host_state state = 0;
+
+       for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) {
+               const int len = strlen(shost_states[i].name);
+               if (strncmp(shost_states[i].name, buf, len) == 0 &&
+                  buf[len] == '\n') {
+                       state = shost_states[i].value;
+                       break;
+               }
+       }
+       if (!state)
+               return -EINVAL;
+
+       if (scsi_host_set_state(shost, state))
+               return -EINVAL;
+       return count;
+}
+
+static ssize_t
+show_shost_state(struct class_device *class_dev, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(class_dev);
+       const char *name = scsi_host_state_name(shost->shost_state);
+
+       if (!name)
+               return -EINVAL;
+
+       return snprintf(buf, 20, "%s\n", name);
+}
+
+static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, 
store_shost_state);
+
 shost_rd_attr(unique_id, "%u\n");
 shost_rd_attr(host_busy, "%hu\n");
 shost_rd_attr(cmd_per_lun, "%hd\n");
@@ -139,6 +200,7 @@ static struct class_device_attribute *sc
        &class_device_attr_unchecked_isa_dma,
        &class_device_attr_proc_name,
        &class_device_attr_scan,
+       &class_device_attr_state,
        NULL
 };
 
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c
+++ b/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;
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h
+++ b/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 *);
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to