| .. | .. |
|---|
| 4 | 4 | * |
|---|
| 5 | 5 | * Interface to Linux SCSI midlayer. |
|---|
| 6 | 6 | * |
|---|
| 7 | | - * Copyright IBM Corp. 2002, 2018 |
|---|
| 7 | + * Copyright IBM Corp. 2002, 2020 |
|---|
| 8 | 8 | */ |
|---|
| 9 | 9 | |
|---|
| 10 | 10 | #define KMSG_COMPONENT "zfcp" |
|---|
| .. | .. |
|---|
| 27 | 27 | |
|---|
| 28 | 28 | static bool enable_dif; |
|---|
| 29 | 29 | module_param_named(dif, enable_dif, bool, 0400); |
|---|
| 30 | | -MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support"); |
|---|
| 30 | +MODULE_PARM_DESC(dif, "Enable DIF data integrity support (default off)"); |
|---|
| 31 | + |
|---|
| 32 | +bool zfcp_experimental_dix; |
|---|
| 33 | +module_param_named(dix, zfcp_experimental_dix, bool, 0400); |
|---|
| 34 | +MODULE_PARM_DESC(dix, "Enable experimental DIX (data integrity extension) support which implies DIF support (default off)"); |
|---|
| 31 | 35 | |
|---|
| 32 | 36 | static bool allow_lun_scan = true; |
|---|
| 33 | 37 | module_param(allow_lun_scan, bool, 0600); |
|---|
| .. | .. |
|---|
| 235 | 239 | (struct zfcp_scsi_req_filter *)data; |
|---|
| 236 | 240 | |
|---|
| 237 | 241 | /* already aborted - prevent side-effects - or not a SCSI command */ |
|---|
| 238 | | - if (old_req->data == NULL || old_req->fsf_command != FSF_QTCB_FCP_CMND) |
|---|
| 242 | + if (old_req->data == NULL || |
|---|
| 243 | + zfcp_fsf_req_is_status_read_buffer(old_req) || |
|---|
| 244 | + old_req->qtcb->header.fsf_command != FSF_QTCB_FCP_CMND) |
|---|
| 239 | 245 | return; |
|---|
| 240 | 246 | |
|---|
| 241 | 247 | /* (tmf_scope == FCP_TMF_TGT_RESET || tmf_scope == FCP_TMF_LUN_RESET) */ |
|---|
| .. | .. |
|---|
| 435 | 441 | .max_sectors = (((QDIO_MAX_ELEMENTS_PER_BUFFER - 1) |
|---|
| 436 | 442 | * ZFCP_QDIO_MAX_SBALS_PER_REQ) - 2) * 8, |
|---|
| 437 | 443 | /* GCD, adjusted later */ |
|---|
| 444 | + /* report size limit per scatter-gather segment */ |
|---|
| 445 | + .max_segment_size = ZFCP_QDIO_SBALE_LEN, |
|---|
| 438 | 446 | .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, |
|---|
| 439 | | - .use_clustering = 1, |
|---|
| 440 | 447 | .shost_attrs = zfcp_sysfs_shost_attrs, |
|---|
| 441 | 448 | .sdev_attrs = zfcp_sysfs_sdev_attrs, |
|---|
| 442 | 449 | .track_queue_depth = 1, |
|---|
| .. | .. |
|---|
| 444 | 451 | }; |
|---|
| 445 | 452 | |
|---|
| 446 | 453 | /** |
|---|
| 447 | | - * zfcp_scsi_adapter_register - Register SCSI and FC host with SCSI midlayer |
|---|
| 454 | + * zfcp_scsi_adapter_register() - Allocate and register SCSI and FC host with |
|---|
| 455 | + * SCSI midlayer |
|---|
| 448 | 456 | * @adapter: The zfcp adapter to register with the SCSI midlayer |
|---|
| 457 | + * |
|---|
| 458 | + * Allocates the SCSI host object for the given adapter, sets basic properties |
|---|
| 459 | + * (such as the transport template, QDIO limits, ...), and registers it with |
|---|
| 460 | + * the midlayer. |
|---|
| 461 | + * |
|---|
| 462 | + * During registration with the midlayer the corresponding FC host object for |
|---|
| 463 | + * the referenced transport class is also implicitely allocated. |
|---|
| 464 | + * |
|---|
| 465 | + * Upon success adapter->scsi_host is set, and upon failure it remains NULL. If |
|---|
| 466 | + * adapter->scsi_host is already set, nothing is done. |
|---|
| 467 | + * |
|---|
| 468 | + * Return: |
|---|
| 469 | + * * 0 - Allocation and registration was successful |
|---|
| 470 | + * * -EEXIST - SCSI and FC host did already exist, nothing was done, nothing |
|---|
| 471 | + * was changed |
|---|
| 472 | + * * -EIO - Allocation or registration failed |
|---|
| 449 | 473 | */ |
|---|
| 450 | 474 | int zfcp_scsi_adapter_register(struct zfcp_adapter *adapter) |
|---|
| 451 | 475 | { |
|---|
| 452 | 476 | struct ccw_dev_id dev_id; |
|---|
| 453 | 477 | |
|---|
| 454 | 478 | if (adapter->scsi_host) |
|---|
| 455 | | - return 0; |
|---|
| 479 | + return -EEXIST; |
|---|
| 456 | 480 | |
|---|
| 457 | 481 | ccw_device_get_id(adapter->ccw_device, &dev_id); |
|---|
| 458 | 482 | /* register adapter as SCSI host with mid layer of SCSI stack */ |
|---|
| 459 | 483 | adapter->scsi_host = scsi_host_alloc(&zfcp_scsi_host_template, |
|---|
| 460 | 484 | sizeof (struct zfcp_adapter *)); |
|---|
| 461 | | - if (!adapter->scsi_host) { |
|---|
| 462 | | - dev_err(&adapter->ccw_device->dev, |
|---|
| 463 | | - "Registering the FCP device with the " |
|---|
| 464 | | - "SCSI stack failed\n"); |
|---|
| 465 | | - return -EIO; |
|---|
| 466 | | - } |
|---|
| 485 | + if (!adapter->scsi_host) |
|---|
| 486 | + goto err_out; |
|---|
| 467 | 487 | |
|---|
| 468 | 488 | /* tell the SCSI stack some characteristics of this adapter */ |
|---|
| 469 | 489 | adapter->scsi_host->max_id = 511; |
|---|
| .. | .. |
|---|
| 473 | 493 | adapter->scsi_host->max_cmd_len = 16; /* in struct fcp_cmnd */ |
|---|
| 474 | 494 | adapter->scsi_host->transportt = zfcp_scsi_transport_template; |
|---|
| 475 | 495 | |
|---|
| 496 | + /* make all basic properties known at registration time */ |
|---|
| 497 | + zfcp_qdio_shost_update(adapter, adapter->qdio); |
|---|
| 498 | + zfcp_scsi_set_prot(adapter); |
|---|
| 499 | + |
|---|
| 476 | 500 | adapter->scsi_host->hostdata[0] = (unsigned long) adapter; |
|---|
| 477 | 501 | |
|---|
| 478 | 502 | if (scsi_add_host(adapter->scsi_host, &adapter->ccw_device->dev)) { |
|---|
| 479 | 503 | scsi_host_put(adapter->scsi_host); |
|---|
| 480 | | - return -EIO; |
|---|
| 504 | + goto err_out; |
|---|
| 481 | 505 | } |
|---|
| 482 | 506 | |
|---|
| 483 | 507 | return 0; |
|---|
| 508 | +err_out: |
|---|
| 509 | + adapter->scsi_host = NULL; |
|---|
| 510 | + dev_err(&adapter->ccw_device->dev, |
|---|
| 511 | + "Registering the FCP device with the SCSI stack failed\n"); |
|---|
| 512 | + return -EIO; |
|---|
| 484 | 513 | } |
|---|
| 485 | 514 | |
|---|
| 486 | 515 | /** |
|---|
| .. | .. |
|---|
| 598 | 627 | return NULL; |
|---|
| 599 | 628 | |
|---|
| 600 | 629 | ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); |
|---|
| 601 | | - if (ret) { |
|---|
| 630 | + if (ret != 0 && ret != -EAGAIN) { |
|---|
| 602 | 631 | kfree(data); |
|---|
| 603 | 632 | return NULL; |
|---|
| 604 | 633 | } |
|---|
| .. | .. |
|---|
| 627 | 656 | return; |
|---|
| 628 | 657 | |
|---|
| 629 | 658 | ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); |
|---|
| 630 | | - if (ret) |
|---|
| 659 | + if (ret != 0 && ret != -EAGAIN) |
|---|
| 631 | 660 | kfree(data); |
|---|
| 632 | 661 | else { |
|---|
| 633 | 662 | adapter->stats_reset = jiffies/HZ; |
|---|
| .. | .. |
|---|
| 801 | 830 | data_div = atomic_read(&adapter->status) & |
|---|
| 802 | 831 | ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED; |
|---|
| 803 | 832 | |
|---|
| 804 | | - if (enable_dif && |
|---|
| 833 | + if ((enable_dif || zfcp_experimental_dix) && |
|---|
| 805 | 834 | adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1) |
|---|
| 806 | 835 | mask |= SHOST_DIF_TYPE1_PROTECTION; |
|---|
| 807 | 836 | |
|---|
| 808 | | - if (enable_dif && data_div && |
|---|
| 837 | + if (zfcp_experimental_dix && data_div && |
|---|
| 809 | 838 | adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { |
|---|
| 810 | 839 | mask |= SHOST_DIX_TYPE1_PROTECTION; |
|---|
| 811 | 840 | scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); |
|---|
| .. | .. |
|---|
| 834 | 863 | set_host_byte(scmd, DID_SOFT_ERROR); |
|---|
| 835 | 864 | } |
|---|
| 836 | 865 | |
|---|
| 866 | +void zfcp_scsi_shost_update_config_data( |
|---|
| 867 | + struct zfcp_adapter *const adapter, |
|---|
| 868 | + const struct fsf_qtcb_bottom_config *const bottom, |
|---|
| 869 | + const bool bottom_incomplete) |
|---|
| 870 | +{ |
|---|
| 871 | + struct Scsi_Host *const shost = adapter->scsi_host; |
|---|
| 872 | + const struct fc_els_flogi *nsp, *plogi; |
|---|
| 873 | + |
|---|
| 874 | + if (shost == NULL) |
|---|
| 875 | + return; |
|---|
| 876 | + |
|---|
| 877 | + snprintf(fc_host_firmware_version(shost), FC_VERSION_STRING_SIZE, |
|---|
| 878 | + "0x%08x", bottom->lic_version); |
|---|
| 879 | + |
|---|
| 880 | + if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { |
|---|
| 881 | + snprintf(fc_host_hardware_version(shost), |
|---|
| 882 | + FC_VERSION_STRING_SIZE, |
|---|
| 883 | + "0x%08x", bottom->hardware_version); |
|---|
| 884 | + memcpy(fc_host_serial_number(shost), bottom->serial_number, |
|---|
| 885 | + min(FC_SERIAL_NUMBER_SIZE, 17)); |
|---|
| 886 | + EBCASC(fc_host_serial_number(shost), |
|---|
| 887 | + min(FC_SERIAL_NUMBER_SIZE, 17)); |
|---|
| 888 | + } |
|---|
| 889 | + |
|---|
| 890 | + /* adjust pointers for missing command code */ |
|---|
| 891 | + nsp = (struct fc_els_flogi *) ((u8 *)&bottom->nport_serv_param |
|---|
| 892 | + - sizeof(u32)); |
|---|
| 893 | + plogi = (struct fc_els_flogi *) ((u8 *)&bottom->plogi_payload |
|---|
| 894 | + - sizeof(u32)); |
|---|
| 895 | + |
|---|
| 896 | + snprintf(fc_host_manufacturer(shost), FC_SERIAL_NUMBER_SIZE, "%s", |
|---|
| 897 | + "IBM"); |
|---|
| 898 | + fc_host_port_name(shost) = be64_to_cpu(nsp->fl_wwpn); |
|---|
| 899 | + fc_host_node_name(shost) = be64_to_cpu(nsp->fl_wwnn); |
|---|
| 900 | + fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; |
|---|
| 901 | + |
|---|
| 902 | + zfcp_scsi_set_prot(adapter); |
|---|
| 903 | + |
|---|
| 904 | + /* do not evaluate invalid fields */ |
|---|
| 905 | + if (bottom_incomplete) |
|---|
| 906 | + return; |
|---|
| 907 | + |
|---|
| 908 | + fc_host_port_id(shost) = ntoh24(bottom->s_id); |
|---|
| 909 | + fc_host_speed(shost) = |
|---|
| 910 | + zfcp_fsf_convert_portspeed(bottom->fc_link_speed); |
|---|
| 911 | + |
|---|
| 912 | + snprintf(fc_host_model(shost), FC_SYMBOLIC_NAME_SIZE, "0x%04x", |
|---|
| 913 | + bottom->adapter_type); |
|---|
| 914 | + |
|---|
| 915 | + switch (bottom->fc_topology) { |
|---|
| 916 | + case FSF_TOPO_P2P: |
|---|
| 917 | + fc_host_port_type(shost) = FC_PORTTYPE_PTP; |
|---|
| 918 | + fc_host_fabric_name(shost) = 0; |
|---|
| 919 | + break; |
|---|
| 920 | + case FSF_TOPO_FABRIC: |
|---|
| 921 | + fc_host_fabric_name(shost) = be64_to_cpu(plogi->fl_wwnn); |
|---|
| 922 | + if (bottom->connection_features & FSF_FEATURE_NPIV_MODE) |
|---|
| 923 | + fc_host_port_type(shost) = FC_PORTTYPE_NPIV; |
|---|
| 924 | + else |
|---|
| 925 | + fc_host_port_type(shost) = FC_PORTTYPE_NPORT; |
|---|
| 926 | + break; |
|---|
| 927 | + case FSF_TOPO_AL: |
|---|
| 928 | + fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; |
|---|
| 929 | + fallthrough; |
|---|
| 930 | + default: |
|---|
| 931 | + fc_host_fabric_name(shost) = 0; |
|---|
| 932 | + break; |
|---|
| 933 | + } |
|---|
| 934 | +} |
|---|
| 935 | + |
|---|
| 936 | +void zfcp_scsi_shost_update_port_data( |
|---|
| 937 | + struct zfcp_adapter *const adapter, |
|---|
| 938 | + const struct fsf_qtcb_bottom_port *const bottom) |
|---|
| 939 | +{ |
|---|
| 940 | + struct Scsi_Host *const shost = adapter->scsi_host; |
|---|
| 941 | + |
|---|
| 942 | + if (shost == NULL) |
|---|
| 943 | + return; |
|---|
| 944 | + |
|---|
| 945 | + fc_host_permanent_port_name(shost) = bottom->wwpn; |
|---|
| 946 | + fc_host_maxframe_size(shost) = bottom->maximum_frame_size; |
|---|
| 947 | + fc_host_supported_speeds(shost) = |
|---|
| 948 | + zfcp_fsf_convert_portspeed(bottom->supported_speed); |
|---|
| 949 | + memcpy(fc_host_supported_fc4s(shost), bottom->supported_fc4_types, |
|---|
| 950 | + FC_FC4_LIST_SIZE); |
|---|
| 951 | + memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types, |
|---|
| 952 | + FC_FC4_LIST_SIZE); |
|---|
| 953 | +} |
|---|
| 954 | + |
|---|
| 837 | 955 | struct fc_function_template zfcp_transport_functions = { |
|---|
| 838 | 956 | .show_starget_port_id = 1, |
|---|
| 839 | 957 | .show_starget_port_name = 1, |
|---|
| .. | .. |
|---|
| 849 | 967 | .show_host_supported_speeds = 1, |
|---|
| 850 | 968 | .show_host_maxframe_size = 1, |
|---|
| 851 | 969 | .show_host_serial_number = 1, |
|---|
| 970 | + .show_host_manufacturer = 1, |
|---|
| 971 | + .show_host_model = 1, |
|---|
| 972 | + .show_host_hardware_version = 1, |
|---|
| 973 | + .show_host_firmware_version = 1, |
|---|
| 852 | 974 | .get_fc_host_stats = zfcp_scsi_get_fc_host_stats, |
|---|
| 853 | 975 | .reset_fc_host_stats = zfcp_scsi_reset_fc_host_stats, |
|---|
| 854 | 976 | .set_rport_dev_loss_tmo = zfcp_scsi_set_rport_dev_loss_tmo, |
|---|
| .. | .. |
|---|
| 864 | 986 | .show_host_symbolic_name = 1, |
|---|
| 865 | 987 | .show_host_speed = 1, |
|---|
| 866 | 988 | .show_host_port_id = 1, |
|---|
| 989 | + .show_host_fabric_name = 1, |
|---|
| 867 | 990 | .dd_bsg_size = sizeof(struct zfcp_fsf_ct_els), |
|---|
| 868 | 991 | }; |
|---|