diff options
-rw-r--r-- | drivers/scsi/scsi_sas_internal.h | 2 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 103 | ||||
-rw-r--r-- | include/scsi/scsi_transport_sas.h | 7 |
3 files changed, 105 insertions, 7 deletions
diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h index 998cb5be6833..6266a5d73d0f 100644 --- a/drivers/scsi/scsi_sas_internal.h +++ b/drivers/scsi/scsi_sas_internal.h | |||
@@ -5,7 +5,7 @@ | |||
5 | #define SAS_PHY_ATTRS 17 | 5 | #define SAS_PHY_ATTRS 17 |
6 | #define SAS_PORT_ATTRS 1 | 6 | #define SAS_PORT_ATTRS 1 |
7 | #define SAS_RPORT_ATTRS 7 | 7 | #define SAS_RPORT_ATTRS 7 |
8 | #define SAS_END_DEV_ATTRS 3 | 8 | #define SAS_END_DEV_ATTRS 5 |
9 | #define SAS_EXPANDER_ATTRS 7 | 9 | #define SAS_EXPANDER_ATTRS 7 |
10 | 10 | ||
11 | struct sas_internal { | 11 | struct sas_internal { |
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index f27e52d963d3..927e99cb7225 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -155,6 +155,17 @@ static struct { | |||
155 | sas_bitfield_name_search(linkspeed, sas_linkspeed_names) | 155 | sas_bitfield_name_search(linkspeed, sas_linkspeed_names) |
156 | sas_bitfield_name_set(linkspeed, sas_linkspeed_names) | 156 | sas_bitfield_name_set(linkspeed, sas_linkspeed_names) |
157 | 157 | ||
158 | static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev) | ||
159 | { | ||
160 | struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); | ||
161 | struct sas_end_device *rdev; | ||
162 | |||
163 | BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); | ||
164 | |||
165 | rdev = rphy_to_end_device(rphy); | ||
166 | return rdev; | ||
167 | } | ||
168 | |||
158 | static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, | 169 | static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, |
159 | struct sas_rphy *rphy) | 170 | struct sas_rphy *rphy) |
160 | { | 171 | { |
@@ -358,6 +369,85 @@ void sas_remove_host(struct Scsi_Host *shost) | |||
358 | } | 369 | } |
359 | EXPORT_SYMBOL(sas_remove_host); | 370 | EXPORT_SYMBOL(sas_remove_host); |
360 | 371 | ||
372 | /** | ||
373 | * sas_tlr_supported - checking TLR bit in vpd 0x90 | ||
374 | * @sdev: scsi device struct | ||
375 | * | ||
376 | * Check Transport Layer Retries are supported or not. | ||
377 | * If vpd page 0x90 is present, TRL is supported. | ||
378 | * | ||
379 | */ | ||
380 | unsigned int | ||
381 | sas_tlr_supported(struct scsi_device *sdev) | ||
382 | { | ||
383 | const int vpd_len = 32; | ||
384 | struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); | ||
385 | char *buffer = kzalloc(vpd_len, GFP_KERNEL); | ||
386 | int ret = 0; | ||
387 | |||
388 | if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len)) | ||
389 | goto out; | ||
390 | |||
391 | /* | ||
392 | * Magic numbers: the VPD Protocol page (0x90) | ||
393 | * has a 4 byte header and then one entry per device port | ||
394 | * the TLR bit is at offset 8 on each port entry | ||
395 | * if we take the first port, that's at total offset 12 | ||
396 | */ | ||
397 | ret = buffer[12] & 0x01; | ||
398 | |||
399 | out: | ||
400 | kfree(buffer); | ||
401 | rdev->tlr_supported = ret; | ||
402 | return ret; | ||
403 | |||
404 | } | ||
405 | EXPORT_SYMBOL_GPL(sas_tlr_supported); | ||
406 | |||
407 | /** | ||
408 | * sas_disable_tlr - setting TLR flags | ||
409 | * @sdev: scsi device struct | ||
410 | * | ||
411 | * Seting tlr_enabled flag to 0. | ||
412 | * | ||
413 | */ | ||
414 | void | ||
415 | sas_disable_tlr(struct scsi_device *sdev) | ||
416 | { | ||
417 | struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); | ||
418 | |||
419 | rdev->tlr_enabled = 0; | ||
420 | } | ||
421 | EXPORT_SYMBOL_GPL(sas_disable_tlr); | ||
422 | |||
423 | /** | ||
424 | * sas_enable_tlr - setting TLR flags | ||
425 | * @sdev: scsi device struct | ||
426 | * | ||
427 | * Seting tlr_enabled flag 1. | ||
428 | * | ||
429 | */ | ||
430 | void sas_enable_tlr(struct scsi_device *sdev) | ||
431 | { | ||
432 | unsigned int tlr_supported = 0; | ||
433 | tlr_supported = sas_tlr_supported(sdev); | ||
434 | |||
435 | if (tlr_supported) { | ||
436 | struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); | ||
437 | |||
438 | rdev->tlr_enabled = 1; | ||
439 | } | ||
440 | |||
441 | return; | ||
442 | } | ||
443 | EXPORT_SYMBOL_GPL(sas_enable_tlr); | ||
444 | |||
445 | unsigned int sas_is_tlr_enabled(struct scsi_device *sdev) | ||
446 | { | ||
447 | struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); | ||
448 | return rdev->tlr_enabled; | ||
449 | } | ||
450 | EXPORT_SYMBOL_GPL(sas_is_tlr_enabled); | ||
361 | 451 | ||
362 | /* | 452 | /* |
363 | * SAS Phy attributes | 453 | * SAS Phy attributes |
@@ -1146,15 +1236,10 @@ sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); | |||
1146 | int sas_read_port_mode_page(struct scsi_device *sdev) | 1236 | int sas_read_port_mode_page(struct scsi_device *sdev) |
1147 | { | 1237 | { |
1148 | char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; | 1238 | char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; |
1149 | struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); | 1239 | struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); |
1150 | struct sas_end_device *rdev; | ||
1151 | struct scsi_mode_data mode_data; | 1240 | struct scsi_mode_data mode_data; |
1152 | int res, error; | 1241 | int res, error; |
1153 | 1242 | ||
1154 | BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); | ||
1155 | |||
1156 | rdev = rphy_to_end_device(rphy); | ||
1157 | |||
1158 | if (!buffer) | 1243 | if (!buffer) |
1159 | return -ENOMEM; | 1244 | return -ENOMEM; |
1160 | 1245 | ||
@@ -1207,6 +1292,10 @@ sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, | |||
1207 | "%d\n", int); | 1292 | "%d\n", int); |
1208 | sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, | 1293 | sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, |
1209 | "%d\n", int); | 1294 | "%d\n", int); |
1295 | sas_end_dev_simple_attr(tlr_supported, tlr_supported, | ||
1296 | "%d\n", int); | ||
1297 | sas_end_dev_simple_attr(tlr_enabled, tlr_enabled, | ||
1298 | "%d\n", int); | ||
1210 | 1299 | ||
1211 | static DECLARE_TRANSPORT_CLASS(sas_expander_class, | 1300 | static DECLARE_TRANSPORT_CLASS(sas_expander_class, |
1212 | "sas_expander", NULL, NULL, NULL); | 1301 | "sas_expander", NULL, NULL, NULL); |
@@ -1733,6 +1822,8 @@ sas_attach_transport(struct sas_function_template *ft) | |||
1733 | SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); | 1822 | SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); |
1734 | SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); | 1823 | SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); |
1735 | SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); | 1824 | SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); |
1825 | SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported); | ||
1826 | SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled); | ||
1736 | i->end_dev_attrs[count] = NULL; | 1827 | i->end_dev_attrs[count] = NULL; |
1737 | 1828 | ||
1738 | count = 0; | 1829 | count = 0; |
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 61ad3594aad6..ffeebc34a4f7 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h | |||
@@ -107,6 +107,8 @@ struct sas_end_device { | |||
107 | struct sas_rphy rphy; | 107 | struct sas_rphy rphy; |
108 | /* flags */ | 108 | /* flags */ |
109 | unsigned ready_led_meaning:1; | 109 | unsigned ready_led_meaning:1; |
110 | unsigned tlr_supported:1; | ||
111 | unsigned tlr_enabled:1; | ||
110 | /* parameters */ | 112 | /* parameters */ |
111 | u16 I_T_nexus_loss_timeout; | 113 | u16 I_T_nexus_loss_timeout; |
112 | u16 initiator_response_timeout; | 114 | u16 initiator_response_timeout; |
@@ -181,6 +183,11 @@ extern int sas_phy_add(struct sas_phy *); | |||
181 | extern void sas_phy_delete(struct sas_phy *); | 183 | extern void sas_phy_delete(struct sas_phy *); |
182 | extern int scsi_is_sas_phy(const struct device *); | 184 | extern int scsi_is_sas_phy(const struct device *); |
183 | 185 | ||
186 | unsigned int sas_tlr_supported(struct scsi_device *); | ||
187 | unsigned int sas_is_tlr_enabled(struct scsi_device *); | ||
188 | void sas_disable_tlr(struct scsi_device *); | ||
189 | void sas_enable_tlr(struct scsi_device *); | ||
190 | |||
184 | extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); | 191 | extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); |
185 | extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); | 192 | extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); |
186 | void sas_rphy_free(struct sas_rphy *); | 193 | void sas_rphy_free(struct sas_rphy *); |