* [PATCH 0/5] scsi host / scsi target state model update @ 2005-06-16 18:10 Mike Anderson 2005-06-16 18:12 ` [PATCH 1/5] " Mike Anderson 0 siblings, 1 reply; 7+ messages in thread From: Mike Anderson @ 2005-06-16 18:10 UTC (permalink / raw) To: linux-scsi 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 andmike@us.ibm.com ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/5] scsi host / scsi target state model update 2005-06-16 18:10 [PATCH 0/5] scsi host / scsi target state model update Mike Anderson @ 2005-06-16 18:12 ` Mike Anderson 2005-06-16 18:13 ` [PATCH 2/5] " Mike Anderson 0 siblings, 1 reply; 7+ messages in thread From: Mike Anderson @ 2005-06-16 18:12 UTC (permalink / raw) To: linux-scsi Migrate the current SCSI host state model to a model like SCSI device is using. Signed-off-by: Mike Anderson <andmike@us.ibm.com> --- 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(-) diff -puN include/scsi/scsi_host.h~host_state include/scsi/scsi_host.h --- linux-2.6.12-rc6-mm1/include/scsi/scsi_host.h~host_state 2005-06-10 15:32:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/include/scsi/scsi_host.h 2005-06-16 10:27:40.000000000 -0700 @@ -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 *); diff -puN drivers/scsi/scsi_sysfs.c~host_state drivers/scsi/scsi_sysfs.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_sysfs.c~host_state 2005-06-10 15:32:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_sysfs.c 2005-06-16 10:27:38.000000000 -0700 @@ -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 -puN drivers/scsi/hosts.c~host_state drivers/scsi/hosts.c --- linux-2.6.12-rc6-mm1/drivers/scsi/hosts.c~host_state 2005-06-10 15:32:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/hosts.c 2005-06-16 10:34:22.000000000 -0700 @@ -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); @@ -231,6 +306,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); @@ -387,7 +463,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 -puN drivers/scsi/scsi.c~host_state drivers/scsi/scsi.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi.c~host_state 2005-06-10 15:32:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi.c 2005-06-16 10:27:42.000000000 -0700 @@ -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 { diff -puN drivers/scsi/scsi_error.c~host_state drivers/scsi/scsi_error.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_error.c~host_state 2005-06-16 10:34:33.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_error.c 2005-06-16 10:38:04.000000000 -0700 @@ -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); diff -puN drivers/scsi/scsi_ioctl.c~host_state drivers/scsi/scsi_ioctl.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_ioctl.c~host_state 2005-06-16 10:38:28.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_ioctl.c 2005-06-16 10:39:26.000000000 -0700 @@ -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 -puN drivers/scsi/scsi_lib.c~host_state drivers/scsi/scsi_lib.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_lib.c~host_state 2005-06-16 10:39:38.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_lib.c 2005-06-16 10:41:22.000000000 -0700 @@ -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) { /* diff -puN drivers/scsi/sg.c~host_state drivers/scsi/sg.c --- linux-2.6.12-rc6-mm1/drivers/scsi/sg.c~host_state 2005-06-16 10:41:42.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/sg.c 2005-06-16 10:42:17.000000000 -0700 @@ -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; _ ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/5] scsi host / scsi target state model update 2005-06-16 18:12 ` [PATCH 1/5] " Mike Anderson @ 2005-06-16 18:13 ` Mike Anderson 2005-06-16 18:14 ` [PATCH 3/5] " Mike Anderson 0 siblings, 1 reply; 7+ messages in thread From: Mike Anderson @ 2005-06-16 18:13 UTC (permalink / raw) To: linux-scsi 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. Signed-off-by: Mike Anderson <andmike@us.ibm.com> --- 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(-) diff -puN drivers/scsi/hosts.c~host_cancel drivers/scsi/hosts.c --- linux-2.6.12-rc6-mm1/drivers/scsi/hosts.c~host_cancel 2005-06-16 10:43:44.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/hosts.c 2005-06-16 10:45:21.000000000 -0700 @@ -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); diff -puN drivers/scsi/scsi.c~host_cancel drivers/scsi/scsi.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi.c~host_cancel 2005-06-16 10:43:44.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi.c 2005-06-16 10:43:44.000000000 -0700 @@ -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 { _ ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/5] scsi host / scsi target state model update 2005-06-16 18:13 ` [PATCH 2/5] " Mike Anderson @ 2005-06-16 18:14 ` Mike Anderson 2005-06-16 18:15 ` [PATCH 4/5] " Mike Anderson 0 siblings, 1 reply; 7+ messages in thread From: Mike Anderson @ 2005-06-16 18:14 UTC (permalink / raw) To: linux-scsi Add support to not allow additions to a host when it is being removed. Signed-off-by: Mike Anderson <andmike@us.ibm.com> --- 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(-) diff -puN drivers/scsi/hosts.c~host_scan drivers/scsi/hosts.c --- linux-2.6.12-rc6-mm1/drivers/scsi/hosts.c~host_scan 2005-06-16 10:47:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/hosts.c 2005-06-16 10:47:17.000000000 -0700 @@ -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); diff -puN include/scsi/scsi_host.h~host_scan include/scsi/scsi_host.h --- linux-2.6.12-rc6-mm1/include/scsi/scsi_host.h~host_scan 2005-06-16 10:47:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/include/scsi/scsi_host.h 2005-06-16 10:47:17.000000000 -0700 @@ -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 *); diff -puN drivers/scsi/scsi_scan.c~host_scan drivers/scsi/scsi_scan.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_scan.c~host_scan 2005-06-16 10:47:17.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_scan.c 2005-06-16 10:47:17.000000000 -0700 @@ -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; _ ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/5] scsi host / scsi target state model update 2005-06-16 18:14 ` [PATCH 3/5] " Mike Anderson @ 2005-06-16 18:15 ` Mike Anderson 2005-06-16 18:16 ` [PATCH 5/5] " Mike Anderson 2005-07-12 16:44 ` [PATCH 4/5] " James Bottomley 0 siblings, 2 replies; 7+ messages in thread From: Mike Anderson @ 2005-06-16 18:15 UTC (permalink / raw) To: linux-scsi Add a SCSI target state model similar to the SCSI device state model. Signed-off-by: Mike Anderson <andmike@us.ibm.com> --- 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(+) diff -puN include/scsi/scsi_device.h~tgt_state include/scsi/scsi_device.h --- linux-2.6.12-rc6-mm1/include/scsi/scsi_device.h~tgt_state 2005-06-16 10:47:35.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/include/scsi/scsi_device.h 2005-06-16 10:47:35.000000000 -0700 @@ -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 *); diff -puN drivers/scsi/scsi_lib.c~tgt_state drivers/scsi/scsi_lib.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_lib.c~tgt_state 2005-06-16 10:47:35.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_lib.c 2005-06-16 10:47:35.000000000 -0700 @@ -1819,6 +1819,63 @@ scsi_device_set_state(struct scsi_device EXPORT_SYMBOL(scsi_device_set_state); /** + * scsi_target_set_state - Take the given target through the target + * state model. + * @starget: scsi target 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_target_set_state(struct scsi_target *starget, enum scsi_target_state state) +{ + enum scsi_target_state oldstate = starget->stgt_state; + + if (state == oldstate) + return 0; + + switch (state) { + case STGT_RUNNING: + /* There are no legal states that come back to + * created. This is the manually initialised start + * state */ + goto illegal; + + case STGT_CANCEL: + switch (oldstate) { + case STGT_RUNNING: + break; + default: + goto illegal; + } + break; + + case STGT_DEL: + switch (oldstate) { + case STGT_CANCEL: + break; + default: + goto illegal; + } + break; + + } + starget->stgt_state = state; + return 0; + + illegal: + SCSI_LOG_ERROR_RECOVERY(1, + dev_printk(KERN_ERR, &starget->dev, + "Illegal state transition %s->%s\n", + scsi_target_state_name(oldstate), + scsi_target_state_name(state)) + ); + return -EINVAL; +} +EXPORT_SYMBOL(scsi_target_set_state); + +/** * scsi_device_quiesce - Block user issued commands. * @sdev: scsi device to quiesce. * diff -puN drivers/scsi/scsi_sysfs.c~tgt_state drivers/scsi/scsi_sysfs.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_sysfs.c~tgt_state 2005-06-16 10:47:35.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_sysfs.c 2005-06-16 10:47:35.000000000 -0700 @@ -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[] = { diff -puN drivers/scsi/scsi_scan.c~tgt_state drivers/scsi/scsi_scan.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_scan.c~tgt_state 2005-06-16 10:47:35.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_scan.c 2005-06-16 10:47:35.000000000 -0700 @@ -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 */ _ ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 5/5] scsi host / scsi target state model update 2005-06-16 18:15 ` [PATCH 4/5] " Mike Anderson @ 2005-06-16 18:16 ` Mike Anderson 2005-07-12 16:44 ` [PATCH 4/5] " James Bottomley 1 sibling, 0 replies; 7+ messages in thread From: Mike Anderson @ 2005-06-16 18:16 UTC (permalink / raw) To: linux-scsi Use new SCSI target state model in scsi_forget_host to help with list traversal and deletion of devices. Signed-off-by: Mike Anderson <andmike@us.ibm.com> --- 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(-) diff -puN drivers/scsi/scsi_scan.c~tgt_remove drivers/scsi/scsi_scan.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_scan.c~tgt_remove 2005-06-16 10:48:38.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_scan.c 2005-06-16 10:48:38.000000000 -0700 @@ -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); } /* diff -puN drivers/scsi/scsi_sysfs.c~tgt_remove drivers/scsi/scsi_sysfs.c --- linux-2.6.12-rc6-mm1/drivers/scsi/scsi_sysfs.c~tgt_remove 2005-06-16 10:48:38.000000000 -0700 +++ linux-2.6.12-rc6-mm1-andmike/drivers/scsi/scsi_sysfs.c 2005-06-16 10:48:38.000000000 -0700 @@ -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); } _ ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 4/5] scsi host / scsi target state model update 2005-06-16 18:15 ` [PATCH 4/5] " Mike Anderson 2005-06-16 18:16 ` [PATCH 5/5] " Mike Anderson @ 2005-07-12 16:44 ` James Bottomley 1 sibling, 0 replies; 7+ messages in thread From: James Bottomley @ 2005-07-12 16:44 UTC (permalink / raw) To: Mike Anderson; +Cc: SCSI Mailing List On Thu, 2005-06-16 at 11:15 -0700, Mike Anderson wrote: > 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 ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2005-07-12 17:51 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-06-16 18:10 [PATCH 0/5] scsi host / scsi target state model update Mike Anderson 2005-06-16 18:12 ` [PATCH 1/5] " Mike Anderson 2005-06-16 18:13 ` [PATCH 2/5] " Mike Anderson 2005-06-16 18:14 ` [PATCH 3/5] " Mike Anderson 2005-06-16 18:15 ` [PATCH 4/5] " Mike Anderson 2005-06-16 18:16 ` [PATCH 5/5] " Mike Anderson 2005-07-12 16:44 ` [PATCH 4/5] " James Bottomley
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox