diff options
Diffstat (limited to 'drivers/scsi/scsi_transport_sas.c')
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 83 |
1 files changed, 69 insertions, 14 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 5a625c3fddae..b5b0c2cba96b 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -77,6 +77,24 @@ get_sas_##title##_names(u32 table_key, char *buf) \ | |||
77 | return len; \ | 77 | return len; \ |
78 | } | 78 | } |
79 | 79 | ||
80 | #define sas_bitfield_name_set(title, table) \ | ||
81 | static ssize_t \ | ||
82 | set_sas_##title##_names(u32 *table_key, const char *buf) \ | ||
83 | { \ | ||
84 | ssize_t len = 0; \ | ||
85 | int i; \ | ||
86 | \ | ||
87 | for (i = 0; i < ARRAY_SIZE(table); i++) { \ | ||
88 | len = strlen(table[i].name); \ | ||
89 | if (strncmp(buf, table[i].name, len) == 0 && \ | ||
90 | (buf[len] == '\n' || buf[len] == '\0')) { \ | ||
91 | *table_key = table[i].value; \ | ||
92 | return 0; \ | ||
93 | } \ | ||
94 | } \ | ||
95 | return -EINVAL; \ | ||
96 | } | ||
97 | |||
80 | #define sas_bitfield_name_search(title, table) \ | 98 | #define sas_bitfield_name_search(title, table) \ |
81 | static ssize_t \ | 99 | static ssize_t \ |
82 | get_sas_##title##_names(u32 table_key, char *buf) \ | 100 | get_sas_##title##_names(u32 table_key, char *buf) \ |
@@ -131,7 +149,7 @@ static struct { | |||
131 | { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, | 149 | { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, |
132 | }; | 150 | }; |
133 | sas_bitfield_name_search(linkspeed, sas_linkspeed_names) | 151 | sas_bitfield_name_search(linkspeed, sas_linkspeed_names) |
134 | 152 | sas_bitfield_name_set(linkspeed, sas_linkspeed_names) | |
135 | 153 | ||
136 | /* | 154 | /* |
137 | * SAS host attributes | 155 | * SAS host attributes |
@@ -253,10 +271,39 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \ | |||
253 | return get_sas_linkspeed_names(phy->field, buf); \ | 271 | return get_sas_linkspeed_names(phy->field, buf); \ |
254 | } | 272 | } |
255 | 273 | ||
274 | /* Fudge to tell if we're minimum or maximum */ | ||
275 | #define sas_phy_store_linkspeed(field) \ | ||
276 | static ssize_t \ | ||
277 | store_sas_phy_##field(struct class_device *cdev, const char *buf, \ | ||
278 | size_t count) \ | ||
279 | { \ | ||
280 | struct sas_phy *phy = transport_class_to_phy(cdev); \ | ||
281 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ | ||
282 | struct sas_internal *i = to_sas_internal(shost->transportt); \ | ||
283 | u32 value; \ | ||
284 | struct sas_phy_linkrates rates = {0}; \ | ||
285 | int error; \ | ||
286 | \ | ||
287 | error = set_sas_linkspeed_names(&value, buf); \ | ||
288 | if (error) \ | ||
289 | return error; \ | ||
290 | rates.field = value; \ | ||
291 | error = i->f->set_phy_speed(phy, &rates); \ | ||
292 | \ | ||
293 | return error ? error : count; \ | ||
294 | } | ||
295 | |||
296 | #define sas_phy_linkspeed_rw_attr(field) \ | ||
297 | sas_phy_show_linkspeed(field) \ | ||
298 | sas_phy_store_linkspeed(field) \ | ||
299 | static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \ | ||
300 | store_sas_phy_##field) | ||
301 | |||
256 | #define sas_phy_linkspeed_attr(field) \ | 302 | #define sas_phy_linkspeed_attr(field) \ |
257 | sas_phy_show_linkspeed(field) \ | 303 | sas_phy_show_linkspeed(field) \ |
258 | static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) | 304 | static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) |
259 | 305 | ||
306 | |||
260 | #define sas_phy_show_linkerror(field) \ | 307 | #define sas_phy_show_linkerror(field) \ |
261 | static ssize_t \ | 308 | static ssize_t \ |
262 | show_sas_phy_##field(struct class_device *cdev, char *buf) \ | 309 | show_sas_phy_##field(struct class_device *cdev, char *buf) \ |
@@ -266,9 +313,6 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \ | |||
266 | struct sas_internal *i = to_sas_internal(shost->transportt); \ | 313 | struct sas_internal *i = to_sas_internal(shost->transportt); \ |
267 | int error; \ | 314 | int error; \ |
268 | \ | 315 | \ |
269 | if (!phy->local_attached) \ | ||
270 | return -EINVAL; \ | ||
271 | \ | ||
272 | error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ | 316 | error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ |
273 | if (error) \ | 317 | if (error) \ |
274 | return error; \ | 318 | return error; \ |
@@ -299,9 +343,6 @@ static ssize_t do_sas_phy_reset(struct class_device *cdev, | |||
299 | struct sas_internal *i = to_sas_internal(shost->transportt); | 343 | struct sas_internal *i = to_sas_internal(shost->transportt); |
300 | int error; | 344 | int error; |
301 | 345 | ||
302 | if (!phy->local_attached) | ||
303 | return -EINVAL; | ||
304 | |||
305 | error = i->f->phy_reset(phy, hard_reset); | 346 | error = i->f->phy_reset(phy, hard_reset); |
306 | if (error) | 347 | if (error) |
307 | return error; | 348 | return error; |
@@ -332,9 +373,9 @@ sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); | |||
332 | //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); | 373 | //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); |
333 | sas_phy_linkspeed_attr(negotiated_linkrate); | 374 | sas_phy_linkspeed_attr(negotiated_linkrate); |
334 | sas_phy_linkspeed_attr(minimum_linkrate_hw); | 375 | sas_phy_linkspeed_attr(minimum_linkrate_hw); |
335 | sas_phy_linkspeed_attr(minimum_linkrate); | 376 | sas_phy_linkspeed_rw_attr(minimum_linkrate); |
336 | sas_phy_linkspeed_attr(maximum_linkrate_hw); | 377 | sas_phy_linkspeed_attr(maximum_linkrate_hw); |
337 | sas_phy_linkspeed_attr(maximum_linkrate); | 378 | sas_phy_linkspeed_rw_attr(maximum_linkrate); |
338 | sas_phy_linkerror_attr(invalid_dword_count); | 379 | sas_phy_linkerror_attr(invalid_dword_count); |
339 | sas_phy_linkerror_attr(running_disparity_error_count); | 380 | sas_phy_linkerror_attr(running_disparity_error_count); |
340 | sas_phy_linkerror_attr(loss_of_dword_sync_count); | 381 | sas_phy_linkerror_attr(loss_of_dword_sync_count); |
@@ -849,7 +890,7 @@ show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf) | |||
849 | * Only devices behind an expander are supported, because the | 890 | * Only devices behind an expander are supported, because the |
850 | * enclosure identifier is a SMP feature. | 891 | * enclosure identifier is a SMP feature. |
851 | */ | 892 | */ |
852 | if (phy->local_attached) | 893 | if (scsi_is_sas_phy_local(phy)) |
853 | return -EINVAL; | 894 | return -EINVAL; |
854 | 895 | ||
855 | error = i->f->get_enclosure_identifier(rphy, &identifier); | 896 | error = i->f->get_enclosure_identifier(rphy, &identifier); |
@@ -870,7 +911,7 @@ show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf) | |||
870 | struct sas_internal *i = to_sas_internal(shost->transportt); | 911 | struct sas_internal *i = to_sas_internal(shost->transportt); |
871 | int val; | 912 | int val; |
872 | 913 | ||
873 | if (phy->local_attached) | 914 | if (scsi_is_sas_phy_local(phy)) |
874 | return -EINVAL; | 915 | return -EINVAL; |
875 | 916 | ||
876 | val = i->f->get_bay_identifier(rphy); | 917 | val = i->f->get_bay_identifier(rphy); |
@@ -1316,13 +1357,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, | |||
1316 | * Setup / Teardown code | 1357 | * Setup / Teardown code |
1317 | */ | 1358 | */ |
1318 | 1359 | ||
1319 | #define SETUP_TEMPLATE(attrb, field, perm, test) \ | 1360 | #define SETUP_TEMPLATE(attrb, field, perm, test) \ |
1320 | i->private_##attrb[count] = class_device_attr_##field; \ | 1361 | i->private_##attrb[count] = class_device_attr_##field; \ |
1321 | i->private_##attrb[count].attr.mode = perm; \ | 1362 | i->private_##attrb[count].attr.mode = perm; \ |
1322 | i->attrb[count] = &i->private_##attrb[count]; \ | 1363 | i->attrb[count] = &i->private_##attrb[count]; \ |
1323 | if (test) \ | 1364 | if (test) \ |
1324 | count++ | 1365 | count++ |
1325 | 1366 | ||
1367 | #define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \ | ||
1368 | i->private_##attrb[count] = class_device_attr_##field; \ | ||
1369 | i->private_##attrb[count].attr.mode = perm; \ | ||
1370 | if (ro_test) { \ | ||
1371 | i->private_##attrb[count].attr.mode = ro_perm; \ | ||
1372 | i->private_##attrb[count].store = NULL; \ | ||
1373 | } \ | ||
1374 | i->attrb[count] = &i->private_##attrb[count]; \ | ||
1375 | if (test) \ | ||
1376 | count++ | ||
1326 | 1377 | ||
1327 | #define SETUP_RPORT_ATTRIBUTE(field) \ | 1378 | #define SETUP_RPORT_ATTRIBUTE(field) \ |
1328 | SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) | 1379 | SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) |
@@ -1333,6 +1384,10 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, | |||
1333 | #define SETUP_PHY_ATTRIBUTE(field) \ | 1384 | #define SETUP_PHY_ATTRIBUTE(field) \ |
1334 | SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) | 1385 | SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) |
1335 | 1386 | ||
1387 | #define SETUP_PHY_ATTRIBUTE_RW(field) \ | ||
1388 | SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ | ||
1389 | !i->f->set_phy_speed, S_IRUGO) | ||
1390 | |||
1336 | #define SETUP_PORT_ATTRIBUTE(field) \ | 1391 | #define SETUP_PORT_ATTRIBUTE(field) \ |
1337 | SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) | 1392 | SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) |
1338 | 1393 | ||
@@ -1413,9 +1468,9 @@ sas_attach_transport(struct sas_function_template *ft) | |||
1413 | //SETUP_PHY_ATTRIBUTE(port_identifier); | 1468 | //SETUP_PHY_ATTRIBUTE(port_identifier); |
1414 | SETUP_PHY_ATTRIBUTE(negotiated_linkrate); | 1469 | SETUP_PHY_ATTRIBUTE(negotiated_linkrate); |
1415 | SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); | 1470 | SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); |
1416 | SETUP_PHY_ATTRIBUTE(minimum_linkrate); | 1471 | SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate); |
1417 | SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); | 1472 | SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); |
1418 | SETUP_PHY_ATTRIBUTE(maximum_linkrate); | 1473 | SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate); |
1419 | 1474 | ||
1420 | SETUP_PHY_ATTRIBUTE(invalid_dword_count); | 1475 | SETUP_PHY_ATTRIBUTE(invalid_dword_count); |
1421 | SETUP_PHY_ATTRIBUTE(running_disparity_error_count); | 1476 | SETUP_PHY_ATTRIBUTE(running_disparity_error_count); |