aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hosts.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/hosts.c')
-rw-r--r--drivers/scsi/hosts.c88
1 files changed, 82 insertions, 6 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 5feb886c3392..6828ca305c2a 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -52,6 +52,82 @@ static struct class shost_class = {
52}; 52};
53 53
54/** 54/**
55 * scsi_host_set_state - Take the given host through the host
56 * state model.
57 * @shost: scsi host to change the state of.
58 * @state: state to change to.
59 *
60 * Returns zero if unsuccessful or an error if the requested
61 * transition is illegal.
62 **/
63int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
64{
65 enum scsi_host_state oldstate = shost->shost_state;
66
67 if (state == oldstate)
68 return 0;
69
70 switch (state) {
71 case SHOST_CREATED:
72 /* There are no legal states that come back to
73 * created. This is the manually initialised start
74 * state */
75 goto illegal;
76
77 case SHOST_RUNNING:
78 switch (oldstate) {
79 case SHOST_CREATED:
80 case SHOST_RECOVERY:
81 break;
82 default:
83 goto illegal;
84 }
85 break;
86
87 case SHOST_RECOVERY:
88 switch (oldstate) {
89 case SHOST_RUNNING:
90 break;
91 default:
92 goto illegal;
93 }
94 break;
95
96 case SHOST_CANCEL:
97 switch (oldstate) {
98 case SHOST_CREATED:
99 case SHOST_RUNNING:
100 break;
101 default:
102 goto illegal;
103 }
104 break;
105
106 case SHOST_DEL:
107 switch (oldstate) {
108 case SHOST_CANCEL:
109 break;
110 default:
111 goto illegal;
112 }
113 break;
114
115 }
116 shost->shost_state = state;
117 return 0;
118
119 illegal:
120 SCSI_LOG_ERROR_RECOVERY(1,
121 dev_printk(KERN_ERR, &shost->shost_gendev,
122 "Illegal host state transition"
123 "%s->%s\n",
124 scsi_host_state_name(oldstate),
125 scsi_host_state_name(state)));
126 return -EINVAL;
127}
128EXPORT_SYMBOL(scsi_host_set_state);
129
130/**
55 * scsi_host_cancel - cancel outstanding IO to this host 131 * scsi_host_cancel - cancel outstanding IO to this host
56 * @shost: pointer to struct Scsi_Host 132 * @shost: pointer to struct Scsi_Host
57 * recovery: recovery requested to run. 133 * recovery: recovery requested to run.
@@ -60,12 +136,11 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
60{ 136{
61 struct scsi_device *sdev; 137 struct scsi_device *sdev;
62 138
63 set_bit(SHOST_CANCEL, &shost->shost_state); 139 scsi_host_set_state(shost, SHOST_CANCEL);
64 shost_for_each_device(sdev, shost) { 140 shost_for_each_device(sdev, shost) {
65 scsi_device_cancel(sdev, recovery); 141 scsi_device_cancel(sdev, recovery);
66 } 142 }
67 wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY, 143 wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY));
68 &shost->shost_state)));
69} 144}
70 145
71/** 146/**
@@ -78,7 +153,7 @@ void scsi_remove_host(struct Scsi_Host *shost)
78 scsi_host_cancel(shost, 0); 153 scsi_host_cancel(shost, 0);
79 scsi_proc_host_rm(shost); 154 scsi_proc_host_rm(shost);
80 155
81 set_bit(SHOST_DEL, &shost->shost_state); 156 scsi_host_set_state(shost, SHOST_DEL);
82 157
83 transport_unregister_device(&shost->shost_gendev); 158 transport_unregister_device(&shost->shost_gendev);
84 class_device_unregister(&shost->shost_classdev); 159 class_device_unregister(&shost->shost_classdev);
@@ -115,7 +190,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
115 if (error) 190 if (error)
116 goto out; 191 goto out;
117 192
118 set_bit(SHOST_ADD, &shost->shost_state); 193 scsi_host_set_state(shost, SHOST_RUNNING);
119 get_device(shost->shost_gendev.parent); 194 get_device(shost->shost_gendev.parent);
120 195
121 error = class_device_add(&shost->shost_classdev); 196 error = class_device_add(&shost->shost_classdev);
@@ -226,6 +301,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
226 301
227 spin_lock_init(&shost->default_lock); 302 spin_lock_init(&shost->default_lock);
228 scsi_assign_lock(shost, &shost->default_lock); 303 scsi_assign_lock(shost, &shost->default_lock);
304 shost->shost_state = SHOST_CREATED;
229 INIT_LIST_HEAD(&shost->__devices); 305 INIT_LIST_HEAD(&shost->__devices);
230 INIT_LIST_HEAD(&shost->__targets); 306 INIT_LIST_HEAD(&shost->__targets);
231 INIT_LIST_HEAD(&shost->eh_cmd_q); 307 INIT_LIST_HEAD(&shost->eh_cmd_q);
@@ -382,7 +458,7 @@ EXPORT_SYMBOL(scsi_host_lookup);
382 **/ 458 **/
383struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) 459struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
384{ 460{
385 if (test_bit(SHOST_DEL, &shost->shost_state) || 461 if ((shost->shost_state == SHOST_DEL) ||
386 !get_device(&shost->shost_gendev)) 462 !get_device(&shost->shost_gendev))
387 return NULL; 463 return NULL;
388 return shost; 464 return shost;