ipath_sysfs.c revision 759d57686dab8169ca68bbf938ce8e965d1e107a
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#include <linux/pci.h> 36 37#include "ipath_kernel.h" 38#include "ips_common.h" 39#include "ipath_layer.h" 40 41/** 42 * ipath_parse_ushort - parse an unsigned short value in an arbitrary base 43 * @str: the string containing the number 44 * @valp: where to put the result 45 * 46 * returns the number of bytes consumed, or negative value on error 47 */ 48int ipath_parse_ushort(const char *str, unsigned short *valp) 49{ 50 unsigned long val; 51 char *end; 52 int ret; 53 54 if (!isdigit(str[0])) { 55 ret = -EINVAL; 56 goto bail; 57 } 58 59 val = simple_strtoul(str, &end, 0); 60 61 if (val > 0xffff) { 62 ret = -EINVAL; 63 goto bail; 64 } 65 66 *valp = val; 67 68 ret = end + 1 - str; 69 if (ret == 0) 70 ret = -EINVAL; 71 72bail: 73 return ret; 74} 75 76static ssize_t show_version(struct device_driver *dev, char *buf) 77{ 78 /* The string printed here is already newline-terminated. */ 79 return scnprintf(buf, PAGE_SIZE, "%s", ipath_core_version); 80} 81 82static ssize_t show_num_units(struct device_driver *dev, char *buf) 83{ 84 return scnprintf(buf, PAGE_SIZE, "%d\n", 85 ipath_count_units(NULL, NULL, NULL)); 86} 87 88#define DRIVER_STAT(name, attr) \ 89 static ssize_t show_stat_##name(struct device_driver *dev, \ 90 char *buf) \ 91 { \ 92 return scnprintf( \ 93 buf, PAGE_SIZE, "%llu\n", \ 94 (unsigned long long) ipath_stats.sps_ ##attr); \ 95 } \ 96 static DRIVER_ATTR(name, S_IRUGO, show_stat_##name, NULL) 97 98DRIVER_STAT(intrs, ints); 99DRIVER_STAT(err_intrs, errints); 100DRIVER_STAT(errs, errs); 101DRIVER_STAT(pkt_errs, pkterrs); 102DRIVER_STAT(crc_errs, crcerrs); 103DRIVER_STAT(hw_errs, hwerrs); 104DRIVER_STAT(ib_link, iblink); 105DRIVER_STAT(port0_pkts, port0pkts); 106DRIVER_STAT(ether_spkts, ether_spkts); 107DRIVER_STAT(ether_rpkts, ether_rpkts); 108DRIVER_STAT(sma_spkts, sma_spkts); 109DRIVER_STAT(sma_rpkts, sma_rpkts); 110DRIVER_STAT(hdrq_full, hdrqfull); 111DRIVER_STAT(etid_full, etidfull); 112DRIVER_STAT(no_piobufs, nopiobufs); 113DRIVER_STAT(ports, ports); 114DRIVER_STAT(pkey0, pkeys[0]); 115DRIVER_STAT(pkey1, pkeys[1]); 116DRIVER_STAT(pkey2, pkeys[2]); 117DRIVER_STAT(pkey3, pkeys[3]); 118/* XXX fix the following when dynamic table of devices used */ 119DRIVER_STAT(lid0, lid[0]); 120DRIVER_STAT(lid1, lid[1]); 121DRIVER_STAT(lid2, lid[2]); 122DRIVER_STAT(lid3, lid[3]); 123 124DRIVER_STAT(nports, nports); 125DRIVER_STAT(null_intr, nullintr); 126DRIVER_STAT(max_pkts_call, maxpkts_call); 127DRIVER_STAT(avg_pkts_call, avgpkts_call); 128DRIVER_STAT(page_locks, pagelocks); 129DRIVER_STAT(page_unlocks, pageunlocks); 130DRIVER_STAT(krdrops, krdrops); 131/* XXX fix the following when dynamic table of devices used */ 132DRIVER_STAT(mlid0, mlid[0]); 133DRIVER_STAT(mlid1, mlid[1]); 134DRIVER_STAT(mlid2, mlid[2]); 135DRIVER_STAT(mlid3, mlid[3]); 136 137static struct attribute *driver_stat_attributes[] = { 138 &driver_attr_intrs.attr, 139 &driver_attr_err_intrs.attr, 140 &driver_attr_errs.attr, 141 &driver_attr_pkt_errs.attr, 142 &driver_attr_crc_errs.attr, 143 &driver_attr_hw_errs.attr, 144 &driver_attr_ib_link.attr, 145 &driver_attr_port0_pkts.attr, 146 &driver_attr_ether_spkts.attr, 147 &driver_attr_ether_rpkts.attr, 148 &driver_attr_sma_spkts.attr, 149 &driver_attr_sma_rpkts.attr, 150 &driver_attr_hdrq_full.attr, 151 &driver_attr_etid_full.attr, 152 &driver_attr_no_piobufs.attr, 153 &driver_attr_ports.attr, 154 &driver_attr_pkey0.attr, 155 &driver_attr_pkey1.attr, 156 &driver_attr_pkey2.attr, 157 &driver_attr_pkey3.attr, 158 &driver_attr_lid0.attr, 159 &driver_attr_lid1.attr, 160 &driver_attr_lid2.attr, 161 &driver_attr_lid3.attr, 162 &driver_attr_nports.attr, 163 &driver_attr_null_intr.attr, 164 &driver_attr_max_pkts_call.attr, 165 &driver_attr_avg_pkts_call.attr, 166 &driver_attr_page_locks.attr, 167 &driver_attr_page_unlocks.attr, 168 &driver_attr_krdrops.attr, 169 &driver_attr_mlid0.attr, 170 &driver_attr_mlid1.attr, 171 &driver_attr_mlid2.attr, 172 &driver_attr_mlid3.attr, 173 NULL 174}; 175 176static struct attribute_group driver_stat_attr_group = { 177 .name = "stats", 178 .attrs = driver_stat_attributes 179}; 180 181static ssize_t show_status(struct device *dev, 182 struct device_attribute *attr, 183 char *buf) 184{ 185 struct ipath_devdata *dd = dev_get_drvdata(dev); 186 ssize_t ret; 187 188 if (!dd->ipath_statusp) { 189 ret = -EINVAL; 190 goto bail; 191 } 192 193 ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n", 194 (unsigned long long) *(dd->ipath_statusp)); 195 196bail: 197 return ret; 198} 199 200static const char *ipath_status_str[] = { 201 "Initted", 202 "Disabled", 203 "Admin_Disabled", 204 "OIB_SMA", 205 "SMA", 206 "Present", 207 "IB_link_up", 208 "IB_configured", 209 "NoIBcable", 210 "Fatal_Hardware_Error", 211 NULL, 212}; 213 214static ssize_t show_status_str(struct device *dev, 215 struct device_attribute *attr, 216 char *buf) 217{ 218 struct ipath_devdata *dd = dev_get_drvdata(dev); 219 int i, any; 220 u64 s; 221 ssize_t ret; 222 223 if (!dd->ipath_statusp) { 224 ret = -EINVAL; 225 goto bail; 226 } 227 228 s = *(dd->ipath_statusp); 229 *buf = '\0'; 230 for (any = i = 0; s && ipath_status_str[i]; i++) { 231 if (s & 1) { 232 if (any && strlcat(buf, " ", PAGE_SIZE) >= 233 PAGE_SIZE) 234 /* overflow */ 235 break; 236 if (strlcat(buf, ipath_status_str[i], 237 PAGE_SIZE) >= PAGE_SIZE) 238 break; 239 any = 1; 240 } 241 s >>= 1; 242 } 243 if (any) 244 strlcat(buf, "\n", PAGE_SIZE); 245 246 ret = strlen(buf); 247 248bail: 249 return ret; 250} 251 252static ssize_t show_boardversion(struct device *dev, 253 struct device_attribute *attr, 254 char *buf) 255{ 256 struct ipath_devdata *dd = dev_get_drvdata(dev); 257 /* The string printed here is already newline-terminated. */ 258 return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion); 259} 260 261static ssize_t show_lid(struct device *dev, 262 struct device_attribute *attr, 263 char *buf) 264{ 265 struct ipath_devdata *dd = dev_get_drvdata(dev); 266 267 return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_lid); 268} 269 270static ssize_t store_lid(struct device *dev, 271 struct device_attribute *attr, 272 const char *buf, 273 size_t count) 274{ 275 struct ipath_devdata *dd = dev_get_drvdata(dev); 276 u16 lid; 277 int ret; 278 279 ret = ipath_parse_ushort(buf, &lid); 280 if (ret < 0) 281 goto invalid; 282 283 if (lid == 0 || lid >= 0xc000) { 284 ret = -EINVAL; 285 goto invalid; 286 } 287 288 ipath_set_sps_lid(dd, lid, 0); 289 290 goto bail; 291invalid: 292 ipath_dev_err(dd, "attempt to set invalid LID\n"); 293bail: 294 return ret; 295} 296 297static ssize_t show_mlid(struct device *dev, 298 struct device_attribute *attr, 299 char *buf) 300{ 301 struct ipath_devdata *dd = dev_get_drvdata(dev); 302 303 return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_mlid); 304} 305 306static ssize_t store_mlid(struct device *dev, 307 struct device_attribute *attr, 308 const char *buf, 309 size_t count) 310{ 311 struct ipath_devdata *dd = dev_get_drvdata(dev); 312 int unit; 313 u16 mlid; 314 int ret; 315 316 ret = ipath_parse_ushort(buf, &mlid); 317 if (ret < 0) 318 goto invalid; 319 320 unit = dd->ipath_unit; 321 322 dd->ipath_mlid = mlid; 323 ipath_stats.sps_mlid[unit] = mlid; 324 ipath_layer_intr(dd, IPATH_LAYER_INT_BCAST); 325 326 goto bail; 327invalid: 328 ipath_dev_err(dd, "attempt to set invalid MLID\n"); 329bail: 330 return ret; 331} 332 333static ssize_t show_guid(struct device *dev, 334 struct device_attribute *attr, 335 char *buf) 336{ 337 struct ipath_devdata *dd = dev_get_drvdata(dev); 338 u8 *guid; 339 340 guid = (u8 *) & (dd->ipath_guid); 341 342 return scnprintf(buf, PAGE_SIZE, 343 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 344 guid[0], guid[1], guid[2], guid[3], 345 guid[4], guid[5], guid[6], guid[7]); 346} 347 348static ssize_t store_guid(struct device *dev, 349 struct device_attribute *attr, 350 const char *buf, 351 size_t count) 352{ 353 struct ipath_devdata *dd = dev_get_drvdata(dev); 354 ssize_t ret; 355 unsigned short guid[8]; 356 __be64 nguid; 357 u8 *ng; 358 int i; 359 360 if (sscanf(buf, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", 361 &guid[0], &guid[1], &guid[2], &guid[3], 362 &guid[4], &guid[5], &guid[6], &guid[7]) != 8) 363 goto invalid; 364 365 ng = (u8 *) &nguid; 366 367 for (i = 0; i < 8; i++) { 368 if (guid[i] > 0xff) 369 goto invalid; 370 ng[i] = guid[i]; 371 } 372 373 dd->ipath_guid = nguid; 374 dd->ipath_nguid = 1; 375 376 ret = strlen(buf); 377 goto bail; 378 379invalid: 380 ipath_dev_err(dd, "attempt to set invalid GUID\n"); 381 ret = -EINVAL; 382 383bail: 384 return ret; 385} 386 387static ssize_t show_nguid(struct device *dev, 388 struct device_attribute *attr, 389 char *buf) 390{ 391 struct ipath_devdata *dd = dev_get_drvdata(dev); 392 393 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid); 394} 395 396static ssize_t show_serial(struct device *dev, 397 struct device_attribute *attr, 398 char *buf) 399{ 400 struct ipath_devdata *dd = dev_get_drvdata(dev); 401 402 buf[sizeof dd->ipath_serial] = '\0'; 403 memcpy(buf, dd->ipath_serial, sizeof dd->ipath_serial); 404 strcat(buf, "\n"); 405 return strlen(buf); 406} 407 408static ssize_t show_unit(struct device *dev, 409 struct device_attribute *attr, 410 char *buf) 411{ 412 struct ipath_devdata *dd = dev_get_drvdata(dev); 413 414 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit); 415} 416 417#define DEVICE_COUNTER(name, attr) \ 418 static ssize_t show_counter_##name(struct device *dev, \ 419 struct device_attribute *attr, \ 420 char *buf) \ 421 { \ 422 struct ipath_devdata *dd = dev_get_drvdata(dev); \ 423 return scnprintf(\ 424 buf, PAGE_SIZE, "%llu\n", (unsigned long long) \ 425 ipath_snap_cntr( \ 426 dd, offsetof(struct infinipath_counters, \ 427 attr) / sizeof(u64))); \ 428 } \ 429 static DEVICE_ATTR(name, S_IRUGO, show_counter_##name, NULL); 430 431DEVICE_COUNTER(ib_link_downeds, IBLinkDownedCnt); 432DEVICE_COUNTER(ib_link_err_recoveries, IBLinkErrRecoveryCnt); 433DEVICE_COUNTER(ib_status_changes, IBStatusChangeCnt); 434DEVICE_COUNTER(ib_symbol_errs, IBSymbolErrCnt); 435DEVICE_COUNTER(lb_flow_stalls, LBFlowStallCnt); 436DEVICE_COUNTER(lb_ints, LBIntCnt); 437DEVICE_COUNTER(rx_bad_formats, RxBadFormatCnt); 438DEVICE_COUNTER(rx_buf_ovfls, RxBufOvflCnt); 439DEVICE_COUNTER(rx_data_pkts, RxDataPktCnt); 440DEVICE_COUNTER(rx_dropped_pkts, RxDroppedPktCnt); 441DEVICE_COUNTER(rx_dwords, RxDwordCnt); 442DEVICE_COUNTER(rx_ebps, RxEBPCnt); 443DEVICE_COUNTER(rx_flow_ctrl_errs, RxFlowCtrlErrCnt); 444DEVICE_COUNTER(rx_flow_pkts, RxFlowPktCnt); 445DEVICE_COUNTER(rx_icrc_errs, RxICRCErrCnt); 446DEVICE_COUNTER(rx_len_errs, RxLenErrCnt); 447DEVICE_COUNTER(rx_link_problems, RxLinkProblemCnt); 448DEVICE_COUNTER(rx_lpcrc_errs, RxLPCRCErrCnt); 449DEVICE_COUNTER(rx_max_min_len_errs, RxMaxMinLenErrCnt); 450DEVICE_COUNTER(rx_p0_hdr_egr_ovfls, RxP0HdrEgrOvflCnt); 451DEVICE_COUNTER(rx_p1_hdr_egr_ovfls, RxP1HdrEgrOvflCnt); 452DEVICE_COUNTER(rx_p2_hdr_egr_ovfls, RxP2HdrEgrOvflCnt); 453DEVICE_COUNTER(rx_p3_hdr_egr_ovfls, RxP3HdrEgrOvflCnt); 454DEVICE_COUNTER(rx_p4_hdr_egr_ovfls, RxP4HdrEgrOvflCnt); 455DEVICE_COUNTER(rx_p5_hdr_egr_ovfls, RxP5HdrEgrOvflCnt); 456DEVICE_COUNTER(rx_p6_hdr_egr_ovfls, RxP6HdrEgrOvflCnt); 457DEVICE_COUNTER(rx_p7_hdr_egr_ovfls, RxP7HdrEgrOvflCnt); 458DEVICE_COUNTER(rx_p8_hdr_egr_ovfls, RxP8HdrEgrOvflCnt); 459DEVICE_COUNTER(rx_pkey_mismatches, RxPKeyMismatchCnt); 460DEVICE_COUNTER(rx_tid_full_errs, RxTIDFullErrCnt); 461DEVICE_COUNTER(rx_tid_valid_errs, RxTIDValidErrCnt); 462DEVICE_COUNTER(rx_vcrc_errs, RxVCRCErrCnt); 463DEVICE_COUNTER(tx_data_pkts, TxDataPktCnt); 464DEVICE_COUNTER(tx_dropped_pkts, TxDroppedPktCnt); 465DEVICE_COUNTER(tx_dwords, TxDwordCnt); 466DEVICE_COUNTER(tx_flow_pkts, TxFlowPktCnt); 467DEVICE_COUNTER(tx_flow_stalls, TxFlowStallCnt); 468DEVICE_COUNTER(tx_len_errs, TxLenErrCnt); 469DEVICE_COUNTER(tx_max_min_len_errs, TxMaxMinLenErrCnt); 470DEVICE_COUNTER(tx_underruns, TxUnderrunCnt); 471DEVICE_COUNTER(tx_unsup_vl_errs, TxUnsupVLErrCnt); 472 473static struct attribute *dev_counter_attributes[] = { 474 &dev_attr_ib_link_downeds.attr, 475 &dev_attr_ib_link_err_recoveries.attr, 476 &dev_attr_ib_status_changes.attr, 477 &dev_attr_ib_symbol_errs.attr, 478 &dev_attr_lb_flow_stalls.attr, 479 &dev_attr_lb_ints.attr, 480 &dev_attr_rx_bad_formats.attr, 481 &dev_attr_rx_buf_ovfls.attr, 482 &dev_attr_rx_data_pkts.attr, 483 &dev_attr_rx_dropped_pkts.attr, 484 &dev_attr_rx_dwords.attr, 485 &dev_attr_rx_ebps.attr, 486 &dev_attr_rx_flow_ctrl_errs.attr, 487 &dev_attr_rx_flow_pkts.attr, 488 &dev_attr_rx_icrc_errs.attr, 489 &dev_attr_rx_len_errs.attr, 490 &dev_attr_rx_link_problems.attr, 491 &dev_attr_rx_lpcrc_errs.attr, 492 &dev_attr_rx_max_min_len_errs.attr, 493 &dev_attr_rx_p0_hdr_egr_ovfls.attr, 494 &dev_attr_rx_p1_hdr_egr_ovfls.attr, 495 &dev_attr_rx_p2_hdr_egr_ovfls.attr, 496 &dev_attr_rx_p3_hdr_egr_ovfls.attr, 497 &dev_attr_rx_p4_hdr_egr_ovfls.attr, 498 &dev_attr_rx_p5_hdr_egr_ovfls.attr, 499 &dev_attr_rx_p6_hdr_egr_ovfls.attr, 500 &dev_attr_rx_p7_hdr_egr_ovfls.attr, 501 &dev_attr_rx_p8_hdr_egr_ovfls.attr, 502 &dev_attr_rx_pkey_mismatches.attr, 503 &dev_attr_rx_tid_full_errs.attr, 504 &dev_attr_rx_tid_valid_errs.attr, 505 &dev_attr_rx_vcrc_errs.attr, 506 &dev_attr_tx_data_pkts.attr, 507 &dev_attr_tx_dropped_pkts.attr, 508 &dev_attr_tx_dwords.attr, 509 &dev_attr_tx_flow_pkts.attr, 510 &dev_attr_tx_flow_stalls.attr, 511 &dev_attr_tx_len_errs.attr, 512 &dev_attr_tx_max_min_len_errs.attr, 513 &dev_attr_tx_underruns.attr, 514 &dev_attr_tx_unsup_vl_errs.attr, 515 NULL 516}; 517 518static struct attribute_group dev_counter_attr_group = { 519 .name = "counters", 520 .attrs = dev_counter_attributes 521}; 522 523static ssize_t store_reset(struct device *dev, 524 struct device_attribute *attr, 525 const char *buf, 526 size_t count) 527{ 528 struct ipath_devdata *dd = dev_get_drvdata(dev); 529 int ret; 530 531 if (count < 5 || memcmp(buf, "reset", 5)) { 532 ret = -EINVAL; 533 goto bail; 534 } 535 536 if (dd->ipath_flags & IPATH_DISABLED) { 537 /* 538 * post-reset init would re-enable interrupts, etc. 539 * so don't allow reset on disabled devices. Not 540 * perfect error, but about the best choice. 541 */ 542 dev_info(dev,"Unit %d is disabled, can't reset\n", 543 dd->ipath_unit); 544 ret = -EINVAL; 545 } 546 ret = ipath_reset_device(dd->ipath_unit); 547bail: 548 return ret<0 ? ret : count; 549} 550 551static ssize_t store_link_state(struct device *dev, 552 struct device_attribute *attr, 553 const char *buf, 554 size_t count) 555{ 556 struct ipath_devdata *dd = dev_get_drvdata(dev); 557 int ret, r; 558 u16 state; 559 560 ret = ipath_parse_ushort(buf, &state); 561 if (ret < 0) 562 goto invalid; 563 564 r = ipath_layer_set_linkstate(dd, state); 565 if (r < 0) { 566 ret = r; 567 goto bail; 568 } 569 570 goto bail; 571invalid: 572 ipath_dev_err(dd, "attempt to set invalid link state\n"); 573bail: 574 return ret; 575} 576 577static ssize_t show_mtu(struct device *dev, 578 struct device_attribute *attr, 579 char *buf) 580{ 581 struct ipath_devdata *dd = dev_get_drvdata(dev); 582 return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_ibmtu); 583} 584 585static ssize_t store_mtu(struct device *dev, 586 struct device_attribute *attr, 587 const char *buf, 588 size_t count) 589{ 590 struct ipath_devdata *dd = dev_get_drvdata(dev); 591 ssize_t ret; 592 u16 mtu = 0; 593 int r; 594 595 ret = ipath_parse_ushort(buf, &mtu); 596 if (ret < 0) 597 goto invalid; 598 599 r = ipath_layer_set_mtu(dd, mtu); 600 if (r < 0) 601 ret = r; 602 603 goto bail; 604invalid: 605 ipath_dev_err(dd, "attempt to set invalid MTU\n"); 606bail: 607 return ret; 608} 609 610static ssize_t show_enabled(struct device *dev, 611 struct device_attribute *attr, 612 char *buf) 613{ 614 struct ipath_devdata *dd = dev_get_drvdata(dev); 615 return scnprintf(buf, PAGE_SIZE, "%u\n", 616 (dd->ipath_flags & IPATH_DISABLED) ? 0 : 1); 617} 618 619static ssize_t store_enabled(struct device *dev, 620 struct device_attribute *attr, 621 const char *buf, 622 size_t count) 623{ 624 struct ipath_devdata *dd = dev_get_drvdata(dev); 625 ssize_t ret; 626 u16 enable = 0; 627 628 ret = ipath_parse_ushort(buf, &enable); 629 if (ret < 0) { 630 ipath_dev_err(dd, "attempt to use non-numeric on enable\n"); 631 goto bail; 632 } 633 634 if (enable) { 635 if (!(dd->ipath_flags & IPATH_DISABLED)) 636 goto bail; 637 638 dev_info(dev, "Enabling unit %d\n", dd->ipath_unit); 639 /* same as post-reset */ 640 ret = ipath_init_chip(dd, 1); 641 if (ret) 642 ipath_dev_err(dd, "Failed to enable unit %d\n", 643 dd->ipath_unit); 644 else { 645 dd->ipath_flags &= ~IPATH_DISABLED; 646 *dd->ipath_statusp &= ~IPATH_STATUS_ADMIN_DISABLED; 647 } 648 } 649 else if (!(dd->ipath_flags & IPATH_DISABLED)) { 650 dev_info(dev, "Disabling unit %d\n", dd->ipath_unit); 651 ipath_shutdown_device(dd); 652 dd->ipath_flags |= IPATH_DISABLED; 653 *dd->ipath_statusp |= IPATH_STATUS_ADMIN_DISABLED; 654 } 655 656bail: 657 return ret; 658} 659 660static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); 661static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); 662 663static struct attribute *driver_attributes[] = { 664 &driver_attr_num_units.attr, 665 &driver_attr_version.attr, 666 NULL 667}; 668 669static struct attribute_group driver_attr_group = { 670 .attrs = driver_attributes 671}; 672 673static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); 674static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); 675static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state); 676static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid); 677static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu); 678static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled); 679static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL); 680static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset); 681static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); 682static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); 683static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL); 684static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); 685static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); 686 687static struct attribute *dev_attributes[] = { 688 &dev_attr_guid.attr, 689 &dev_attr_lid.attr, 690 &dev_attr_link_state.attr, 691 &dev_attr_mlid.attr, 692 &dev_attr_mtu.attr, 693 &dev_attr_nguid.attr, 694 &dev_attr_serial.attr, 695 &dev_attr_status.attr, 696 &dev_attr_status_str.attr, 697 &dev_attr_boardversion.attr, 698 &dev_attr_unit.attr, 699 &dev_attr_enabled.attr, 700 NULL 701}; 702 703static struct attribute_group dev_attr_group = { 704 .attrs = dev_attributes 705}; 706 707/** 708 * ipath_expose_reset - create a device reset file 709 * @dev: the device structure 710 * 711 * Only expose a file that lets us reset the device after someone 712 * enters diag mode. A device reset is quite likely to crash the 713 * machine entirely, so we don't want to normally make it 714 * available. 715 * 716 * Called with ipath_mutex held. 717 */ 718int ipath_expose_reset(struct device *dev) 719{ 720 static int exposed; 721 int ret; 722 723 if (!exposed) { 724 ret = device_create_file(dev, &dev_attr_reset); 725 exposed = 1; 726 } 727 else 728 ret = 0; 729 730 return ret; 731} 732 733int ipath_driver_create_group(struct device_driver *drv) 734{ 735 int ret; 736 737 ret = sysfs_create_group(&drv->kobj, &driver_attr_group); 738 if (ret) 739 goto bail; 740 741 ret = sysfs_create_group(&drv->kobj, &driver_stat_attr_group); 742 if (ret) 743 sysfs_remove_group(&drv->kobj, &driver_attr_group); 744 745bail: 746 return ret; 747} 748 749void ipath_driver_remove_group(struct device_driver *drv) 750{ 751 sysfs_remove_group(&drv->kobj, &driver_stat_attr_group); 752 sysfs_remove_group(&drv->kobj, &driver_attr_group); 753} 754 755int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) 756{ 757 int ret; 758 char unit[5]; 759 760 ret = sysfs_create_group(&dev->kobj, &dev_attr_group); 761 if (ret) 762 goto bail; 763 764 ret = sysfs_create_group(&dev->kobj, &dev_counter_attr_group); 765 if (ret) 766 goto bail_attrs; 767 768 snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); 769 ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit); 770 if (ret == 0) 771 goto bail; 772 773 sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); 774bail_attrs: 775 sysfs_remove_group(&dev->kobj, &dev_attr_group); 776bail: 777 return ret; 778} 779 780void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd) 781{ 782 char unit[5]; 783 784 snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); 785 sysfs_remove_link(&dev->driver->kobj, unit); 786 787 sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); 788 sysfs_remove_group(&dev->kobj, &dev_attr_group); 789 790 device_remove_file(dev, &dev_attr_reset); 791} 792