ipath_sysfs.c revision 6473d160b4aba8023bcf38519a5989694dfd51a7
1/* 2 * Copyright (c) 2006 QLogic, Inc. All rights reserved. 3 * Copyright (c) 2006 PathScale, Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34#include <linux/ctype.h> 35 36#include "ipath_kernel.h" 37#include "ipath_common.h" 38 39/** 40 * ipath_parse_ushort - parse an unsigned short value in an arbitrary base 41 * @str: the string containing the number 42 * @valp: where to put the result 43 * 44 * returns the number of bytes consumed, or negative value on error 45 */ 46int ipath_parse_ushort(const char *str, unsigned short *valp) 47{ 48 unsigned long val; 49 char *end; 50 int ret; 51 52 if (!isdigit(str[0])) { 53 ret = -EINVAL; 54 goto bail; 55 } 56 57 val = simple_strtoul(str, &end, 0); 58 59 if (val > 0xffff) { 60 ret = -EINVAL; 61 goto bail; 62 } 63 64 *valp = val; 65 66 ret = end + 1 - str; 67 if (ret == 0) 68 ret = -EINVAL; 69 70bail: 71 return ret; 72} 73 74static ssize_t show_version(struct device_driver *dev, char *buf) 75{ 76 /* The string printed here is already newline-terminated. */ 77 return scnprintf(buf, PAGE_SIZE, "%s", ib_ipath_version); 78} 79 80static ssize_t show_num_units(struct device_driver *dev, char *buf) 81{ 82 return scnprintf(buf, PAGE_SIZE, "%d\n", 83 ipath_count_units(NULL, NULL, NULL)); 84} 85 86static ssize_t show_status(struct device *dev, 87 struct device_attribute *attr, 88 char *buf) 89{ 90 struct ipath_devdata *dd = dev_get_drvdata(dev); 91 ssize_t ret; 92 93 if (!dd->ipath_statusp) { 94 ret = -EINVAL; 95 goto bail; 96 } 97 98 ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n", 99 (unsigned long long) *(dd->ipath_statusp)); 100 101bail: 102 return ret; 103} 104 105static const char *ipath_status_str[] = { 106 "Initted", 107 "Disabled", 108 "Admin_Disabled", 109 "", /* This used to be the old "OIB_SMA" status. */ 110 "", /* This used to be the old "SMA" status. */ 111 "Present", 112 "IB_link_up", 113 "IB_configured", 114 "NoIBcable", 115 "Fatal_Hardware_Error", 116 NULL, 117}; 118 119static ssize_t show_status_str(struct device *dev, 120 struct device_attribute *attr, 121 char *buf) 122{ 123 struct ipath_devdata *dd = dev_get_drvdata(dev); 124 int i, any; 125 u64 s; 126 ssize_t ret; 127 128 if (!dd->ipath_statusp) { 129 ret = -EINVAL; 130 goto bail; 131 } 132 133 s = *(dd->ipath_statusp); 134 *buf = '\0'; 135 for (any = i = 0; s && ipath_status_str[i]; i++) { 136 if (s & 1) { 137 if (any && strlcat(buf, " ", PAGE_SIZE) >= 138 PAGE_SIZE) 139 /* overflow */ 140 break; 141 if (strlcat(buf, ipath_status_str[i], 142 PAGE_SIZE) >= PAGE_SIZE) 143 break; 144 any = 1; 145 } 146 s >>= 1; 147 } 148 if (any) 149 strlcat(buf, "\n", PAGE_SIZE); 150 151 ret = strlen(buf); 152 153bail: 154 return ret; 155} 156 157static ssize_t show_boardversion(struct device *dev, 158 struct device_attribute *attr, 159 char *buf) 160{ 161 struct ipath_devdata *dd = dev_get_drvdata(dev); 162 /* The string printed here is already newline-terminated. */ 163 return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion); 164} 165 166static ssize_t show_lid(struct device *dev, 167 struct device_attribute *attr, 168 char *buf) 169{ 170 struct ipath_devdata *dd = dev_get_drvdata(dev); 171 172 return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_lid); 173} 174 175static ssize_t store_lid(struct device *dev, 176 struct device_attribute *attr, 177 const char *buf, 178 size_t count) 179{ 180 struct ipath_devdata *dd = dev_get_drvdata(dev); 181 u16 lid = 0; 182 int ret; 183 184 ret = ipath_parse_ushort(buf, &lid); 185 if (ret < 0) 186 goto invalid; 187 188 if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) { 189 ret = -EINVAL; 190 goto invalid; 191 } 192 193 ipath_set_lid(dd, lid, 0); 194 195 goto bail; 196invalid: 197 ipath_dev_err(dd, "attempt to set invalid LID 0x%x\n", lid); 198bail: 199 return ret; 200} 201 202static ssize_t show_mlid(struct device *dev, 203 struct device_attribute *attr, 204 char *buf) 205{ 206 struct ipath_devdata *dd = dev_get_drvdata(dev); 207 208 return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_mlid); 209} 210 211static ssize_t store_mlid(struct device *dev, 212 struct device_attribute *attr, 213 const char *buf, 214 size_t count) 215{ 216 struct ipath_devdata *dd = dev_get_drvdata(dev); 217 u16 mlid; 218 int ret; 219 220 ret = ipath_parse_ushort(buf, &mlid); 221 if (ret < 0 || mlid < IPATH_MULTICAST_LID_BASE) 222 goto invalid; 223 224 dd->ipath_mlid = mlid; 225 226 goto bail; 227invalid: 228 ipath_dev_err(dd, "attempt to set invalid MLID\n"); 229bail: 230 return ret; 231} 232 233static ssize_t show_guid(struct device *dev, 234 struct device_attribute *attr, 235 char *buf) 236{ 237 struct ipath_devdata *dd = dev_get_drvdata(dev); 238 u8 *guid; 239 240 guid = (u8 *) & (dd->ipath_guid); 241 242 return scnprintf(buf, PAGE_SIZE, 243 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 244 guid[0], guid[1], guid[2], guid[3], 245 guid[4], guid[5], guid[6], guid[7]); 246} 247 248static ssize_t store_guid(struct device *dev, 249 struct device_attribute *attr, 250 const char *buf, 251 size_t count) 252{ 253 struct ipath_devdata *dd = dev_get_drvdata(dev); 254 ssize_t ret; 255 unsigned short guid[8]; 256 __be64 new_guid; 257 u8 *ng; 258 int i; 259 260 if (sscanf(buf, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", 261 &guid[0], &guid[1], &guid[2], &guid[3], 262 &guid[4], &guid[5], &guid[6], &guid[7]) != 8) 263 goto invalid; 264 265 ng = (u8 *) &new_guid; 266 267 for (i = 0; i < 8; i++) { 268 if (guid[i] > 0xff) 269 goto invalid; 270 ng[i] = guid[i]; 271 } 272 273 if (new_guid == 0) 274 goto invalid; 275 276 dd->ipath_guid = new_guid; 277 dd->ipath_nguid = 1; 278 279 ret = strlen(buf); 280 goto bail; 281 282invalid: 283 ipath_dev_err(dd, "attempt to set invalid GUID\n"); 284 ret = -EINVAL; 285 286bail: 287 return ret; 288} 289 290static ssize_t show_nguid(struct device *dev, 291 struct device_attribute *attr, 292 char *buf) 293{ 294 struct ipath_devdata *dd = dev_get_drvdata(dev); 295 296 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid); 297} 298 299static ssize_t show_nports(struct device *dev, 300 struct device_attribute *attr, 301 char *buf) 302{ 303 struct ipath_devdata *dd = dev_get_drvdata(dev); 304 305 /* Return the number of user ports available. */ 306 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_cfgports - 1); 307} 308 309static ssize_t show_serial(struct device *dev, 310 struct device_attribute *attr, 311 char *buf) 312{ 313 struct ipath_devdata *dd = dev_get_drvdata(dev); 314 315 buf[sizeof dd->ipath_serial] = '\0'; 316 memcpy(buf, dd->ipath_serial, sizeof dd->ipath_serial); 317 strcat(buf, "\n"); 318 return strlen(buf); 319} 320 321static ssize_t show_unit(struct device *dev, 322 struct device_attribute *attr, 323 char *buf) 324{ 325 struct ipath_devdata *dd = dev_get_drvdata(dev); 326 327 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit); 328} 329 330#define DEVICE_COUNTER(name, attr) \ 331 static ssize_t show_counter_##name(struct device *dev, \ 332 struct device_attribute *attr, \ 333 char *buf) \ 334 { \ 335 struct ipath_devdata *dd = dev_get_drvdata(dev); \ 336 return scnprintf(\ 337 buf, PAGE_SIZE, "%llu\n", (unsigned long long) \ 338 ipath_snap_cntr( \ 339 dd, offsetof(struct infinipath_counters, \ 340 attr) / sizeof(u64))); \ 341 } \ 342 static DEVICE_ATTR(name, S_IRUGO, show_counter_##name, NULL); 343 344DEVICE_COUNTER(ib_link_downeds, IBLinkDownedCnt); 345DEVICE_COUNTER(ib_link_err_recoveries, IBLinkErrRecoveryCnt); 346DEVICE_COUNTER(ib_status_changes, IBStatusChangeCnt); 347DEVICE_COUNTER(ib_symbol_errs, IBSymbolErrCnt); 348DEVICE_COUNTER(lb_flow_stalls, LBFlowStallCnt); 349DEVICE_COUNTER(lb_ints, LBIntCnt); 350DEVICE_COUNTER(rx_bad_formats, RxBadFormatCnt); 351DEVICE_COUNTER(rx_buf_ovfls, RxBufOvflCnt); 352DEVICE_COUNTER(rx_data_pkts, RxDataPktCnt); 353DEVICE_COUNTER(rx_dropped_pkts, RxDroppedPktCnt); 354DEVICE_COUNTER(rx_dwords, RxDwordCnt); 355DEVICE_COUNTER(rx_ebps, RxEBPCnt); 356DEVICE_COUNTER(rx_flow_ctrl_errs, RxFlowCtrlErrCnt); 357DEVICE_COUNTER(rx_flow_pkts, RxFlowPktCnt); 358DEVICE_COUNTER(rx_icrc_errs, RxICRCErrCnt); 359DEVICE_COUNTER(rx_len_errs, RxLenErrCnt); 360DEVICE_COUNTER(rx_link_problems, RxLinkProblemCnt); 361DEVICE_COUNTER(rx_lpcrc_errs, RxLPCRCErrCnt); 362DEVICE_COUNTER(rx_max_min_len_errs, RxMaxMinLenErrCnt); 363DEVICE_COUNTER(rx_p0_hdr_egr_ovfls, RxP0HdrEgrOvflCnt); 364DEVICE_COUNTER(rx_p1_hdr_egr_ovfls, RxP1HdrEgrOvflCnt); 365DEVICE_COUNTER(rx_p2_hdr_egr_ovfls, RxP2HdrEgrOvflCnt); 366DEVICE_COUNTER(rx_p3_hdr_egr_ovfls, RxP3HdrEgrOvflCnt); 367DEVICE_COUNTER(rx_p4_hdr_egr_ovfls, RxP4HdrEgrOvflCnt); 368DEVICE_COUNTER(rx_p5_hdr_egr_ovfls, RxP5HdrEgrOvflCnt); 369DEVICE_COUNTER(rx_p6_hdr_egr_ovfls, RxP6HdrEgrOvflCnt); 370DEVICE_COUNTER(rx_p7_hdr_egr_ovfls, RxP7HdrEgrOvflCnt); 371DEVICE_COUNTER(rx_p8_hdr_egr_ovfls, RxP8HdrEgrOvflCnt); 372DEVICE_COUNTER(rx_pkey_mismatches, RxPKeyMismatchCnt); 373DEVICE_COUNTER(rx_tid_full_errs, RxTIDFullErrCnt); 374DEVICE_COUNTER(rx_tid_valid_errs, RxTIDValidErrCnt); 375DEVICE_COUNTER(rx_vcrc_errs, RxVCRCErrCnt); 376DEVICE_COUNTER(tx_data_pkts, TxDataPktCnt); 377DEVICE_COUNTER(tx_dropped_pkts, TxDroppedPktCnt); 378DEVICE_COUNTER(tx_dwords, TxDwordCnt); 379DEVICE_COUNTER(tx_flow_pkts, TxFlowPktCnt); 380DEVICE_COUNTER(tx_flow_stalls, TxFlowStallCnt); 381DEVICE_COUNTER(tx_len_errs, TxLenErrCnt); 382DEVICE_COUNTER(tx_max_min_len_errs, TxMaxMinLenErrCnt); 383DEVICE_COUNTER(tx_underruns, TxUnderrunCnt); 384DEVICE_COUNTER(tx_unsup_vl_errs, TxUnsupVLErrCnt); 385 386static struct attribute *dev_counter_attributes[] = { 387 &dev_attr_ib_link_downeds.attr, 388 &dev_attr_ib_link_err_recoveries.attr, 389 &dev_attr_ib_status_changes.attr, 390 &dev_attr_ib_symbol_errs.attr, 391 &dev_attr_lb_flow_stalls.attr, 392 &dev_attr_lb_ints.attr, 393 &dev_attr_rx_bad_formats.attr, 394 &dev_attr_rx_buf_ovfls.attr, 395 &dev_attr_rx_data_pkts.attr, 396 &dev_attr_rx_dropped_pkts.attr, 397 &dev_attr_rx_dwords.attr, 398 &dev_attr_rx_ebps.attr, 399 &dev_attr_rx_flow_ctrl_errs.attr, 400 &dev_attr_rx_flow_pkts.attr, 401 &dev_attr_rx_icrc_errs.attr, 402 &dev_attr_rx_len_errs.attr, 403 &dev_attr_rx_link_problems.attr, 404 &dev_attr_rx_lpcrc_errs.attr, 405 &dev_attr_rx_max_min_len_errs.attr, 406 &dev_attr_rx_p0_hdr_egr_ovfls.attr, 407 &dev_attr_rx_p1_hdr_egr_ovfls.attr, 408 &dev_attr_rx_p2_hdr_egr_ovfls.attr, 409 &dev_attr_rx_p3_hdr_egr_ovfls.attr, 410 &dev_attr_rx_p4_hdr_egr_ovfls.attr, 411 &dev_attr_rx_p5_hdr_egr_ovfls.attr, 412 &dev_attr_rx_p6_hdr_egr_ovfls.attr, 413 &dev_attr_rx_p7_hdr_egr_ovfls.attr, 414 &dev_attr_rx_p8_hdr_egr_ovfls.attr, 415 &dev_attr_rx_pkey_mismatches.attr, 416 &dev_attr_rx_tid_full_errs.attr, 417 &dev_attr_rx_tid_valid_errs.attr, 418 &dev_attr_rx_vcrc_errs.attr, 419 &dev_attr_tx_data_pkts.attr, 420 &dev_attr_tx_dropped_pkts.attr, 421 &dev_attr_tx_dwords.attr, 422 &dev_attr_tx_flow_pkts.attr, 423 &dev_attr_tx_flow_stalls.attr, 424 &dev_attr_tx_len_errs.attr, 425 &dev_attr_tx_max_min_len_errs.attr, 426 &dev_attr_tx_underruns.attr, 427 &dev_attr_tx_unsup_vl_errs.attr, 428 NULL 429}; 430 431static struct attribute_group dev_counter_attr_group = { 432 .name = "counters", 433 .attrs = dev_counter_attributes 434}; 435 436static ssize_t store_reset(struct device *dev, 437 struct device_attribute *attr, 438 const char *buf, 439 size_t count) 440{ 441 struct ipath_devdata *dd = dev_get_drvdata(dev); 442 int ret; 443 444 if (count < 5 || memcmp(buf, "reset", 5)) { 445 ret = -EINVAL; 446 goto bail; 447 } 448 449 if (dd->ipath_flags & IPATH_DISABLED) { 450 /* 451 * post-reset init would re-enable interrupts, etc. 452 * so don't allow reset on disabled devices. Not 453 * perfect error, but about the best choice. 454 */ 455 dev_info(dev,"Unit %d is disabled, can't reset\n", 456 dd->ipath_unit); 457 ret = -EINVAL; 458 } 459 ret = ipath_reset_device(dd->ipath_unit); 460bail: 461 return ret<0 ? ret : count; 462} 463 464static ssize_t store_link_state(struct device *dev, 465 struct device_attribute *attr, 466 const char *buf, 467 size_t count) 468{ 469 struct ipath_devdata *dd = dev_get_drvdata(dev); 470 int ret, r; 471 u16 state; 472 473 ret = ipath_parse_ushort(buf, &state); 474 if (ret < 0) 475 goto invalid; 476 477 r = ipath_set_linkstate(dd, state); 478 if (r < 0) { 479 ret = r; 480 goto bail; 481 } 482 483 goto bail; 484invalid: 485 ipath_dev_err(dd, "attempt to set invalid link state\n"); 486bail: 487 return ret; 488} 489 490static ssize_t show_mtu(struct device *dev, 491 struct device_attribute *attr, 492 char *buf) 493{ 494 struct ipath_devdata *dd = dev_get_drvdata(dev); 495 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_ibmtu); 496} 497 498static ssize_t store_mtu(struct device *dev, 499 struct device_attribute *attr, 500 const char *buf, 501 size_t count) 502{ 503 struct ipath_devdata *dd = dev_get_drvdata(dev); 504 ssize_t ret; 505 u16 mtu = 0; 506 int r; 507 508 ret = ipath_parse_ushort(buf, &mtu); 509 if (ret < 0) 510 goto invalid; 511 512 r = ipath_set_mtu(dd, mtu); 513 if (r < 0) 514 ret = r; 515 516 goto bail; 517invalid: 518 ipath_dev_err(dd, "attempt to set invalid MTU\n"); 519bail: 520 return ret; 521} 522 523static ssize_t show_enabled(struct device *dev, 524 struct device_attribute *attr, 525 char *buf) 526{ 527 struct ipath_devdata *dd = dev_get_drvdata(dev); 528 return scnprintf(buf, PAGE_SIZE, "%u\n", 529 (dd->ipath_flags & IPATH_DISABLED) ? 0 : 1); 530} 531 532static ssize_t store_enabled(struct device *dev, 533 struct device_attribute *attr, 534 const char *buf, 535 size_t count) 536{ 537 struct ipath_devdata *dd = dev_get_drvdata(dev); 538 ssize_t ret; 539 u16 enable = 0; 540 541 ret = ipath_parse_ushort(buf, &enable); 542 if (ret < 0) { 543 ipath_dev_err(dd, "attempt to use non-numeric on enable\n"); 544 goto bail; 545 } 546 547 if (enable) { 548 if (!(dd->ipath_flags & IPATH_DISABLED)) 549 goto bail; 550 551 dev_info(dev, "Enabling unit %d\n", dd->ipath_unit); 552 /* same as post-reset */ 553 ret = ipath_init_chip(dd, 1); 554 if (ret) 555 ipath_dev_err(dd, "Failed to enable unit %d\n", 556 dd->ipath_unit); 557 else { 558 dd->ipath_flags &= ~IPATH_DISABLED; 559 *dd->ipath_statusp &= ~IPATH_STATUS_ADMIN_DISABLED; 560 } 561 } 562 else if (!(dd->ipath_flags & IPATH_DISABLED)) { 563 dev_info(dev, "Disabling unit %d\n", dd->ipath_unit); 564 ipath_shutdown_device(dd); 565 dd->ipath_flags |= IPATH_DISABLED; 566 *dd->ipath_statusp |= IPATH_STATUS_ADMIN_DISABLED; 567 } 568 569bail: 570 return ret; 571} 572 573static ssize_t store_rx_pol_inv(struct device *dev, 574 struct device_attribute *attr, 575 const char *buf, 576 size_t count) 577{ 578 struct ipath_devdata *dd = dev_get_drvdata(dev); 579 int ret, r; 580 u16 val; 581 582 ret = ipath_parse_ushort(buf, &val); 583 if (ret < 0) 584 goto invalid; 585 586 r = ipath_set_rx_pol_inv(dd, val); 587 if (r < 0) { 588 ret = r; 589 goto bail; 590 } 591 592 goto bail; 593invalid: 594 ipath_dev_err(dd, "attempt to set invalid Rx Polarity invert\n"); 595bail: 596 return ret; 597} 598 599 600static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); 601static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); 602 603static struct attribute *driver_attributes[] = { 604 &driver_attr_num_units.attr, 605 &driver_attr_version.attr, 606 NULL 607}; 608 609static struct attribute_group driver_attr_group = { 610 .attrs = driver_attributes 611}; 612 613static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); 614static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); 615static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state); 616static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid); 617static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu); 618static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled); 619static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL); 620static DEVICE_ATTR(nports, S_IRUGO, show_nports, NULL); 621static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset); 622static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); 623static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); 624static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL); 625static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); 626static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); 627static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv); 628 629static struct attribute *dev_attributes[] = { 630 &dev_attr_guid.attr, 631 &dev_attr_lid.attr, 632 &dev_attr_link_state.attr, 633 &dev_attr_mlid.attr, 634 &dev_attr_mtu.attr, 635 &dev_attr_nguid.attr, 636 &dev_attr_nports.attr, 637 &dev_attr_serial.attr, 638 &dev_attr_status.attr, 639 &dev_attr_status_str.attr, 640 &dev_attr_boardversion.attr, 641 &dev_attr_unit.attr, 642 &dev_attr_enabled.attr, 643 &dev_attr_rx_pol_inv.attr, 644 NULL 645}; 646 647static struct attribute_group dev_attr_group = { 648 .attrs = dev_attributes 649}; 650 651/** 652 * ipath_expose_reset - create a device reset file 653 * @dev: the device structure 654 * 655 * Only expose a file that lets us reset the device after someone 656 * enters diag mode. A device reset is quite likely to crash the 657 * machine entirely, so we don't want to normally make it 658 * available. 659 * 660 * Called with ipath_mutex held. 661 */ 662int ipath_expose_reset(struct device *dev) 663{ 664 static int exposed; 665 int ret; 666 667 if (!exposed) { 668 ret = device_create_file(dev, &dev_attr_reset); 669 exposed = 1; 670 } 671 else 672 ret = 0; 673 674 return ret; 675} 676 677int ipath_driver_create_group(struct device_driver *drv) 678{ 679 int ret; 680 681 ret = sysfs_create_group(&drv->kobj, &driver_attr_group); 682 683 return ret; 684} 685 686void ipath_driver_remove_group(struct device_driver *drv) 687{ 688 sysfs_remove_group(&drv->kobj, &driver_attr_group); 689} 690 691int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) 692{ 693 int ret; 694 char unit[5]; 695 696 ret = sysfs_create_group(&dev->kobj, &dev_attr_group); 697 if (ret) 698 goto bail; 699 700 ret = sysfs_create_group(&dev->kobj, &dev_counter_attr_group); 701 if (ret) 702 goto bail_attrs; 703 704 snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); 705 ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit); 706 if (ret == 0) 707 goto bail; 708 709 sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); 710bail_attrs: 711 sysfs_remove_group(&dev->kobj, &dev_attr_group); 712bail: 713 return ret; 714} 715 716void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd) 717{ 718 char unit[5]; 719 720 snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); 721 sysfs_remove_link(&dev->driver->kobj, unit); 722 723 sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); 724 sysfs_remove_group(&dev->kobj, &dev_attr_group); 725 726 device_remove_file(dev, &dev_attr_reset); 727} 728