aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-11 17:14:57 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-13 17:13:00 -0500
commitacbf167d4ad8c27f9743a4b539d51ae9535bf21c (patch)
treee53f8330f60acaef42d74a745b3dd5131b424e49 /drivers/scsi
parentb218a0d8e250e0ae8fd4d4e45bd66a588b380752 (diff)
[SCSI] libsas: Add a sysfs knob to enable/disable a phy
This patch lets a user arbitrarily enable or disable a phy via sysfs. Potential applications include shutting down a phy to replace one lane of wide port, and (more importantly) providing a method for the libata SATL to control the phy. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libsas/sas_init.c35
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c1
-rw-r--r--drivers/scsi/scsi_transport_sas.c51
3 files changed, 85 insertions, 2 deletions
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 2f0c07fc3f48..90cce34cb6f5 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -146,6 +146,36 @@ static int sas_get_linkerrors(struct sas_phy *phy)
146 return sas_smp_get_phy_events(phy); 146 return sas_smp_get_phy_events(phy);
147} 147}
148 148
149int sas_phy_enable(struct sas_phy *phy, int enable)
150{
151 int ret;
152 enum phy_func command;
153
154 if (enable)
155 command = PHY_FUNC_LINK_RESET;
156 else
157 command = PHY_FUNC_DISABLE;
158
159 if (scsi_is_sas_phy_local(phy)) {
160 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
161 struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
162 struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
163 struct sas_internal *i =
164 to_sas_internal(sas_ha->core.shost->transportt);
165
166 if (!enable) {
167 sas_phy_disconnected(asd_phy);
168 sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL);
169 }
170 ret = i->dft->lldd_control_phy(asd_phy, command, NULL);
171 } else {
172 struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
173 struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
174 ret = sas_smp_phy_control(ddev, phy->number, command, NULL);
175 }
176 return ret;
177}
178
149int sas_phy_reset(struct sas_phy *phy, int hard_reset) 179int sas_phy_reset(struct sas_phy *phy, int hard_reset)
150{ 180{
151 int ret; 181 int ret;
@@ -172,8 +202,8 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset)
172 return ret; 202 return ret;
173} 203}
174 204
175static int sas_set_phy_speed(struct sas_phy *phy, 205int sas_set_phy_speed(struct sas_phy *phy,
176 struct sas_phy_linkrates *rates) 206 struct sas_phy_linkrates *rates)
177{ 207{
178 int ret; 208 int ret;
179 209
@@ -212,6 +242,7 @@ static int sas_set_phy_speed(struct sas_phy *phy,
212} 242}
213 243
214static struct sas_function_template sft = { 244static struct sas_function_template sft = {
245 .phy_enable = sas_phy_enable,
215 .phy_reset = sas_phy_reset, 246 .phy_reset = sas_phy_reset,
216 .set_phy_speed = sas_set_phy_speed, 247 .set_phy_speed = sas_set_phy_speed,
217 .get_linkerrors = sas_get_linkerrors, 248 .get_linkerrors = sas_get_linkerrors,
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 21bd24775980..7774eb3628ad 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -875,3 +875,4 @@ EXPORT_SYMBOL_GPL(sas_change_queue_type);
875EXPORT_SYMBOL_GPL(sas_bios_param); 875EXPORT_SYMBOL_GPL(sas_bios_param);
876EXPORT_SYMBOL_GPL(sas_task_abort); 876EXPORT_SYMBOL_GPL(sas_task_abort);
877EXPORT_SYMBOL_GPL(sas_phy_reset); 877EXPORT_SYMBOL_GPL(sas_phy_reset);
878EXPORT_SYMBOL_GPL(sas_phy_enable);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 5c0b75bbfa10..9e38c1894bb2 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -336,6 +336,51 @@ show_sas_device_type(struct class_device *cdev, char *buf)
336} 336}
337static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); 337static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
338 338
339static ssize_t do_sas_phy_enable(struct class_device *cdev,
340 size_t count, int enable)
341{
342 struct sas_phy *phy = transport_class_to_phy(cdev);
343 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
344 struct sas_internal *i = to_sas_internal(shost->transportt);
345 int error;
346
347 error = i->f->phy_enable(phy, enable);
348 if (error)
349 return error;
350 phy->enabled = enable;
351 return count;
352};
353
354static ssize_t store_sas_phy_enable(struct class_device *cdev,
355 const char *buf, size_t count)
356{
357 if (count < 1)
358 return -EINVAL;
359
360 switch (buf[0]) {
361 case '0':
362 do_sas_phy_enable(cdev, count, 0);
363 break;
364 case '1':
365 do_sas_phy_enable(cdev, count, 1);
366 break;
367 default:
368 return -EINVAL;
369 }
370
371 return count;
372}
373
374static ssize_t show_sas_phy_enable(struct class_device *cdev, char *buf)
375{
376 struct sas_phy *phy = transport_class_to_phy(cdev);
377
378 return snprintf(buf, 20, "%d", phy->enabled);
379}
380
381static CLASS_DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,
382 store_sas_phy_enable);
383
339static ssize_t do_sas_phy_reset(struct class_device *cdev, 384static ssize_t do_sas_phy_reset(struct class_device *cdev,
340 size_t count, int hard_reset) 385 size_t count, int hard_reset)
341{ 386{
@@ -435,6 +480,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
435 return NULL; 480 return NULL;
436 481
437 phy->number = number; 482 phy->number = number;
483 phy->enabled = 1;
438 484
439 device_initialize(&phy->dev); 485 device_initialize(&phy->dev);
440 phy->dev.parent = get_device(parent); 486 phy->dev.parent = get_device(parent);
@@ -1389,6 +1435,10 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
1389 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ 1435 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
1390 !i->f->set_phy_speed, S_IRUGO) 1436 !i->f->set_phy_speed, S_IRUGO)
1391 1437
1438#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \
1439 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
1440 !i->f->func, S_IRUGO)
1441
1392#define SETUP_PORT_ATTRIBUTE(field) \ 1442#define SETUP_PORT_ATTRIBUTE(field) \
1393 SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) 1443 SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
1394 1444
@@ -1479,6 +1529,7 @@ sas_attach_transport(struct sas_function_template *ft)
1479 SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); 1529 SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
1480 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); 1530 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
1481 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); 1531 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
1532 SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);
1482 i->phy_attrs[count] = NULL; 1533 i->phy_attrs[count] = NULL;
1483 1534
1484 count = 0; 1535 count = 0;