.. | .. |
---|
4 | 4 | * |
---|
5 | 5 | * sysfs attributes. |
---|
6 | 6 | * |
---|
7 | | - * Copyright IBM Corp. 2008, 2010 |
---|
| 7 | + * Copyright IBM Corp. 2008, 2020 |
---|
8 | 8 | */ |
---|
9 | 9 | |
---|
10 | 10 | #define KMSG_COMPONENT "zfcp" |
---|
11 | 11 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
---|
12 | 12 | |
---|
13 | 13 | #include <linux/slab.h> |
---|
| 14 | +#include "zfcp_diag.h" |
---|
14 | 15 | #include "zfcp_ext.h" |
---|
15 | 16 | |
---|
16 | 17 | #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ |
---|
.. | .. |
---|
215 | 216 | { |
---|
216 | 217 | struct ccw_device *cdev = to_ccwdev(dev); |
---|
217 | 218 | struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
---|
| 219 | + int retval = 0; |
---|
218 | 220 | |
---|
219 | 221 | if (!adapter) |
---|
220 | 222 | return -ENODEV; |
---|
| 223 | + |
---|
| 224 | + /* |
---|
| 225 | + * If `scsi_host` is missing, we can't schedule `scan_work`, as it |
---|
| 226 | + * makes use of the corresponding fc_host object. But this state is |
---|
| 227 | + * only possible if xconfig/xport data has never completed yet, |
---|
| 228 | + * and we couldn't successfully scan for ports anyway. |
---|
| 229 | + */ |
---|
| 230 | + if (adapter->scsi_host == NULL) { |
---|
| 231 | + retval = -ENODEV; |
---|
| 232 | + goto out; |
---|
| 233 | + } |
---|
221 | 234 | |
---|
222 | 235 | /* |
---|
223 | 236 | * Users wish is our command: immediately schedule and flush a |
---|
.. | .. |
---|
226 | 239 | */ |
---|
227 | 240 | queue_delayed_work(adapter->work_queue, &adapter->scan_work, 0); |
---|
228 | 241 | flush_delayed_work(&adapter->scan_work); |
---|
| 242 | +out: |
---|
229 | 243 | zfcp_ccw_adapter_put(adapter); |
---|
230 | | - |
---|
231 | | - return (ssize_t) count; |
---|
| 244 | + return retval ? retval : (ssize_t) count; |
---|
232 | 245 | } |
---|
233 | 246 | static ZFCP_DEV_ATTR(adapter, port_rescan, S_IWUSR, NULL, |
---|
234 | 247 | zfcp_sysfs_port_rescan_store); |
---|
.. | .. |
---|
325 | 338 | static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, |
---|
326 | 339 | zfcp_sysfs_port_remove_store); |
---|
327 | 340 | |
---|
| 341 | +static ssize_t |
---|
| 342 | +zfcp_sysfs_adapter_diag_max_age_show(struct device *dev, |
---|
| 343 | + struct device_attribute *attr, char *buf) |
---|
| 344 | +{ |
---|
| 345 | + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); |
---|
| 346 | + ssize_t rc; |
---|
| 347 | + |
---|
| 348 | + if (!adapter) |
---|
| 349 | + return -ENODEV; |
---|
| 350 | + |
---|
| 351 | + /* ceil(log(2^64 - 1) / log(10)) = 20 */ |
---|
| 352 | + rc = scnprintf(buf, 20 + 2, "%lu\n", adapter->diagnostics->max_age); |
---|
| 353 | + |
---|
| 354 | + zfcp_ccw_adapter_put(adapter); |
---|
| 355 | + return rc; |
---|
| 356 | +} |
---|
| 357 | + |
---|
| 358 | +static ssize_t |
---|
| 359 | +zfcp_sysfs_adapter_diag_max_age_store(struct device *dev, |
---|
| 360 | + struct device_attribute *attr, |
---|
| 361 | + const char *buf, size_t count) |
---|
| 362 | +{ |
---|
| 363 | + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); |
---|
| 364 | + unsigned long max_age; |
---|
| 365 | + ssize_t rc; |
---|
| 366 | + |
---|
| 367 | + if (!adapter) |
---|
| 368 | + return -ENODEV; |
---|
| 369 | + |
---|
| 370 | + rc = kstrtoul(buf, 10, &max_age); |
---|
| 371 | + if (rc != 0) |
---|
| 372 | + goto out; |
---|
| 373 | + |
---|
| 374 | + adapter->diagnostics->max_age = max_age; |
---|
| 375 | + |
---|
| 376 | + rc = count; |
---|
| 377 | +out: |
---|
| 378 | + zfcp_ccw_adapter_put(adapter); |
---|
| 379 | + return rc; |
---|
| 380 | +} |
---|
| 381 | +static ZFCP_DEV_ATTR(adapter, diag_max_age, 0644, |
---|
| 382 | + zfcp_sysfs_adapter_diag_max_age_show, |
---|
| 383 | + zfcp_sysfs_adapter_diag_max_age_store); |
---|
| 384 | + |
---|
| 385 | +static ssize_t zfcp_sysfs_adapter_fc_security_show( |
---|
| 386 | + struct device *dev, struct device_attribute *attr, char *buf) |
---|
| 387 | +{ |
---|
| 388 | + struct ccw_device *cdev = to_ccwdev(dev); |
---|
| 389 | + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev); |
---|
| 390 | + unsigned int status; |
---|
| 391 | + int i; |
---|
| 392 | + |
---|
| 393 | + if (!adapter) |
---|
| 394 | + return -ENODEV; |
---|
| 395 | + |
---|
| 396 | + /* |
---|
| 397 | + * Adapter status COMMON_OPEN implies xconf data and xport data |
---|
| 398 | + * was done. Adapter FC Endpoint Security capability remains |
---|
| 399 | + * unchanged in case of COMMON_ERP_FAILED (e.g. due to local link |
---|
| 400 | + * down). |
---|
| 401 | + */ |
---|
| 402 | + status = atomic_read(&adapter->status); |
---|
| 403 | + if (0 == (status & ZFCP_STATUS_COMMON_OPEN)) |
---|
| 404 | + i = sprintf(buf, "unknown\n"); |
---|
| 405 | + else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY)) |
---|
| 406 | + i = sprintf(buf, "unsupported\n"); |
---|
| 407 | + else { |
---|
| 408 | + i = zfcp_fsf_scnprint_fc_security( |
---|
| 409 | + buf, PAGE_SIZE - 1, adapter->fc_security_algorithms, |
---|
| 410 | + ZFCP_FSF_PRINT_FMT_LIST); |
---|
| 411 | + i += scnprintf(buf + i, PAGE_SIZE - i, "\n"); |
---|
| 412 | + } |
---|
| 413 | + |
---|
| 414 | + zfcp_ccw_adapter_put(adapter); |
---|
| 415 | + return i; |
---|
| 416 | +} |
---|
| 417 | +static ZFCP_DEV_ATTR(adapter, fc_security, S_IRUGO, |
---|
| 418 | + zfcp_sysfs_adapter_fc_security_show, |
---|
| 419 | + NULL); |
---|
| 420 | + |
---|
328 | 421 | static struct attribute *zfcp_adapter_attrs[] = { |
---|
329 | 422 | &dev_attr_adapter_failed.attr, |
---|
330 | 423 | &dev_attr_adapter_in_recovery.attr, |
---|
.. | .. |
---|
337 | 430 | &dev_attr_adapter_lic_version.attr, |
---|
338 | 431 | &dev_attr_adapter_status.attr, |
---|
339 | 432 | &dev_attr_adapter_hardware_version.attr, |
---|
| 433 | + &dev_attr_adapter_diag_max_age.attr, |
---|
| 434 | + &dev_attr_adapter_fc_security.attr, |
---|
340 | 435 | NULL |
---|
341 | 436 | }; |
---|
342 | 437 | |
---|
.. | .. |
---|
380 | 475 | } |
---|
381 | 476 | static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store); |
---|
382 | 477 | |
---|
| 478 | +static ssize_t zfcp_sysfs_port_fc_security_show(struct device *dev, |
---|
| 479 | + struct device_attribute *attr, |
---|
| 480 | + char *buf) |
---|
| 481 | +{ |
---|
| 482 | + struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); |
---|
| 483 | + struct zfcp_adapter *adapter = port->adapter; |
---|
| 484 | + unsigned int status = atomic_read(&port->status); |
---|
| 485 | + int i; |
---|
| 486 | + |
---|
| 487 | + if (0 == (status & ZFCP_STATUS_COMMON_OPEN) || |
---|
| 488 | + 0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) || |
---|
| 489 | + 0 == (status & ZFCP_STATUS_PORT_PHYS_OPEN) || |
---|
| 490 | + 0 != (status & ZFCP_STATUS_PORT_LINK_TEST) || |
---|
| 491 | + 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED) || |
---|
| 492 | + 0 != (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) |
---|
| 493 | + i = sprintf(buf, "unknown\n"); |
---|
| 494 | + else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY)) |
---|
| 495 | + i = sprintf(buf, "unsupported\n"); |
---|
| 496 | + else { |
---|
| 497 | + i = zfcp_fsf_scnprint_fc_security( |
---|
| 498 | + buf, PAGE_SIZE - 1, port->connection_info, |
---|
| 499 | + ZFCP_FSF_PRINT_FMT_SINGLEITEM); |
---|
| 500 | + i += scnprintf(buf + i, PAGE_SIZE - i, "\n"); |
---|
| 501 | + } |
---|
| 502 | + |
---|
| 503 | + return i; |
---|
| 504 | +} |
---|
| 505 | +static ZFCP_DEV_ATTR(port, fc_security, S_IRUGO, |
---|
| 506 | + zfcp_sysfs_port_fc_security_show, |
---|
| 507 | + NULL); |
---|
| 508 | + |
---|
383 | 509 | static struct attribute *zfcp_port_attrs[] = { |
---|
384 | 510 | &dev_attr_unit_add.attr, |
---|
385 | 511 | &dev_attr_unit_remove.attr, |
---|
.. | .. |
---|
387 | 513 | &dev_attr_port_in_recovery.attr, |
---|
388 | 514 | &dev_attr_port_status.attr, |
---|
389 | 515 | &dev_attr_port_access_denied.attr, |
---|
| 516 | + &dev_attr_port_fc_security.attr, |
---|
390 | 517 | NULL |
---|
391 | 518 | }; |
---|
392 | 519 | static struct attribute_group zfcp_port_attr_group = { |
---|
.. | .. |
---|
577 | 704 | return -ENOMEM; |
---|
578 | 705 | |
---|
579 | 706 | retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port); |
---|
580 | | - if (!retval) |
---|
| 707 | + if (retval == 0 || retval == -EAGAIN) |
---|
581 | 708 | retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, |
---|
582 | 709 | qtcb_port->cb_util, qtcb_port->a_util); |
---|
583 | 710 | kfree(qtcb_port); |
---|
.. | .. |
---|
603 | 730 | return -ENOMEM; |
---|
604 | 731 | |
---|
605 | 732 | retval = zfcp_fsf_exchange_config_data_sync(adapter->qdio, qtcb_config); |
---|
606 | | - if (!retval) |
---|
| 733 | + if (retval == 0 || retval == -EAGAIN) |
---|
607 | 734 | *stat_inf = qtcb_config->stat_info; |
---|
608 | 735 | |
---|
609 | 736 | kfree(qtcb_config); |
---|
.. | .. |
---|
664 | 791 | &dev_attr_queue_full, |
---|
665 | 792 | NULL |
---|
666 | 793 | }; |
---|
| 794 | + |
---|
| 795 | +static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show( |
---|
| 796 | + struct device *dev, struct device_attribute *attr, char *buf) |
---|
| 797 | +{ |
---|
| 798 | + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); |
---|
| 799 | + struct zfcp_diag_header *diag_hdr; |
---|
| 800 | + struct fc_els_flogi *nsp; |
---|
| 801 | + ssize_t rc = -ENOLINK; |
---|
| 802 | + unsigned long flags; |
---|
| 803 | + unsigned int status; |
---|
| 804 | + |
---|
| 805 | + if (!adapter) |
---|
| 806 | + return -ENODEV; |
---|
| 807 | + |
---|
| 808 | + status = atomic_read(&adapter->status); |
---|
| 809 | + if (0 == (status & ZFCP_STATUS_COMMON_OPEN) || |
---|
| 810 | + 0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) || |
---|
| 811 | + 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED)) |
---|
| 812 | + goto out; |
---|
| 813 | + |
---|
| 814 | + diag_hdr = &adapter->diagnostics->config_data.header; |
---|
| 815 | + |
---|
| 816 | + rc = zfcp_diag_update_buffer_limited( |
---|
| 817 | + adapter, diag_hdr, zfcp_diag_update_config_data_buffer); |
---|
| 818 | + if (rc != 0) |
---|
| 819 | + goto out; |
---|
| 820 | + |
---|
| 821 | + spin_lock_irqsave(&diag_hdr->access_lock, flags); |
---|
| 822 | + /* nport_serv_param doesn't contain the ELS_Command code */ |
---|
| 823 | + nsp = (struct fc_els_flogi *)((unsigned long) |
---|
| 824 | + adapter->diagnostics->config_data |
---|
| 825 | + .data.nport_serv_param - |
---|
| 826 | + sizeof(u32)); |
---|
| 827 | + |
---|
| 828 | + rc = scnprintf(buf, 5 + 2, "%hu\n", |
---|
| 829 | + be16_to_cpu(nsp->fl_csp.sp_bb_cred)); |
---|
| 830 | + spin_unlock_irqrestore(&diag_hdr->access_lock, flags); |
---|
| 831 | + |
---|
| 832 | +out: |
---|
| 833 | + zfcp_ccw_adapter_put(adapter); |
---|
| 834 | + return rc; |
---|
| 835 | +} |
---|
| 836 | +static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400, |
---|
| 837 | + zfcp_sysfs_adapter_diag_b2b_credit_show, NULL); |
---|
| 838 | + |
---|
| 839 | +#define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt) \ |
---|
| 840 | + static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show( \ |
---|
| 841 | + struct device *dev, struct device_attribute *attr, char *buf) \ |
---|
| 842 | + { \ |
---|
| 843 | + struct zfcp_adapter *const adapter = \ |
---|
| 844 | + zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); \ |
---|
| 845 | + struct zfcp_diag_header *diag_hdr; \ |
---|
| 846 | + ssize_t rc = -ENOLINK; \ |
---|
| 847 | + unsigned long flags; \ |
---|
| 848 | + unsigned int status; \ |
---|
| 849 | + \ |
---|
| 850 | + if (!adapter) \ |
---|
| 851 | + return -ENODEV; \ |
---|
| 852 | + \ |
---|
| 853 | + status = atomic_read(&adapter->status); \ |
---|
| 854 | + if (0 == (status & ZFCP_STATUS_COMMON_OPEN) || \ |
---|
| 855 | + 0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) || \ |
---|
| 856 | + 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED)) \ |
---|
| 857 | + goto out; \ |
---|
| 858 | + \ |
---|
| 859 | + if (!zfcp_diag_support_sfp(adapter)) { \ |
---|
| 860 | + rc = -EOPNOTSUPP; \ |
---|
| 861 | + goto out; \ |
---|
| 862 | + } \ |
---|
| 863 | + \ |
---|
| 864 | + diag_hdr = &adapter->diagnostics->port_data.header; \ |
---|
| 865 | + \ |
---|
| 866 | + rc = zfcp_diag_update_buffer_limited( \ |
---|
| 867 | + adapter, diag_hdr, zfcp_diag_update_port_data_buffer); \ |
---|
| 868 | + if (rc != 0) \ |
---|
| 869 | + goto out; \ |
---|
| 870 | + \ |
---|
| 871 | + spin_lock_irqsave(&diag_hdr->access_lock, flags); \ |
---|
| 872 | + rc = scnprintf( \ |
---|
| 873 | + buf, (_prtsize) + 2, _prtfmt "\n", \ |
---|
| 874 | + adapter->diagnostics->port_data.data._qtcb_member); \ |
---|
| 875 | + spin_unlock_irqrestore(&diag_hdr->access_lock, flags); \ |
---|
| 876 | + \ |
---|
| 877 | + out: \ |
---|
| 878 | + zfcp_ccw_adapter_put(adapter); \ |
---|
| 879 | + return rc; \ |
---|
| 880 | + } \ |
---|
| 881 | + static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400, \ |
---|
| 882 | + zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL) |
---|
| 883 | + |
---|
| 884 | +ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 6, "%hd"); |
---|
| 885 | +ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu"); |
---|
| 886 | +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu"); |
---|
| 887 | +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu"); |
---|
| 888 | +ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, 5, "%hu"); |
---|
| 889 | +ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, 2, "%hu"); |
---|
| 890 | +ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, 1, "%hu"); |
---|
| 891 | +ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, 1, "%hu"); |
---|
| 892 | +ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, 1, "%hu"); |
---|
| 893 | +ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, 1, "%hu"); |
---|
| 894 | + |
---|
| 895 | +static struct attribute *zfcp_sysfs_diag_attrs[] = { |
---|
| 896 | + &dev_attr_adapter_diag_sfp_temperature.attr, |
---|
| 897 | + &dev_attr_adapter_diag_sfp_vcc.attr, |
---|
| 898 | + &dev_attr_adapter_diag_sfp_tx_bias.attr, |
---|
| 899 | + &dev_attr_adapter_diag_sfp_tx_power.attr, |
---|
| 900 | + &dev_attr_adapter_diag_sfp_rx_power.attr, |
---|
| 901 | + &dev_attr_adapter_diag_sfp_port_tx_type.attr, |
---|
| 902 | + &dev_attr_adapter_diag_sfp_optical_port.attr, |
---|
| 903 | + &dev_attr_adapter_diag_sfp_sfp_invalid.attr, |
---|
| 904 | + &dev_attr_adapter_diag_sfp_connector_type.attr, |
---|
| 905 | + &dev_attr_adapter_diag_sfp_fec_active.attr, |
---|
| 906 | + &dev_attr_adapter_diag_b2b_credit.attr, |
---|
| 907 | + NULL, |
---|
| 908 | +}; |
---|
| 909 | + |
---|
| 910 | +const struct attribute_group zfcp_sysfs_diag_attr_group = { |
---|
| 911 | + .name = "diagnostics", |
---|
| 912 | + .attrs = zfcp_sysfs_diag_attrs, |
---|
| 913 | +}; |
---|