diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2006-09-06 20:25:22 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-09-07 16:16:44 -0400 |
commit | d24e1eeb3a16e4944288c2f3bf082e1513f4b425 (patch) | |
tree | 395812a03c26a8693c23362eb403048164352dd6 | |
parent | 88edf74610bd894b93438f389688bc8b4a2d3414 (diff) |
[SCSI] scsi_transport_sas: make minimum and maximum linkrate settable quantities
According to SPEC, the minimum_linkrate and maximum_linkrate should be
settable by the user. This patch introduces a callback that allows the
sas class to pass these settings on to the driver.
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 73 | ||||
-rw-r--r-- | include/scsi/scsi_transport_sas.h | 6 |
2 files changed, 73 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index d518c1207fb4..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) \ |
@@ -326,9 +373,9 @@ sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); | |||
326 | //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); | 373 | //sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); |
327 | sas_phy_linkspeed_attr(negotiated_linkrate); | 374 | sas_phy_linkspeed_attr(negotiated_linkrate); |
328 | sas_phy_linkspeed_attr(minimum_linkrate_hw); | 375 | sas_phy_linkspeed_attr(minimum_linkrate_hw); |
329 | sas_phy_linkspeed_attr(minimum_linkrate); | 376 | sas_phy_linkspeed_rw_attr(minimum_linkrate); |
330 | sas_phy_linkspeed_attr(maximum_linkrate_hw); | 377 | sas_phy_linkspeed_attr(maximum_linkrate_hw); |
331 | sas_phy_linkspeed_attr(maximum_linkrate); | 378 | sas_phy_linkspeed_rw_attr(maximum_linkrate); |
332 | sas_phy_linkerror_attr(invalid_dword_count); | 379 | sas_phy_linkerror_attr(invalid_dword_count); |
333 | sas_phy_linkerror_attr(running_disparity_error_count); | 380 | sas_phy_linkerror_attr(running_disparity_error_count); |
334 | sas_phy_linkerror_attr(loss_of_dword_sync_count); | 381 | sas_phy_linkerror_attr(loss_of_dword_sync_count); |
@@ -1310,13 +1357,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, | |||
1310 | * Setup / Teardown code | 1357 | * Setup / Teardown code |
1311 | */ | 1358 | */ |
1312 | 1359 | ||
1313 | #define SETUP_TEMPLATE(attrb, field, perm, test) \ | 1360 | #define SETUP_TEMPLATE(attrb, field, perm, test) \ |
1314 | i->private_##attrb[count] = class_device_attr_##field; \ | 1361 | i->private_##attrb[count] = class_device_attr_##field; \ |
1315 | i->private_##attrb[count].attr.mode = perm; \ | 1362 | i->private_##attrb[count].attr.mode = perm; \ |
1316 | i->attrb[count] = &i->private_##attrb[count]; \ | 1363 | i->attrb[count] = &i->private_##attrb[count]; \ |
1317 | if (test) \ | 1364 | if (test) \ |
1318 | count++ | 1365 | count++ |
1319 | 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++ | ||
1320 | 1377 | ||
1321 | #define SETUP_RPORT_ATTRIBUTE(field) \ | 1378 | #define SETUP_RPORT_ATTRIBUTE(field) \ |
1322 | SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) | 1379 | SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) |
@@ -1327,6 +1384,10 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, | |||
1327 | #define SETUP_PHY_ATTRIBUTE(field) \ | 1384 | #define SETUP_PHY_ATTRIBUTE(field) \ |
1328 | SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) | 1385 | SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) |
1329 | 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 | |||
1330 | #define SETUP_PORT_ATTRIBUTE(field) \ | 1391 | #define SETUP_PORT_ATTRIBUTE(field) \ |
1331 | SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) | 1392 | SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) |
1332 | 1393 | ||
@@ -1407,9 +1468,9 @@ sas_attach_transport(struct sas_function_template *ft) | |||
1407 | //SETUP_PHY_ATTRIBUTE(port_identifier); | 1468 | //SETUP_PHY_ATTRIBUTE(port_identifier); |
1408 | SETUP_PHY_ATTRIBUTE(negotiated_linkrate); | 1469 | SETUP_PHY_ATTRIBUTE(negotiated_linkrate); |
1409 | SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); | 1470 | SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); |
1410 | SETUP_PHY_ATTRIBUTE(minimum_linkrate); | 1471 | SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate); |
1411 | SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); | 1472 | SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); |
1412 | SETUP_PHY_ATTRIBUTE(maximum_linkrate); | 1473 | SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate); |
1413 | 1474 | ||
1414 | SETUP_PHY_ATTRIBUTE(invalid_dword_count); | 1475 | SETUP_PHY_ATTRIBUTE(invalid_dword_count); |
1415 | SETUP_PHY_ATTRIBUTE(running_disparity_error_count); | 1476 | SETUP_PHY_ATTRIBUTE(running_disparity_error_count); |
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 87de518960c1..53024377f3b8 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h | |||
@@ -150,12 +150,18 @@ struct sas_port { | |||
150 | #define transport_class_to_sas_port(cdev) \ | 150 | #define transport_class_to_sas_port(cdev) \ |
151 | dev_to_sas_port((cdev)->dev) | 151 | dev_to_sas_port((cdev)->dev) |
152 | 152 | ||
153 | struct sas_phy_linkrates { | ||
154 | enum sas_linkrate maximum_linkrate; | ||
155 | enum sas_linkrate minimum_linkrate; | ||
156 | }; | ||
157 | |||
153 | /* The functions by which the transport class and the driver communicate */ | 158 | /* The functions by which the transport class and the driver communicate */ |
154 | struct sas_function_template { | 159 | struct sas_function_template { |
155 | int (*get_linkerrors)(struct sas_phy *); | 160 | int (*get_linkerrors)(struct sas_phy *); |
156 | int (*get_enclosure_identifier)(struct sas_rphy *, u64 *); | 161 | int (*get_enclosure_identifier)(struct sas_rphy *, u64 *); |
157 | int (*get_bay_identifier)(struct sas_rphy *); | 162 | int (*get_bay_identifier)(struct sas_rphy *); |
158 | int (*phy_reset)(struct sas_phy *, int); | 163 | int (*phy_reset)(struct sas_phy *, int); |
164 | int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *); | ||
159 | }; | 165 | }; |
160 | 166 | ||
161 | 167 | ||