mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 08:31:55 +00:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
This commit is contained in:
commit
d5ea4e2660
@ -400,6 +400,35 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
|
||||
return found_target;
|
||||
}
|
||||
|
||||
struct work_queue_wrapper {
|
||||
struct work_struct work;
|
||||
struct scsi_target *starget;
|
||||
};
|
||||
|
||||
static void scsi_target_reap_work(void *data) {
|
||||
struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
|
||||
struct scsi_target *starget = wqw->starget;
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
unsigned long flags;
|
||||
|
||||
kfree(wqw);
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
|
||||
if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
|
||||
list_del_init(&starget->siblings);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
device_del(&starget->dev);
|
||||
transport_unregister_device(&starget->dev);
|
||||
put_device(&starget->dev);
|
||||
return;
|
||||
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* scsi_target_reap - check to see if target is in use and destroy if not
|
||||
*
|
||||
@ -411,19 +440,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
|
||||
*/
|
||||
void scsi_target_reap(struct scsi_target *starget)
|
||||
{
|
||||
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
struct work_queue_wrapper *wqw =
|
||||
kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC);
|
||||
|
||||
if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
|
||||
list_del_init(&starget->siblings);
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
device_del(&starget->dev);
|
||||
transport_unregister_device(&starget->dev);
|
||||
put_device(&starget->dev);
|
||||
if (!wqw) {
|
||||
starget_printk(KERN_ERR, starget,
|
||||
"Failed to allocate memory in scsi_reap_target()\n");
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
INIT_WORK(&wqw->work, scsi_target_reap_work, wqw);
|
||||
wqw->starget = starget;
|
||||
schedule_work(&wqw->work);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,6 +105,7 @@ static struct {
|
||||
{ FC_PORTSTATE_LINKDOWN, "Linkdown" },
|
||||
{ FC_PORTSTATE_ERROR, "Error" },
|
||||
{ FC_PORTSTATE_LOOPBACK, "Loopback" },
|
||||
{ FC_PORTSTATE_DELETED, "Deleted" },
|
||||
};
|
||||
fc_enum_name_search(port_state, fc_port_state, fc_port_state_names)
|
||||
#define FC_PORTSTATE_MAX_NAMELEN 20
|
||||
@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
|
||||
#define FC_MGMTSRVR_PORTID 0x00000a
|
||||
|
||||
|
||||
static void fc_shost_remove_rports(void *data);
|
||||
static void fc_timeout_deleted_rport(void *data);
|
||||
static void fc_scsi_scan_rport(void *data);
|
||||
static void fc_rport_terminate(struct fc_rport *rport);
|
||||
@ -318,6 +320,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
|
||||
fc_host_next_rport_number(shost) = 0;
|
||||
fc_host_next_target_id(shost) = 0;
|
||||
|
||||
fc_host_flags(shost) = 0;
|
||||
INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \
|
||||
struct fc_internal *i = to_fc_internal(shost->transportt); \
|
||||
if ((i->f->get_rport_##field) && \
|
||||
!((rport->port_state == FC_PORTSTATE_BLOCKED) || \
|
||||
(rport->port_state == FC_PORTSTATE_DELETED) || \
|
||||
(rport->port_state == FC_PORTSTATE_NOTPRESENT))) \
|
||||
i->f->get_rport_##field(rport); \
|
||||
return snprintf(buf, sz, format_string, cast rport->field); \
|
||||
@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \
|
||||
struct Scsi_Host *shost = rport_to_shost(rport); \
|
||||
struct fc_internal *i = to_fc_internal(shost->transportt); \
|
||||
if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
|
||||
(rport->port_state == FC_PORTSTATE_DELETED) || \
|
||||
(rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
|
||||
return -EBUSY; \
|
||||
val = simple_strtoul(buf, NULL, 0); \
|
||||
@ -519,6 +525,7 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf,
|
||||
struct Scsi_Host *shost = rport_to_shost(rport);
|
||||
struct fc_internal *i = to_fc_internal(shost->transportt);
|
||||
if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
|
||||
(rport->port_state == FC_PORTSTATE_DELETED) ||
|
||||
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
|
||||
return -EBUSY;
|
||||
val = simple_strtoul(buf, NULL, 0);
|
||||
@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data)
|
||||
rport->maxframe_size = -1;
|
||||
rport->supported_classes = FC_COS_UNSPECIFIED;
|
||||
rport->roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
rport->port_state = FC_PORTSTATE_NOTPRESENT;
|
||||
rport->port_state = FC_PORTSTATE_DELETED;
|
||||
|
||||
/* remove the identifiers that aren't used in the consisting binding */
|
||||
switch (fc_host_tgtid_bind_type(shost)) {
|
||||
@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
/*
|
||||
* As this only occurs if the remote port (scsi target)
|
||||
* went away and didn't come back - we'll remove
|
||||
* all attached scsi devices.
|
||||
*
|
||||
* We'll schedule the shost work item to perform the actual removal
|
||||
* to avoid recursion in the different flush calls if we perform
|
||||
* the removal in each target - and there are lots of targets
|
||||
* whose timeouts fire at the same time.
|
||||
*/
|
||||
fc_rport_tgt_remove(rport);
|
||||
|
||||
if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) {
|
||||
fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED;
|
||||
scsi_queue_work(shost, &fc_host_rport_del_work(shost));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1818,6 +1834,41 @@ fc_scsi_scan_rport(void *data)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fc_shost_remove_rports - called to remove all rports that are marked
|
||||
* as in a deleted (not connected) state.
|
||||
*
|
||||
* @data: shost whose rports are to be looked at
|
||||
**/
|
||||
static void
|
||||
fc_shost_remove_rports(void *data)
|
||||
{
|
||||
struct Scsi_Host *shost = (struct Scsi_Host *)data;
|
||||
struct fc_rport *rport, *next_rport;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) {
|
||||
|
||||
fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED;
|
||||
|
||||
restart_search:
|
||||
list_for_each_entry_safe(rport, next_rport,
|
||||
&fc_host_rport_bindings(shost), peers) {
|
||||
if (rport->port_state == FC_PORTSTATE_DELETED) {
|
||||
rport->port_state = FC_PORTSTATE_NOTPRESENT;
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
fc_rport_tgt_remove(rport);
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
goto restart_search;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
MODULE_AUTHOR("Martin Hicks");
|
||||
MODULE_DESCRIPTION("FC Transport Attributes");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -79,6 +79,7 @@ enum fc_port_state {
|
||||
FC_PORTSTATE_LINKDOWN,
|
||||
FC_PORTSTATE_ERROR,
|
||||
FC_PORTSTATE_LOOPBACK,
|
||||
FC_PORTSTATE_DELETED,
|
||||
};
|
||||
|
||||
|
||||
@ -325,8 +326,14 @@ struct fc_host_attrs {
|
||||
struct list_head rport_bindings;
|
||||
u32 next_rport_number;
|
||||
u32 next_target_id;
|
||||
u8 flags;
|
||||
struct work_struct rport_del_work;
|
||||
};
|
||||
|
||||
/* values for struct fc_host_attrs "flags" field: */
|
||||
#define FC_SHOST_RPORT_DEL_SCHEDULED 0x01
|
||||
|
||||
|
||||
#define fc_host_node_name(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->node_name)
|
||||
#define fc_host_port_name(x) \
|
||||
@ -365,6 +372,10 @@ struct fc_host_attrs {
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
|
||||
#define fc_host_next_target_id(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
|
||||
#define fc_host_flags(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->flags)
|
||||
#define fc_host_rport_del_work(x) \
|
||||
(((struct fc_host_attrs *)(x)->shost_data)->rport_del_work)
|
||||
|
||||
|
||||
/* The functions by which the transport class and the driver communicate */
|
||||
|
Loading…
Reference in New Issue
Block a user