[SCSI] scsi_transport_sas: add support for transport layer retries (TLR)

The mpt2sas driver wants to use transport layer retries (TLR) so the
simplest thing to do seems to be to add the enabling flags and checks
to the SAS transport class, since they're a SAS specific protocol
feature.

Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
James Bottomley 2010-01-18 10:14:51 -06:00
parent 8605c46c17
commit 0f88009d5c
3 changed files with 105 additions and 7 deletions

View file

@ -5,7 +5,7 @@
#define SAS_PHY_ATTRS 17 #define SAS_PHY_ATTRS 17
#define SAS_PORT_ATTRS 1 #define SAS_PORT_ATTRS 1
#define SAS_RPORT_ATTRS 7 #define SAS_RPORT_ATTRS 7
#define SAS_END_DEV_ATTRS 3 #define SAS_END_DEV_ATTRS 5
#define SAS_EXPANDER_ATTRS 7 #define SAS_EXPANDER_ATTRS 7
struct sas_internal { struct sas_internal {

View file

@ -155,6 +155,17 @@ static struct {
sas_bitfield_name_search(linkspeed, sas_linkspeed_names) sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
sas_bitfield_name_set(linkspeed, sas_linkspeed_names) sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev)
{
struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
struct sas_end_device *rdev;
BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
rdev = rphy_to_end_device(rphy);
return rdev;
}
static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
struct sas_rphy *rphy) struct sas_rphy *rphy)
{ {
@ -358,6 +369,85 @@ void sas_remove_host(struct Scsi_Host *shost)
} }
EXPORT_SYMBOL(sas_remove_host); EXPORT_SYMBOL(sas_remove_host);
/**
* sas_tlr_supported - checking TLR bit in vpd 0x90
* @sdev: scsi device struct
*
* Check Transport Layer Retries are supported or not.
* If vpd page 0x90 is present, TRL is supported.
*
*/
unsigned int
sas_tlr_supported(struct scsi_device *sdev)
{
const int vpd_len = 32;
struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
char *buffer = kzalloc(vpd_len, GFP_KERNEL);
int ret = 0;
if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))
goto out;
/*
* Magic numbers: the VPD Protocol page (0x90)
* has a 4 byte header and then one entry per device port
* the TLR bit is at offset 8 on each port entry
* if we take the first port, that's at total offset 12
*/
ret = buffer[12] & 0x01;
out:
kfree(buffer);
rdev->tlr_supported = ret;
return ret;
}
EXPORT_SYMBOL_GPL(sas_tlr_supported);
/**
* sas_disable_tlr - setting TLR flags
* @sdev: scsi device struct
*
* Seting tlr_enabled flag to 0.
*
*/
void
sas_disable_tlr(struct scsi_device *sdev)
{
struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
rdev->tlr_enabled = 0;
}
EXPORT_SYMBOL_GPL(sas_disable_tlr);
/**
* sas_enable_tlr - setting TLR flags
* @sdev: scsi device struct
*
* Seting tlr_enabled flag 1.
*
*/
void sas_enable_tlr(struct scsi_device *sdev)
{
unsigned int tlr_supported = 0;
tlr_supported = sas_tlr_supported(sdev);
if (tlr_supported) {
struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
rdev->tlr_enabled = 1;
}
return;
}
EXPORT_SYMBOL_GPL(sas_enable_tlr);
unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
{
struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
return rdev->tlr_enabled;
}
EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
/* /*
* SAS Phy attributes * SAS Phy attributes
@ -1146,15 +1236,10 @@ sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
int sas_read_port_mode_page(struct scsi_device *sdev) int sas_read_port_mode_page(struct scsi_device *sdev)
{ {
char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
struct sas_end_device *rdev;
struct scsi_mode_data mode_data; struct scsi_mode_data mode_data;
int res, error; int res, error;
BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
rdev = rphy_to_end_device(rphy);
if (!buffer) if (!buffer)
return -ENOMEM; return -ENOMEM;
@ -1207,6 +1292,10 @@ sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
"%d\n", int); "%d\n", int);
sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
"%d\n", int); "%d\n", int);
sas_end_dev_simple_attr(tlr_supported, tlr_supported,
"%d\n", int);
sas_end_dev_simple_attr(tlr_enabled, tlr_enabled,
"%d\n", int);
static DECLARE_TRANSPORT_CLASS(sas_expander_class, static DECLARE_TRANSPORT_CLASS(sas_expander_class,
"sas_expander", NULL, NULL, NULL); "sas_expander", NULL, NULL, NULL);
@ -1733,6 +1822,8 @@ sas_attach_transport(struct sas_function_template *ft)
SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);
SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);
i->end_dev_attrs[count] = NULL; i->end_dev_attrs[count] = NULL;
count = 0; count = 0;

View file

@ -107,6 +107,8 @@ struct sas_end_device {
struct sas_rphy rphy; struct sas_rphy rphy;
/* flags */ /* flags */
unsigned ready_led_meaning:1; unsigned ready_led_meaning:1;
unsigned tlr_supported:1;
unsigned tlr_enabled:1;
/* parameters */ /* parameters */
u16 I_T_nexus_loss_timeout; u16 I_T_nexus_loss_timeout;
u16 initiator_response_timeout; u16 initiator_response_timeout;
@ -181,6 +183,11 @@ extern int sas_phy_add(struct sas_phy *);
extern void sas_phy_delete(struct sas_phy *); extern void sas_phy_delete(struct sas_phy *);
extern int scsi_is_sas_phy(const struct device *); extern int scsi_is_sas_phy(const struct device *);
unsigned int sas_tlr_supported(struct scsi_device *);
unsigned int sas_is_tlr_enabled(struct scsi_device *);
void sas_disable_tlr(struct scsi_device *);
void sas_enable_tlr(struct scsi_device *);
extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
void sas_rphy_free(struct sas_rphy *); void sas_rphy_free(struct sas_rphy *);