Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d5ea4e26
Commit
d5ea4e26
authored
Dec 21, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
parents
c7ac6b42
863a930a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
104 additions
and
14 deletions
+104
-14
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_scan.c
+38
-10
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_fc.c
+55
-4
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_fc.h
+11
-0
No files found.
drivers/scsi/scsi_scan.c
View file @
d5ea4e26
...
@@ -400,6 +400,35 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
...
@@ -400,6 +400,35 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
return
found_target
;
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
* 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,
...
@@ -411,19 +440,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
*/
*/
void
scsi_target_reap
(
struct
scsi_target
*
starget
)
void
scsi_target_reap
(
struct
scsi_target
*
starget
)
{
{
struct
Scsi_Host
*
shost
=
dev_to_shost
(
starget
->
dev
.
parent
);
struct
work_queue_wrapper
*
wqw
=
unsigned
long
flags
;
kzalloc
(
sizeof
(
struct
work_queue_wrapper
),
GFP_ATOMIC
);
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
if
(
--
starget
->
reap_ref
==
0
&&
list_empty
(
&
starget
->
devices
))
{
if
(
!
wqw
)
{
list_del_init
(
&
starget
->
siblings
);
starget_printk
(
KERN_ERR
,
starget
,
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
"Failed to allocate memory in scsi_reap_target()
\n
"
);
device_del
(
&
starget
->
dev
);
transport_unregister_device
(
&
starget
->
dev
);
put_device
(
&
starget
->
dev
);
return
;
return
;
}
}
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
INIT_WORK
(
&
wqw
->
work
,
scsi_target_reap_work
,
wqw
);
wqw
->
starget
=
starget
;
schedule_work
(
&
wqw
->
work
);
}
}
/**
/**
...
...
drivers/scsi/scsi_transport_fc.c
View file @
d5ea4e26
...
@@ -105,6 +105,7 @@ static struct {
...
@@ -105,6 +105,7 @@ static struct {
{
FC_PORTSTATE_LINKDOWN
,
"Linkdown"
},
{
FC_PORTSTATE_LINKDOWN
,
"Linkdown"
},
{
FC_PORTSTATE_ERROR
,
"Error"
},
{
FC_PORTSTATE_ERROR
,
"Error"
},
{
FC_PORTSTATE_LOOPBACK
,
"Loopback"
},
{
FC_PORTSTATE_LOOPBACK
,
"Loopback"
},
{
FC_PORTSTATE_DELETED
,
"Deleted"
},
};
};
fc_enum_name_search
(
port_state
,
fc_port_state
,
fc_port_state_names
)
fc_enum_name_search
(
port_state
,
fc_port_state
,
fc_port_state_names
)
#define FC_PORTSTATE_MAX_NAMELEN 20
#define FC_PORTSTATE_MAX_NAMELEN 20
...
@@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
...
@@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
#define FC_MGMTSRVR_PORTID 0x00000a
#define FC_MGMTSRVR_PORTID 0x00000a
static
void
fc_shost_remove_rports
(
void
*
data
);
static
void
fc_timeout_deleted_rport
(
void
*
data
);
static
void
fc_timeout_deleted_rport
(
void
*
data
);
static
void
fc_scsi_scan_rport
(
void
*
data
);
static
void
fc_scsi_scan_rport
(
void
*
data
);
static
void
fc_rport_terminate
(
struct
fc_rport
*
rport
);
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,
...
@@ -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_rport_number
(
shost
)
=
0
;
fc_host_next_target_id
(
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
;
return
0
;
}
}
...
@@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \
...
@@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \
struct fc_internal *i = to_fc_internal(shost->transportt); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
if ((i->f->get_rport_##field) && \
if ((i->f->get_rport_##field) && \
!((rport->port_state == FC_PORTSTATE_BLOCKED) || \
!((rport->port_state == FC_PORTSTATE_BLOCKED) || \
(rport->port_state == FC_PORTSTATE_DELETED) || \
(rport->port_state == FC_PORTSTATE_NOTPRESENT))) \
(rport->port_state == FC_PORTSTATE_NOTPRESENT))) \
i->f->get_rport_##field(rport); \
i->f->get_rport_##field(rport); \
return snprintf(buf, sz, format_string, cast rport->field); \
return snprintf(buf, sz, format_string, cast rport->field); \
...
@@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \
...
@@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \
struct Scsi_Host *shost = rport_to_shost(rport); \
struct Scsi_Host *shost = rport_to_shost(rport); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
(rport->port_state == FC_PORTSTATE_DELETED) || \
(rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
(rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
return -EBUSY; \
return -EBUSY; \
val = simple_strtoul(buf, NULL, 0); \
val = simple_strtoul(buf, NULL, 0); \
...
@@ -519,6 +525,7 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf,
...
@@ -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
Scsi_Host
*
shost
=
rport_to_shost
(
rport
);
struct
fc_internal
*
i
=
to_fc_internal
(
shost
->
transportt
);
struct
fc_internal
*
i
=
to_fc_internal
(
shost
->
transportt
);
if
((
rport
->
port_state
==
FC_PORTSTATE_BLOCKED
)
||
if
((
rport
->
port_state
==
FC_PORTSTATE_BLOCKED
)
||
(
rport
->
port_state
==
FC_PORTSTATE_DELETED
)
||
(
rport
->
port_state
==
FC_PORTSTATE_NOTPRESENT
))
(
rport
->
port_state
==
FC_PORTSTATE_NOTPRESENT
))
return
-
EBUSY
;
return
-
EBUSY
;
val
=
simple_strtoul
(
buf
,
NULL
,
0
);
val
=
simple_strtoul
(
buf
,
NULL
,
0
);
...
@@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data)
...
@@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data)
rport
->
maxframe_size
=
-
1
;
rport
->
maxframe_size
=
-
1
;
rport
->
supported_classes
=
FC_COS_UNSPECIFIED
;
rport
->
supported_classes
=
FC_COS_UNSPECIFIED
;
rport
->
roles
=
FC_RPORT_ROLE_UNKNOWN
;
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 */
/* remove the identifiers that aren't used in the consisting binding */
switch
(
fc_host_tgtid_bind_type
(
shost
))
{
switch
(
fc_host_tgtid_bind_type
(
shost
))
{
...
@@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data)
...
@@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data)
break
;
break
;
}
}
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
/*
/*
* As this only occurs if the remote port (scsi target)
* As this only occurs if the remote port (scsi target)
* went away and didn't come back - we'll remove
* went away and didn't come back - we'll remove
* all attached scsi devices.
* 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)
...
@@ -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_AUTHOR
(
"Martin Hicks"
);
MODULE_DESCRIPTION
(
"FC Transport Attributes"
);
MODULE_DESCRIPTION
(
"FC Transport Attributes"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
...
...
include/scsi/scsi_transport_fc.h
View file @
d5ea4e26
...
@@ -79,6 +79,7 @@ enum fc_port_state {
...
@@ -79,6 +79,7 @@ enum fc_port_state {
FC_PORTSTATE_LINKDOWN
,
FC_PORTSTATE_LINKDOWN
,
FC_PORTSTATE_ERROR
,
FC_PORTSTATE_ERROR
,
FC_PORTSTATE_LOOPBACK
,
FC_PORTSTATE_LOOPBACK
,
FC_PORTSTATE_DELETED
,
};
};
...
@@ -325,8 +326,14 @@ struct fc_host_attrs {
...
@@ -325,8 +326,14 @@ struct fc_host_attrs {
struct
list_head
rport_bindings
;
struct
list_head
rport_bindings
;
u32
next_rport_number
;
u32
next_rport_number
;
u32
next_target_id
;
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) \
#define fc_host_node_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->node_name)
(((struct fc_host_attrs *)(x)->shost_data)->node_name)
#define fc_host_port_name(x) \
#define fc_host_port_name(x) \
...
@@ -365,6 +372,10 @@ struct fc_host_attrs {
...
@@ -365,6 +372,10 @@ struct fc_host_attrs {
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
#define fc_host_next_target_id(x) \
#define fc_host_next_target_id(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
(((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 */
/* The functions by which the transport class and the driver communicate */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment