Commit d3301874 authored by Mike Anderson's avatar Mike Anderson Committed by James Bottomley

[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: default avatarMike Anderson <andmike@us.ibm.com>

Rejections fixed up and
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 5dbffcd8
...@@ -51,6 +51,82 @@ static struct class shost_class = { ...@@ -51,6 +51,82 @@ static struct class shost_class = {
.release = scsi_host_cls_release, .release = scsi_host_cls_release,
}; };
/**
* 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 * scsi_host_cancel - cancel outstanding IO to this host
* @shost: pointer to struct Scsi_Host * @shost: pointer to struct Scsi_Host
...@@ -60,12 +136,11 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) ...@@ -60,12 +136,11 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
{ {
struct scsi_device *sdev; struct scsi_device *sdev;
set_bit(SHOST_CANCEL, &shost->shost_state); scsi_host_set_state(shost, SHOST_CANCEL);
shost_for_each_device(sdev, shost) { shost_for_each_device(sdev, shost) {
scsi_device_cancel(sdev, recovery); scsi_device_cancel(sdev, recovery);
} }
wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY, wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY));
&shost->shost_state)));
} }
/** /**
...@@ -78,7 +153,7 @@ void scsi_remove_host(struct Scsi_Host *shost) ...@@ -78,7 +153,7 @@ void scsi_remove_host(struct Scsi_Host *shost)
scsi_host_cancel(shost, 0); scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost); 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); transport_unregister_device(&shost->shost_gendev);
class_device_unregister(&shost->shost_classdev); class_device_unregister(&shost->shost_classdev);
...@@ -115,7 +190,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) ...@@ -115,7 +190,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
if (error) if (error)
goto out; goto out;
set_bit(SHOST_ADD, &shost->shost_state); scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent); get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev); 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,6 +301,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
spin_lock_init(&shost->default_lock); spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock); scsi_assign_lock(shost, &shost->default_lock);
shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices); INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets); INIT_LIST_HEAD(&shost->__targets);
INIT_LIST_HEAD(&shost->eh_cmd_q); INIT_LIST_HEAD(&shost->eh_cmd_q);
...@@ -382,7 +458,7 @@ EXPORT_SYMBOL(scsi_host_lookup); ...@@ -382,7 +458,7 @@ EXPORT_SYMBOL(scsi_host_lookup);
**/ **/
struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) 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)) !get_device(&shost->shost_gendev))
return NULL; return NULL;
return shost; return shost;
......
...@@ -627,7 +627,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) ...@@ -627,7 +627,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
spin_lock_irqsave(host->host_lock, flags); spin_lock_irqsave(host->host_lock, flags);
scsi_cmd_get_serial(host, cmd); 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); cmd->result = (DID_NO_CONNECT << 16);
scsi_done(cmd); scsi_done(cmd);
} else { } else {
......
...@@ -75,7 +75,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) ...@@ -75,7 +75,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
scmd->eh_eflags |= eh_flag; scmd->eh_eflags |= eh_flag;
list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); 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++; shost->host_failed++;
scsi_eh_wakeup(shost); scsi_eh_wakeup(shost);
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
...@@ -197,7 +197,8 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) ...@@ -197,7 +197,8 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev)
{ {
int online; 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); online = scsi_device_online(sdev);
...@@ -1458,7 +1459,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost) ...@@ -1458,7 +1459,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
__FUNCTION__)); __FUNCTION__));
clear_bit(SHOST_RECOVERY, &shost->shost_state); scsi_host_set_state(shost, SHOST_RUNNING);
wake_up(&shost->host_wait); wake_up(&shost->host_wait);
......
...@@ -475,8 +475,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, ...@@ -475,8 +475,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
* error processing, as long as the device was opened * error processing, as long as the device was opened
* non-blocking */ * non-blocking */
if (filp && filp->f_flags & O_NONBLOCK) { if (filp && filp->f_flags & O_NONBLOCK) {
if (test_bit(SHOST_RECOVERY, if (sdev->host->shost_state == SHOST_RECOVERY)
&sdev->host->shost_state))
return -ENODEV; return -ENODEV;
} else if (!scsi_block_when_processing_errors(sdev)) } else if (!scsi_block_when_processing_errors(sdev))
return -ENODEV; return -ENODEV;
......
...@@ -348,7 +348,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) ...@@ -348,7 +348,7 @@ void scsi_device_unbusy(struct scsi_device *sdev)
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
shost->host_busy--; shost->host_busy--;
if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) && if (unlikely((shost->shost_state == SHOST_RECOVERY) &&
shost->host_failed)) shost->host_failed))
scsi_eh_wakeup(shost); scsi_eh_wakeup(shost);
spin_unlock(shost->host_lock); spin_unlock(shost->host_lock);
...@@ -1207,7 +1207,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q, ...@@ -1207,7 +1207,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
struct Scsi_Host *shost, struct Scsi_Host *shost,
struct scsi_device *sdev) struct scsi_device *sdev)
{ {
if (test_bit(SHOST_RECOVERY, &shost->shost_state)) if (shost->shost_state == SHOST_RECOVERY)
return 0; return 0;
if (shost->host_busy == 0 && shost->host_blocked) { if (shost->host_busy == 0 && shost->host_blocked) {
/* /*
......
...@@ -48,6 +48,30 @@ const char *scsi_device_state_name(enum scsi_device_state state) ...@@ -48,6 +48,30 @@ const char *scsi_device_state_name(enum scsi_device_state state)
return name; 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) static int check_set(unsigned int *val, char *src)
{ {
char *last; char *last;
...@@ -124,6 +148,43 @@ static ssize_t store_scan(struct class_device *class_dev, const char *buf, ...@@ -124,6 +148,43 @@ static ssize_t store_scan(struct class_device *class_dev, const char *buf,
}; };
static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); 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(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n"); shost_rd_attr(cmd_per_lun, "%hd\n");
...@@ -139,6 +200,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { ...@@ -139,6 +200,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_unchecked_isa_dma, &class_device_attr_unchecked_isa_dma,
&class_device_attr_proc_name, &class_device_attr_proc_name,
&class_device_attr_scan, &class_device_attr_scan,
&class_device_attr_state,
NULL NULL
}; };
......
...@@ -1027,8 +1027,7 @@ sg_ioctl(struct inode *inode, struct file *filp, ...@@ -1027,8 +1027,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
if (sdp->detached) if (sdp->detached)
return -ENODEV; return -ENODEV;
if (filp->f_flags & O_NONBLOCK) { if (filp->f_flags & O_NONBLOCK) {
if (test_bit(SHOST_RECOVERY, if (sdp->device->host->shost_state == SHOST_RECOVERY)
&sdp->device->host->shost_state))
return -EBUSY; return -EBUSY;
} else if (!scsi_block_when_processing_errors(sdp->device)) } else if (!scsi_block_when_processing_errors(sdp->device))
return -EBUSY; return -EBUSY;
......
...@@ -429,12 +429,15 @@ struct scsi_host_template { ...@@ -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 { enum scsi_host_state {
SHOST_ADD, SHOST_CREATED = 1,
SHOST_DEL, SHOST_RUNNING,
SHOST_CANCEL, SHOST_CANCEL,
SHOST_DEL,
SHOST_RECOVERY, SHOST_RECOVERY,
}; };
...@@ -575,7 +578,7 @@ struct Scsi_Host { ...@@ -575,7 +578,7 @@ struct Scsi_Host {
unsigned int irq; unsigned int irq;
unsigned long shost_state; enum scsi_host_state shost_state;
/* ldm bits */ /* ldm bits */
struct device shost_gendev; struct device shost_gendev;
...@@ -633,6 +636,7 @@ extern void scsi_remove_host(struct Scsi_Host *); ...@@ -633,6 +636,7 @@ extern void scsi_remove_host(struct Scsi_Host *);
extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *); extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *);
extern void scsi_host_put(struct Scsi_Host *t); extern void scsi_host_put(struct Scsi_Host *t);
extern struct Scsi_Host *scsi_host_lookup(unsigned short); 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 *); extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment