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
nexedi
linux
Commits
fd0a1c61
Commit
fd0a1c61
authored
Sep 30, 2002
by
James Bottomley
Browse files
Options
Browse Files
Download
Plain Diff
Merge mulgrave.(none):/home/jejb/BK/linux-2.5
into mulgrave.(none):/home/jejb/BK/scsi-for-linus-2.5
parents
1c6232c3
9b46c836
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1267 additions
and
1553 deletions
+1267
-1553
drivers/scsi/53c700.c
drivers/scsi/53c700.c
+1
-0
drivers/scsi/hosts.c
drivers/scsi/hosts.c
+42
-0
drivers/scsi/hosts.h
drivers/scsi/hosts.h
+7
-0
drivers/scsi/scsi.c
drivers/scsi/scsi.c
+6
-53
drivers/scsi/scsi.h
drivers/scsi/scsi.h
+23
-1
drivers/scsi/scsi_error.c
drivers/scsi/scsi_error.c
+1158
-1494
drivers/scsi/scsi_merge.c
drivers/scsi/scsi_merge.c
+1
-1
drivers/scsi/sg.c
drivers/scsi/sg.c
+23
-3
include/scsi/sg.h
include/scsi/sg.h
+6
-1
No files found.
drivers/scsi/53c700.c
View file @
fd0a1c61
...
@@ -284,6 +284,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
...
@@ -284,6 +284,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
tpnt
->
use_clustering
=
DISABLE_CLUSTERING
;
tpnt
->
use_clustering
=
DISABLE_CLUSTERING
;
tpnt
->
proc_info
=
NCR_700_proc_directory_info
;
tpnt
->
proc_info
=
NCR_700_proc_directory_info
;
tpnt
->
use_blk_tcq
=
1
;
tpnt
->
use_blk_tcq
=
1
;
tpnt
->
highmem_io
=
1
;
if
(
tpnt
->
name
==
NULL
)
if
(
tpnt
->
name
==
NULL
)
tpnt
->
name
=
"53c700"
;
tpnt
->
name
=
"53c700"
;
...
...
drivers/scsi/hosts.c
View file @
fd0a1c61
...
@@ -259,6 +259,48 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
...
@@ -259,6 +259,48 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
return
retval
;
return
retval
;
}
}
void
scsi_host_busy_inc
(
struct
Scsi_Host
*
shost
,
Scsi_Device
*
sdev
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
shost
->
host_busy
++
;
sdev
->
device_busy
++
;
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
}
void
scsi_host_busy_dec_and_test
(
struct
Scsi_Host
*
shost
,
Scsi_Device
*
sdev
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
shost
->
host_busy
--
;
sdev
->
device_busy
--
;
if
(
shost
->
in_recovery
&&
(
shost
->
host_busy
==
shost
->
host_failed
))
{
up
(
shost
->
eh_wait
);
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Waking error handler"
"thread (%d)
\n
"
,
atomic_read
(
&
shost
->
eh_wait
->
count
)));
}
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
}
void
scsi_host_failed_inc_and_test
(
struct
Scsi_Host
*
shost
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
shost
->
in_recovery
=
1
;
shost
->
host_failed
++
;
if
(
shost
->
host_busy
==
shost
->
host_failed
)
{
up
(
shost
->
eh_wait
);
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Waking error handler"
"thread (%d)
\n
"
,
atomic_read
(
&
shost
->
eh_wait
->
count
)));
}
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
}
/*
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* Emacs will notice this stuff at the end of the file and automatically
...
...
drivers/scsi/hosts.h
View file @
fd0a1c61
...
@@ -543,6 +543,13 @@ extern int scsi_unregister_device(struct Scsi_Device_Template *);
...
@@ -543,6 +543,13 @@ extern int scsi_unregister_device(struct Scsi_Device_Template *);
extern
int
scsi_register_host
(
Scsi_Host_Template
*
);
extern
int
scsi_register_host
(
Scsi_Host_Template
*
);
extern
int
scsi_unregister_host
(
Scsi_Host_Template
*
);
extern
int
scsi_unregister_host
(
Scsi_Host_Template
*
);
/*
* host_busy inc/dec/test functions
*/
extern
void
scsi_host_busy_inc
(
struct
Scsi_Host
*
,
Scsi_Device
*
);
extern
void
scsi_host_busy_dec_and_test
(
struct
Scsi_Host
*
,
Scsi_Device
*
);
extern
void
scsi_host_failed_inc_and_test
(
struct
Scsi_Host
*
);
/*
/*
* This is an ugly hack. If we expect to be able to load devices at run time,
* This is an ugly hack. If we expect to be able to load devices at run time,
...
...
drivers/scsi/scsi.c
View file @
fd0a1c61
...
@@ -566,22 +566,6 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt)
...
@@ -566,22 +566,6 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt)
SCpnt
->
target
,
SCpnt
->
target
,
atomic_read
(
&
SCpnt
->
host
->
host_active
),
atomic_read
(
&
SCpnt
->
host
->
host_active
),
SCpnt
->
host
->
host_failed
));
SCpnt
->
host
->
host_failed
));
if
(
SCpnt
->
host
->
host_failed
!=
0
)
{
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Error handler thread %d %d
\n
"
,
SCpnt
->
host
->
in_recovery
,
SCpnt
->
host
->
eh_active
));
}
/*
* If the host is having troubles, then look to see if this was the last
* command that might have failed. If so, wake up the error handler.
*/
if
(
SCpnt
->
host
->
in_recovery
&&
!
SCpnt
->
host
->
eh_active
&&
SCpnt
->
host
->
host_busy
==
SCpnt
->
host
->
host_failed
)
{
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Waking error handler thread (%d)
\n
"
,
atomic_read
(
&
SCpnt
->
host
->
eh_wait
->
count
)));
up
(
SCpnt
->
host
->
eh_wait
);
}
spin_unlock_irqrestore
(
&
device_request_lock
,
flags
);
spin_unlock_irqrestore
(
&
device_request_lock
,
flags
);
...
@@ -1217,28 +1201,11 @@ void scsi_done(Scsi_Cmnd * SCpnt)
...
@@ -1217,28 +1201,11 @@ void scsi_done(Scsi_Cmnd * SCpnt)
* etc, etc.
* etc, etc.
*/
*/
if
(
!
tstatus
)
{
if
(
!
tstatus
)
{
SCpnt
->
done_late
=
1
;
return
;
return
;
}
}
/* Set the serial numbers back to zero */
/* Set the serial numbers back to zero */
SCpnt
->
serial_number
=
0
;
SCpnt
->
serial_number
=
0
;
/*
* First, see whether this command already timed out. If so, we ignore
* the response. We treat it as if the command never finished.
*
* Since serial_number is now 0, the error handler cound detect this
* situation and avoid to call the low level driver abort routine.
* (DB)
*
* FIXME(eric) - I believe that this test is now redundant, due to
* the test of the return status of del_timer().
*/
if
(
SCpnt
->
state
==
SCSI_STATE_TIMEOUT
)
{
SCSI_LOG_MLCOMPLETE
(
1
,
printk
(
"Ignoring completion of %p due to timeout status"
,
SCpnt
));
return
;
}
SCpnt
->
serial_number_at_timeout
=
0
;
SCpnt
->
serial_number_at_timeout
=
0
;
SCpnt
->
state
=
SCSI_STATE_BHQUEUE
;
SCpnt
->
state
=
SCSI_STATE_BHQUEUE
;
SCpnt
->
owner
=
SCSI_OWNER_BH_HANDLER
;
SCpnt
->
owner
=
SCSI_OWNER_BH_HANDLER
;
...
@@ -1349,21 +1316,11 @@ static void scsi_softirq(struct softirq_action *h)
...
@@ -1349,21 +1316,11 @@ static void scsi_softirq(struct softirq_action *h)
SCSI_LOG_MLCOMPLETE
(
3
,
print_sense
(
"bh"
,
SCpnt
));
SCSI_LOG_MLCOMPLETE
(
3
,
print_sense
(
"bh"
,
SCpnt
));
}
}
if
(
SCpnt
->
host
->
eh_wait
!=
NULL
)
{
if
(
SCpnt
->
host
->
eh_wait
!=
NULL
)
{
SCpnt
->
host
->
host_failed
++
;
scsi_eh_eflags_set
(
SCpnt
,
SCSI_EH_CMD_FAILED
|
SCSI_EH_CMD_ERR
)
;
SCpnt
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
SCpnt
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
SCpnt
->
state
=
SCSI_STATE_FAILED
;
SCpnt
->
state
=
SCSI_STATE_FAILED
;
SCpnt
->
host
->
in_recovery
=
1
;
/*
scsi_host_failed_inc_and_test
(
SCpnt
->
host
);
* If the host is having troubles, then
* look to see if this was the last
* command that might have failed. If
* so, wake up the error handler.
*/
if
(
SCpnt
->
host
->
host_busy
==
SCpnt
->
host
->
host_failed
)
{
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Waking error handler thread (%d)
\n
"
,
atomic_read
(
&
SCpnt
->
host
->
eh_wait
->
count
)));
up
(
SCpnt
->
host
->
eh_wait
);
}
}
else
{
}
else
{
/*
/*
* We only get here if the error
* We only get here if the error
...
@@ -1418,7 +1375,6 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
...
@@ -1418,7 +1375,6 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
struct
Scsi_Host
*
host
;
struct
Scsi_Host
*
host
;
Scsi_Device
*
device
;
Scsi_Device
*
device
;
Scsi_Request
*
SRpnt
;
Scsi_Request
*
SRpnt
;
unsigned
long
flags
;
host
=
SCpnt
->
host
;
host
=
SCpnt
->
host
;
device
=
SCpnt
->
device
;
device
=
SCpnt
->
device
;
...
@@ -1432,10 +1388,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
...
@@ -1432,10 +1388,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
* one execution context, but the device and host structures are
* one execution context, but the device and host structures are
* shared.
* shared.
*/
*/
spin_lock_irqsave
(
host
->
host_lock
,
flags
);
scsi_host_busy_dec_and_test
(
host
,
device
);
host
->
host_busy
--
;
/* Indicate that we are free */
device
->
device_busy
--
;
/* Decrement device usage counter. */
spin_unlock_irqrestore
(
host
->
host_lock
,
flags
);
/*
/*
* Clear the flags which say that the device/host is no longer
* Clear the flags which say that the device/host is no longer
...
@@ -1450,7 +1403,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
...
@@ -1450,7 +1403,7 @@ void scsi_finish_command(Scsi_Cmnd * SCpnt)
* If we have valid sense information, then some kind of recovery
* If we have valid sense information, then some kind of recovery
* must have taken place. Make a note of this.
* must have taken place. Make a note of this.
*/
*/
if
(
scsi_sense_valid
(
SCpnt
))
{
if
(
SCSI_SENSE_VALID
(
SCpnt
))
{
SCpnt
->
result
|=
(
DRIVER_SENSE
<<
24
);
SCpnt
->
result
|=
(
DRIVER_SENSE
<<
24
);
}
}
SCSI_LOG_MLCOMPLETE
(
3
,
printk
(
"Notifying upper driver of completion for device %d %x
\n
"
,
SCSI_LOG_MLCOMPLETE
(
3
,
printk
(
"Notifying upper driver of completion for device %d %x
\n
"
,
...
...
drivers/scsi/scsi.h
View file @
fd0a1c61
...
@@ -428,7 +428,6 @@ extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout,
...
@@ -428,7 +428,6 @@ extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout,
void
(
*
complete
)
(
Scsi_Cmnd
*
));
void
(
*
complete
)
(
Scsi_Cmnd
*
));
extern
int
scsi_delete_timer
(
Scsi_Cmnd
*
SCset
);
extern
int
scsi_delete_timer
(
Scsi_Cmnd
*
SCset
);
extern
void
scsi_error_handler
(
void
*
host
);
extern
void
scsi_error_handler
(
void
*
host
);
extern
int
scsi_sense_valid
(
Scsi_Cmnd
*
);
extern
int
scsi_decide_disposition
(
Scsi_Cmnd
*
SCpnt
);
extern
int
scsi_decide_disposition
(
Scsi_Cmnd
*
SCpnt
);
extern
int
scsi_block_when_processing_errors
(
Scsi_Device
*
);
extern
int
scsi_block_when_processing_errors
(
Scsi_Device
*
);
extern
void
scsi_sleep
(
int
);
extern
void
scsi_sleep
(
int
);
...
@@ -701,6 +700,7 @@ struct scsi_cmnd {
...
@@ -701,6 +700,7 @@ struct scsi_cmnd {
struct
scsi_cmnd
*
reset_chain
;
struct
scsi_cmnd
*
reset_chain
;
int
eh_state
;
/* Used for state tracking in error handlr */
int
eh_state
;
/* Used for state tracking in error handlr */
int
eh_eflags
;
/* Used by error handlr */
void
(
*
done
)
(
struct
scsi_cmnd
*
);
/* Mid-level done function */
void
(
*
done
)
(
struct
scsi_cmnd
*
);
/* Mid-level done function */
/*
/*
A SCSI Command is assigned a nonzero serial_number when internal_cmnd
A SCSI Command is assigned a nonzero serial_number when internal_cmnd
...
@@ -940,4 +940,26 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
...
@@ -940,4 +940,26 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
return
(
Scsi_Cmnd
*
)
req
->
special
;
return
(
Scsi_Cmnd
*
)
req
->
special
;
}
}
#define scsi_eh_eflags_chk(scp, flags) (scp->eh_eflags & flags)
#define scsi_eh_eflags_set(scp, flags) do { \
scp->eh_eflags |= flags; \
} while(0)
#define scsi_eh_eflags_clr(scp, flags) do { \
scp->eh_eflags &= ~flags; \
} while(0)
#define scsi_eh_eflags_clr_all(scp) (scp->eh_eflags = 0)
/*
* Scsi Error Handler Flags
*/
#define SCSI_EH_CMD_ERR 0x0001
/* Orig cmd error'd */
#define SCSI_EH_CMD_FAILED 0x0002
/* Orig cmd error type failed */
#define SCSI_EH_CMD_TIMEOUT 0x0004
/* Orig cmd error type timeout */
#define SCSI_EH_REC_TIMEOUT 0x0008
/* Recovery cmd timeout */
#define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70)
#endif
#endif
drivers/scsi/scsi_error.c
View file @
fd0a1c61
This diff is collapsed.
Click to expand it.
drivers/scsi/scsi_merge.c
View file @
fd0a1c61
...
@@ -140,7 +140,7 @@ void scsi_initialize_merge_fn(Scsi_Device * SDpnt)
...
@@ -140,7 +140,7 @@ void scsi_initialize_merge_fn(Scsi_Device * SDpnt)
* Enable highmem I/O, if appropriate.
* Enable highmem I/O, if appropriate.
*/
*/
bounce_limit
=
BLK_BOUNCE_HIGH
;
bounce_limit
=
BLK_BOUNCE_HIGH
;
if
(
SHpnt
->
highmem_io
&&
(
SDpnt
->
type
==
TYPE_DISK
)
)
{
if
(
SHpnt
->
highmem_io
)
{
if
(
!
PCI_DMA_BUS_IS_PHYS
)
if
(
!
PCI_DMA_BUS_IS_PHYS
)
/* Platforms with virtual-DMA translation
/* Platforms with virtual-DMA translation
* hardware have no practical limit.
* hardware have no practical limit.
...
...
drivers/scsi/sg.c
View file @
fd0a1c61
...
@@ -82,6 +82,19 @@ static void sg_proc_cleanup(void);
...
@@ -82,6 +82,19 @@ static void sg_proc_cleanup(void);
#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
/*
* Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d)
* Then when using 32 bit integers x * m may overflow during the calculation.
* Replacing muldiv(x) by muldiv(x)=((x % d) * m) / d + int(x / d) * m
* calculates the same, but prevents the overflow when both m and d
* are "small" numbers (like HZ and USER_HZ).
* Of course an overflow is inavoidable if the result of muldiv doesn't fit
* in 32 bits.
*/
#define MULDIV(X,MUL,DIV) ((((X % DIV) * MUL) / DIV) + ((X / DIV) * MUL))
#define SG_DEFAULT_TIMEOUT MULDIV(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
int
sg_big_buff
=
SG_DEF_RESERVED_SIZE
;
int
sg_big_buff
=
SG_DEF_RESERVED_SIZE
;
/* N.B. This variable is readable and writeable via
/* N.B. This variable is readable and writeable via
/proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
/proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
...
@@ -151,6 +164,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
...
@@ -151,6 +164,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
wait_queue_head_t
read_wait
;
/* queue read until command done */
wait_queue_head_t
read_wait
;
/* queue read until command done */
rwlock_t
rq_list_lock
;
/* protect access to list in req_arr */
rwlock_t
rq_list_lock
;
/* protect access to list in req_arr */
int
timeout
;
/* defaults to SG_DEFAULT_TIMEOUT */
int
timeout
;
/* defaults to SG_DEFAULT_TIMEOUT */
int
timeout_user
;
/* defaults to SG_DEFAULT_TIMEOUT_USER */
Sg_scatter_hold
reserve
;
/* buffer held for this file descriptor */
Sg_scatter_hold
reserve
;
/* buffer held for this file descriptor */
unsigned
save_scat_len
;
/* original length of trunc. scat. element */
unsigned
save_scat_len
;
/* original length of trunc. scat. element */
Sg_request
*
headrp
;
/* head of request slist, NULL->empty */
Sg_request
*
headrp
;
/* head of request slist, NULL->empty */
...
@@ -790,10 +804,15 @@ sg_ioctl(struct inode *inode, struct file *filp,
...
@@ -790,10 +804,15 @@ sg_ioctl(struct inode *inode, struct file *filp,
return
result
;
return
result
;
if
(
val
<
0
)
if
(
val
<
0
)
return
-
EIO
;
return
-
EIO
;
sfp
->
timeout
=
val
;
if
(
val
>=
MULDIV
(
INT_MAX
,
USER_HZ
,
HZ
))
val
=
MULDIV
(
INT_MAX
,
USER_HZ
,
HZ
);
sfp
->
timeout_user
=
val
;
sfp
->
timeout
=
MULDIV
(
val
,
HZ
,
USER_HZ
);
return
0
;
return
0
;
case
SG_GET_TIMEOUT
:
/* N.B. User receives timeout as return value */
case
SG_GET_TIMEOUT
:
/* N.B. User receives timeout as return value */
return
sfp
->
timeout
;
/* strange ..., for backward compatibility */
/* strange ..., for backward compatibility */
return
sfp
->
timeout_user
;
case
SG_SET_FORCE_LOW_DMA
:
case
SG_SET_FORCE_LOW_DMA
:
result
=
get_user
(
val
,
(
int
*
)
arg
);
result
=
get_user
(
val
,
(
int
*
)
arg
);
if
(
result
)
if
(
result
)
...
@@ -2432,6 +2451,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
...
@@ -2432,6 +2451,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
sfp
->
rq_list_lock
=
RW_LOCK_UNLOCKED
;
sfp
->
rq_list_lock
=
RW_LOCK_UNLOCKED
;
sfp
->
timeout
=
SG_DEFAULT_TIMEOUT
;
sfp
->
timeout
=
SG_DEFAULT_TIMEOUT
;
sfp
->
timeout_user
=
SG_DEFAULT_TIMEOUT_USER
;
sfp
->
force_packid
=
SG_DEF_FORCE_PACK_ID
;
sfp
->
force_packid
=
SG_DEF_FORCE_PACK_ID
;
sfp
->
low_dma
=
(
SG_DEF_FORCE_LOW_DMA
==
0
)
?
sfp
->
low_dma
=
(
SG_DEF_FORCE_LOW_DMA
==
0
)
?
sdp
->
device
->
host
->
unchecked_isa_dma
:
1
;
sdp
->
device
->
host
->
unchecked_isa_dma
:
1
;
...
...
include/scsi/sg.h
View file @
fd0a1c61
...
@@ -304,7 +304,12 @@ struct sg_header
...
@@ -304,7 +304,12 @@ struct sg_header
/* Defaults, commented if they differ from original sg driver */
/* Defaults, commented if they differ from original sg driver */
#ifdef __KERNEL__
#define SG_DEFAULT_TIMEOUT_USER (60*USER_HZ)
/* HZ == 'jiffies in 1 second' */
#else
#define SG_DEFAULT_TIMEOUT (60*HZ)
/* HZ == 'jiffies in 1 second' */
#define SG_DEFAULT_TIMEOUT (60*HZ)
/* HZ == 'jiffies in 1 second' */
#endif
#define SG_DEF_COMMAND_Q 0
/* command queuing is always on when
#define SG_DEF_COMMAND_Q 0
/* command queuing is always on when
the new interface is used */
the new interface is used */
#define SG_DEF_UNDERRUN_FLAG 0
#define SG_DEF_UNDERRUN_FLAG 0
...
...
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