scsi host / scsi target state model update
Subsystems (2)
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]
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
@@ -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 Scsiextern 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
@@ -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
@@ -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(struSCSI_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
@@ -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
@@ -357,7 +357,7 @@ void scsi_device_unbusy(struct scsi_devispin_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
@@ -1027,8 +1027,7 @@ sg_ioctl(struct inode *inode, struct filif (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 ;
_
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
@@ -128,29 +128,13 @@ int scsi_host_set_state(struct Scsi_HostEXPORT_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
@@ -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 {
_
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
@@ -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
@@ -656,6 +656,15 @@ static inline struct device *scsi_get_dereturn 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
@@ -1218,9 +1218,12 @@ struct scsi_device *__scsi_add_device(stget_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 ;
_
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
@@ -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
@@ -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
@@ -361,6 +361,7 @@ static struct scsi_target *scsi_alloc_taif (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 */
_
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
@@ -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
@@ -750,6 +750,7 @@ void __scsi_remove_target(struct scsi_tascsi_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); }
_
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