diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
| -rw-r--r-- | drivers/message/fusion/mptsas.c | 404 |
1 files changed, 346 insertions, 58 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 17e9757e728b..5a06d8d8694e 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * | 5 | * |
| 6 | * Copyright (c) 1999-2005 LSI Logic Corporation | 6 | * Copyright (c) 1999-2005 LSI Logic Corporation |
| 7 | * (mailto:mpt_linux_developer@lsil.com) | 7 | * (mailto:mpt_linux_developer@lsil.com) |
| 8 | * Copyright (c) 2005 Dell | 8 | * Copyright (c) 2005-2006 Dell |
| 9 | */ | 9 | */ |
| 10 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | 10 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ |
| 11 | /* | 11 | /* |
| @@ -86,6 +86,24 @@ static int mptsasInternalCtx = -1; /* Used only for internal commands */ | |||
| 86 | static int mptsasMgmtCtx = -1; | 86 | static int mptsasMgmtCtx = -1; |
| 87 | 87 | ||
| 88 | 88 | ||
| 89 | enum mptsas_hotplug_action { | ||
| 90 | MPTSAS_ADD_DEVICE, | ||
| 91 | MPTSAS_DEL_DEVICE, | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct mptsas_hotplug_event { | ||
| 95 | struct work_struct work; | ||
| 96 | MPT_ADAPTER *ioc; | ||
| 97 | enum mptsas_hotplug_action event_type; | ||
| 98 | u64 sas_address; | ||
| 99 | u32 channel; | ||
| 100 | u32 id; | ||
| 101 | u32 device_info; | ||
| 102 | u16 handle; | ||
| 103 | u16 parent_handle; | ||
| 104 | u8 phy_id; | ||
| 105 | }; | ||
| 106 | |||
| 89 | /* | 107 | /* |
| 90 | * SAS topology structures | 108 | * SAS topology structures |
| 91 | * | 109 | * |
| @@ -99,8 +117,8 @@ struct mptsas_devinfo { | |||
| 99 | u8 phy_id; /* phy number of parent device */ | 117 | u8 phy_id; /* phy number of parent device */ |
| 100 | u8 port_id; /* sas physical port this device | 118 | u8 port_id; /* sas physical port this device |
| 101 | is assoc'd with */ | 119 | is assoc'd with */ |
| 102 | u8 target; /* logical target id of this device */ | 120 | u8 id; /* logical target id of this device */ |
| 103 | u8 bus; /* logical bus number of this device */ | 121 | u8 channel; /* logical bus number of this device */ |
| 104 | u64 sas_address; /* WWN of this device, | 122 | u64 sas_address; /* WWN of this device, |
| 105 | SATA is assigned by HBA,expander */ | 123 | SATA is assigned by HBA,expander */ |
| 106 | u32 device_info; /* bitfield detailed info about this device */ | 124 | u32 device_info; /* bitfield detailed info about this device */ |
| @@ -114,6 +132,7 @@ struct mptsas_phyinfo { | |||
| 114 | u8 programmed_link_rate; /* programmed max/min phy link rate */ | 132 | u8 programmed_link_rate; /* programmed max/min phy link rate */ |
| 115 | struct mptsas_devinfo identify; /* point to phy device info */ | 133 | struct mptsas_devinfo identify; /* point to phy device info */ |
| 116 | struct mptsas_devinfo attached; /* point to attached device info */ | 134 | struct mptsas_devinfo attached; /* point to attached device info */ |
| 135 | struct sas_phy *phy; | ||
| 117 | struct sas_rphy *rphy; | 136 | struct sas_rphy *rphy; |
| 118 | }; | 137 | }; |
| 119 | 138 | ||
| @@ -239,13 +258,12 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 239 | struct scsi_target *starget; | 258 | struct scsi_target *starget; |
| 240 | int i; | 259 | int i; |
| 241 | 260 | ||
| 242 | vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); | 261 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); |
| 243 | if (!vdev) { | 262 | if (!vdev) { |
| 244 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", | 263 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", |
| 245 | hd->ioc->name, sizeof(VirtDevice)); | 264 | hd->ioc->name, sizeof(VirtDevice)); |
| 246 | return -ENOMEM; | 265 | return -ENOMEM; |
| 247 | } | 266 | } |
| 248 | memset(vdev, 0, sizeof(VirtDevice)); | ||
| 249 | vdev->ioc_id = hd->ioc->id; | 267 | vdev->ioc_id = hd->ioc->id; |
| 250 | sdev->hostdata = vdev; | 268 | sdev->hostdata = vdev; |
| 251 | starget = scsi_target(sdev); | 269 | starget = scsi_target(sdev); |
| @@ -256,19 +274,32 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 256 | hd->Targets[sdev->id] = vtarget; | 274 | hd->Targets[sdev->id] = vtarget; |
| 257 | } | 275 | } |
| 258 | 276 | ||
| 277 | /* | ||
| 278 | RAID volumes placed beyond the last expected port. | ||
| 279 | */ | ||
| 280 | if (sdev->channel == hd->ioc->num_ports) { | ||
| 281 | vdev->target_id = sdev->id; | ||
| 282 | vdev->bus_id = 0; | ||
| 283 | vdev->lun = 0; | ||
| 284 | goto out; | ||
| 285 | } | ||
| 286 | |||
| 259 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); | 287 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); |
| 288 | mutex_lock(&hd->ioc->sas_topology_mutex); | ||
| 260 | list_for_each_entry(p, &hd->ioc->sas_topology, list) { | 289 | list_for_each_entry(p, &hd->ioc->sas_topology, list) { |
| 261 | for (i = 0; i < p->num_phys; i++) { | 290 | for (i = 0; i < p->num_phys; i++) { |
| 262 | if (p->phy_info[i].attached.sas_address == | 291 | if (p->phy_info[i].attached.sas_address == |
| 263 | rphy->identify.sas_address) { | 292 | rphy->identify.sas_address) { |
| 264 | vdev->target_id = | 293 | vdev->target_id = |
| 265 | p->phy_info[i].attached.target; | 294 | p->phy_info[i].attached.id; |
| 266 | vdev->bus_id = p->phy_info[i].attached.bus; | 295 | vdev->bus_id = p->phy_info[i].attached.channel; |
| 267 | vdev->lun = sdev->lun; | 296 | vdev->lun = sdev->lun; |
| 297 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
| 268 | goto out; | 298 | goto out; |
| 269 | } | 299 | } |
| 270 | } | 300 | } |
| 271 | } | 301 | } |
| 302 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
| 272 | 303 | ||
| 273 | printk("No matching SAS device found!!\n"); | 304 | printk("No matching SAS device found!!\n"); |
| 274 | kfree(vdev); | 305 | kfree(vdev); |
| @@ -282,6 +313,42 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 282 | return 0; | 313 | return 0; |
| 283 | } | 314 | } |
| 284 | 315 | ||
| 316 | static void | ||
| 317 | mptsas_slave_destroy(struct scsi_device *sdev) | ||
| 318 | { | ||
| 319 | struct Scsi_Host *host = sdev->host; | ||
| 320 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; | ||
| 321 | struct sas_rphy *rphy; | ||
| 322 | struct mptsas_portinfo *p; | ||
| 323 | int i; | ||
| 324 | |||
| 325 | /* | ||
| 326 | * Handle hotplug removal case. | ||
| 327 | * We need to clear out attached data structure. | ||
| 328 | */ | ||
| 329 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); | ||
| 330 | |||
| 331 | mutex_lock(&hd->ioc->sas_topology_mutex); | ||
| 332 | list_for_each_entry(p, &hd->ioc->sas_topology, list) { | ||
| 333 | for (i = 0; i < p->num_phys; i++) { | ||
| 334 | if (p->phy_info[i].attached.sas_address == | ||
| 335 | rphy->identify.sas_address) { | ||
| 336 | memset(&p->phy_info[i].attached, 0, | ||
| 337 | sizeof(struct mptsas_devinfo)); | ||
| 338 | p->phy_info[i].rphy = NULL; | ||
| 339 | goto out; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | } | ||
| 343 | |||
| 344 | out: | ||
| 345 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
| 346 | /* | ||
| 347 | * TODO: Issue target reset to flush firmware outstanding commands. | ||
| 348 | */ | ||
| 349 | mptscsih_slave_destroy(sdev); | ||
| 350 | } | ||
| 351 | |||
| 285 | static struct scsi_host_template mptsas_driver_template = { | 352 | static struct scsi_host_template mptsas_driver_template = { |
| 286 | .module = THIS_MODULE, | 353 | .module = THIS_MODULE, |
| 287 | .proc_name = "mptsas", | 354 | .proc_name = "mptsas", |
| @@ -293,7 +360,7 @@ static struct scsi_host_template mptsas_driver_template = { | |||
| 293 | .slave_alloc = mptsas_slave_alloc, | 360 | .slave_alloc = mptsas_slave_alloc, |
| 294 | .slave_configure = mptscsih_slave_configure, | 361 | .slave_configure = mptscsih_slave_configure, |
| 295 | .target_destroy = mptscsih_target_destroy, | 362 | .target_destroy = mptscsih_target_destroy, |
| 296 | .slave_destroy = mptscsih_slave_destroy, | 363 | .slave_destroy = mptsas_slave_destroy, |
| 297 | .change_queue_depth = mptscsih_change_queue_depth, | 364 | .change_queue_depth = mptscsih_change_queue_depth, |
| 298 | .eh_abort_handler = mptscsih_abort, | 365 | .eh_abort_handler = mptscsih_abort, |
| 299 | .eh_device_reset_handler = mptscsih_dev_reset, | 366 | .eh_device_reset_handler = mptscsih_dev_reset, |
| @@ -399,7 +466,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
| 399 | if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) | 466 | if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) |
| 400 | return -ENXIO; | 467 | return -ENXIO; |
| 401 | 468 | ||
| 402 | if (down_interruptible(&ioc->sas_mgmt.mutex)) | 469 | if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) |
| 403 | goto out; | 470 | goto out; |
| 404 | 471 | ||
| 405 | mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); | 472 | mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); |
| @@ -450,7 +517,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
| 450 | error = 0; | 517 | error = 0; |
| 451 | 518 | ||
| 452 | out_unlock: | 519 | out_unlock: |
| 453 | up(&ioc->sas_mgmt.mutex); | 520 | mutex_unlock(&ioc->sas_mgmt.mutex); |
| 454 | out: | 521 | out: |
| 455 | return error; | 522 | return error; |
| 456 | } | 523 | } |
| @@ -649,8 +716,8 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
| 649 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 716 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
| 650 | device_info->phy_id = buffer->PhyNum; | 717 | device_info->phy_id = buffer->PhyNum; |
| 651 | device_info->port_id = buffer->PhysicalPort; | 718 | device_info->port_id = buffer->PhysicalPort; |
| 652 | device_info->target = buffer->TargetID; | 719 | device_info->id = buffer->TargetID; |
| 653 | device_info->bus = buffer->Bus; | 720 | device_info->channel = buffer->Bus; |
| 654 | memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); | 721 | memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); |
| 655 | device_info->sas_address = le64_to_cpu(sas_address); | 722 | device_info->sas_address = le64_to_cpu(sas_address); |
| 656 | device_info->device_info = | 723 | device_info->device_info = |
| @@ -858,36 +925,36 @@ mptsas_parse_device_info(struct sas_identify *identify, | |||
| 858 | static int mptsas_probe_one_phy(struct device *dev, | 925 | static int mptsas_probe_one_phy(struct device *dev, |
| 859 | struct mptsas_phyinfo *phy_info, int index, int local) | 926 | struct mptsas_phyinfo *phy_info, int index, int local) |
| 860 | { | 927 | { |
| 861 | struct sas_phy *port; | 928 | struct sas_phy *phy; |
| 862 | int error; | 929 | int error; |
| 863 | 930 | ||
| 864 | port = sas_phy_alloc(dev, index); | 931 | phy = sas_phy_alloc(dev, index); |
| 865 | if (!port) | 932 | if (!phy) |
| 866 | return -ENOMEM; | 933 | return -ENOMEM; |
| 867 | 934 | ||
| 868 | port->port_identifier = phy_info->port_id; | 935 | phy->port_identifier = phy_info->port_id; |
| 869 | mptsas_parse_device_info(&port->identify, &phy_info->identify); | 936 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); |
| 870 | 937 | ||
| 871 | /* | 938 | /* |
| 872 | * Set Negotiated link rate. | 939 | * Set Negotiated link rate. |
| 873 | */ | 940 | */ |
| 874 | switch (phy_info->negotiated_link_rate) { | 941 | switch (phy_info->negotiated_link_rate) { |
| 875 | case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: | 942 | case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: |
| 876 | port->negotiated_linkrate = SAS_PHY_DISABLED; | 943 | phy->negotiated_linkrate = SAS_PHY_DISABLED; |
| 877 | break; | 944 | break; |
| 878 | case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: | 945 | case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: |
| 879 | port->negotiated_linkrate = SAS_LINK_RATE_FAILED; | 946 | phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; |
| 880 | break; | 947 | break; |
| 881 | case MPI_SAS_IOUNIT0_RATE_1_5: | 948 | case MPI_SAS_IOUNIT0_RATE_1_5: |
| 882 | port->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; | 949 | phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; |
| 883 | break; | 950 | break; |
| 884 | case MPI_SAS_IOUNIT0_RATE_3_0: | 951 | case MPI_SAS_IOUNIT0_RATE_3_0: |
| 885 | port->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; | 952 | phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; |
| 886 | break; | 953 | break; |
| 887 | case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: | 954 | case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: |
| 888 | case MPI_SAS_IOUNIT0_RATE_UNKNOWN: | 955 | case MPI_SAS_IOUNIT0_RATE_UNKNOWN: |
| 889 | default: | 956 | default: |
| 890 | port->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; | 957 | phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; |
| 891 | break; | 958 | break; |
| 892 | } | 959 | } |
| 893 | 960 | ||
| @@ -896,10 +963,10 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 896 | */ | 963 | */ |
| 897 | switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { | 964 | switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { |
| 898 | case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: | 965 | case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: |
| 899 | port->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; | 966 | phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; |
| 900 | break; | 967 | break; |
| 901 | case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: | 968 | case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: |
| 902 | port->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; | 969 | phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; |
| 903 | break; | 970 | break; |
| 904 | default: | 971 | default: |
| 905 | break; | 972 | break; |
| @@ -911,10 +978,10 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 911 | switch (phy_info->programmed_link_rate & | 978 | switch (phy_info->programmed_link_rate & |
| 912 | MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { | 979 | MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { |
| 913 | case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: | 980 | case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: |
| 914 | port->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; | 981 | phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; |
| 915 | break; | 982 | break; |
| 916 | case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: | 983 | case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: |
| 917 | port->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; | 984 | phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; |
| 918 | break; | 985 | break; |
| 919 | default: | 986 | default: |
| 920 | break; | 987 | break; |
| @@ -925,10 +992,10 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 925 | */ | 992 | */ |
| 926 | switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { | 993 | switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { |
| 927 | case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: | 994 | case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: |
| 928 | port->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; | 995 | phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; |
| 929 | break; | 996 | break; |
| 930 | case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: | 997 | case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: |
| 931 | port->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; | 998 | phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; |
| 932 | break; | 999 | break; |
| 933 | default: | 1000 | default: |
| 934 | break; | 1001 | break; |
| @@ -940,28 +1007,29 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 940 | switch (phy_info->programmed_link_rate & | 1007 | switch (phy_info->programmed_link_rate & |
| 941 | MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { | 1008 | MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { |
| 942 | case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: | 1009 | case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: |
| 943 | port->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; | 1010 | phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; |
| 944 | break; | 1011 | break; |
| 945 | case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: | 1012 | case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: |
| 946 | port->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; | 1013 | phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; |
| 947 | break; | 1014 | break; |
| 948 | default: | 1015 | default: |
| 949 | break; | 1016 | break; |
| 950 | } | 1017 | } |
| 951 | 1018 | ||
| 952 | if (local) | 1019 | if (local) |
| 953 | port->local_attached = 1; | 1020 | phy->local_attached = 1; |
| 954 | 1021 | ||
| 955 | error = sas_phy_add(port); | 1022 | error = sas_phy_add(phy); |
| 956 | if (error) { | 1023 | if (error) { |
| 957 | sas_phy_free(port); | 1024 | sas_phy_free(phy); |
| 958 | return error; | 1025 | return error; |
| 959 | } | 1026 | } |
| 1027 | phy_info->phy = phy; | ||
| 960 | 1028 | ||
| 961 | if (phy_info->attached.handle) { | 1029 | if (phy_info->attached.handle) { |
| 962 | struct sas_rphy *rphy; | 1030 | struct sas_rphy *rphy; |
| 963 | 1031 | ||
| 964 | rphy = sas_rphy_alloc(port); | 1032 | rphy = sas_rphy_alloc(phy); |
| 965 | if (!rphy) | 1033 | if (!rphy) |
| 966 | return 0; /* non-fatal: an rphy can be added later */ | 1034 | return 0; /* non-fatal: an rphy can be added later */ |
| 967 | 1035 | ||
| @@ -985,16 +1053,19 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | |||
| 985 | u32 handle = 0xFFFF; | 1053 | u32 handle = 0xFFFF; |
| 986 | int error = -ENOMEM, i; | 1054 | int error = -ENOMEM, i; |
| 987 | 1055 | ||
| 988 | port_info = kmalloc(sizeof(*port_info), GFP_KERNEL); | 1056 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); |
| 989 | if (!port_info) | 1057 | if (!port_info) |
| 990 | goto out; | 1058 | goto out; |
| 991 | memset(port_info, 0, sizeof(*port_info)); | ||
| 992 | 1059 | ||
| 993 | error = mptsas_sas_io_unit_pg0(ioc, port_info); | 1060 | error = mptsas_sas_io_unit_pg0(ioc, port_info); |
| 994 | if (error) | 1061 | if (error) |
| 995 | goto out_free_port_info; | 1062 | goto out_free_port_info; |
| 996 | 1063 | ||
| 1064 | ioc->num_ports = port_info->num_phys; | ||
| 1065 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 997 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1066 | list_add_tail(&port_info->list, &ioc->sas_topology); |
| 1067 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1068 | |||
| 998 | for (i = 0; i < port_info->num_phys; i++) { | 1069 | for (i = 0; i < port_info->num_phys; i++) { |
| 999 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], | 1070 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], |
| 1000 | (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << | 1071 | (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << |
| @@ -1034,10 +1105,9 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1034 | struct mptsas_portinfo *port_info, *p; | 1105 | struct mptsas_portinfo *port_info, *p; |
| 1035 | int error = -ENOMEM, i, j; | 1106 | int error = -ENOMEM, i, j; |
| 1036 | 1107 | ||
| 1037 | port_info = kmalloc(sizeof(*port_info), GFP_KERNEL); | 1108 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); |
| 1038 | if (!port_info) | 1109 | if (!port_info) |
| 1039 | goto out; | 1110 | goto out; |
| 1040 | memset(port_info, 0, sizeof(*port_info)); | ||
| 1041 | 1111 | ||
| 1042 | error = mptsas_sas_expander_pg0(ioc, port_info, | 1112 | error = mptsas_sas_expander_pg0(ioc, port_info, |
| 1043 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | 1113 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
| @@ -1047,7 +1117,10 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1047 | 1117 | ||
| 1048 | *handle = port_info->handle; | 1118 | *handle = port_info->handle; |
| 1049 | 1119 | ||
| 1120 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1050 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1121 | list_add_tail(&port_info->list, &ioc->sas_topology); |
| 1122 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1123 | |||
| 1051 | for (i = 0; i < port_info->num_phys; i++) { | 1124 | for (i = 0; i < port_info->num_phys; i++) { |
| 1052 | struct device *parent; | 1125 | struct device *parent; |
| 1053 | 1126 | ||
| @@ -1079,6 +1152,7 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1079 | * HBA phys. | 1152 | * HBA phys. |
| 1080 | */ | 1153 | */ |
| 1081 | parent = &ioc->sh->shost_gendev; | 1154 | parent = &ioc->sh->shost_gendev; |
| 1155 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1082 | list_for_each_entry(p, &ioc->sas_topology, list) { | 1156 | list_for_each_entry(p, &ioc->sas_topology, list) { |
| 1083 | for (j = 0; j < p->num_phys; j++) { | 1157 | for (j = 0; j < p->num_phys; j++) { |
| 1084 | if (port_info->phy_info[i].identify.handle == | 1158 | if (port_info->phy_info[i].identify.handle == |
| @@ -1086,6 +1160,7 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1086 | parent = &p->phy_info[j].rphy->dev; | 1160 | parent = &p->phy_info[j].rphy->dev; |
| 1087 | } | 1161 | } |
| 1088 | } | 1162 | } |
| 1163 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1089 | 1164 | ||
| 1090 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], | 1165 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], |
| 1091 | *index, 0); | 1166 | *index, 0); |
| @@ -1111,6 +1186,211 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | |||
| 1111 | ; | 1186 | ; |
| 1112 | } | 1187 | } |
| 1113 | 1188 | ||
| 1189 | static struct mptsas_phyinfo * | ||
| 1190 | mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) | ||
| 1191 | { | ||
| 1192 | struct mptsas_portinfo *port_info; | ||
| 1193 | struct mptsas_devinfo device_info; | ||
| 1194 | struct mptsas_phyinfo *phy_info = NULL; | ||
| 1195 | int i, error; | ||
| 1196 | |||
| 1197 | /* | ||
| 1198 | * Retrieve the parent sas_address | ||
| 1199 | */ | ||
| 1200 | error = mptsas_sas_device_pg0(ioc, &device_info, | ||
| 1201 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | ||
| 1202 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | ||
| 1203 | parent_handle); | ||
| 1204 | if (error) { | ||
| 1205 | printk("mptsas: failed to retrieve device page\n"); | ||
| 1206 | return NULL; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | /* | ||
| 1210 | * The phy_info structures are never deallocated during lifetime of | ||
| 1211 | * a host, so the code below is safe without additional refcounting. | ||
| 1212 | */ | ||
| 1213 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1214 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | ||
| 1215 | for (i = 0; i < port_info->num_phys; i++) { | ||
| 1216 | if (port_info->phy_info[i].identify.sas_address == | ||
| 1217 | device_info.sas_address && | ||
| 1218 | port_info->phy_info[i].phy_id == phy_id) { | ||
| 1219 | phy_info = &port_info->phy_info[i]; | ||
| 1220 | break; | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | } | ||
| 1224 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1225 | |||
| 1226 | return phy_info; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | static struct mptsas_phyinfo * | ||
| 1230 | mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | ||
| 1231 | { | ||
| 1232 | struct mptsas_portinfo *port_info; | ||
| 1233 | struct mptsas_phyinfo *phy_info = NULL; | ||
| 1234 | int i; | ||
| 1235 | |||
| 1236 | /* | ||
| 1237 | * The phy_info structures are never deallocated during lifetime of | ||
| 1238 | * a host, so the code below is safe without additional refcounting. | ||
| 1239 | */ | ||
| 1240 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1241 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | ||
| 1242 | for (i = 0; i < port_info->num_phys; i++) { | ||
| 1243 | if (port_info->phy_info[i].attached.handle == handle) { | ||
| 1244 | phy_info = &port_info->phy_info[i]; | ||
| 1245 | break; | ||
| 1246 | } | ||
| 1247 | } | ||
| 1248 | } | ||
| 1249 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1250 | |||
| 1251 | return phy_info; | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | static void | ||
| 1255 | mptsas_hotplug_work(void *arg) | ||
| 1256 | { | ||
| 1257 | struct mptsas_hotplug_event *ev = arg; | ||
| 1258 | MPT_ADAPTER *ioc = ev->ioc; | ||
| 1259 | struct mptsas_phyinfo *phy_info; | ||
| 1260 | struct sas_rphy *rphy; | ||
| 1261 | char *ds = NULL; | ||
| 1262 | |||
| 1263 | if (ev->device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
| 1264 | ds = "ssp"; | ||
| 1265 | if (ev->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
| 1266 | ds = "stp"; | ||
| 1267 | if (ev->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
| 1268 | ds = "sata"; | ||
| 1269 | |||
| 1270 | switch (ev->event_type) { | ||
| 1271 | case MPTSAS_DEL_DEVICE: | ||
| 1272 | printk(MYIOC_s_INFO_FMT | ||
| 1273 | "removing %s device, channel %d, id %d, phy %d\n", | ||
| 1274 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
| 1275 | |||
| 1276 | phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle); | ||
| 1277 | if (!phy_info) { | ||
| 1278 | printk("mptsas: remove event for non-existant PHY.\n"); | ||
| 1279 | break; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | if (phy_info->rphy) { | ||
| 1283 | sas_rphy_delete(phy_info->rphy); | ||
| 1284 | phy_info->rphy = NULL; | ||
| 1285 | } | ||
| 1286 | break; | ||
| 1287 | case MPTSAS_ADD_DEVICE: | ||
| 1288 | printk(MYIOC_s_INFO_FMT | ||
| 1289 | "attaching %s device, channel %d, id %d, phy %d\n", | ||
| 1290 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
| 1291 | |||
| 1292 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | ||
| 1293 | ev->parent_handle, ev->phy_id); | ||
| 1294 | if (!phy_info) { | ||
| 1295 | printk("mptsas: add event for non-existant PHY.\n"); | ||
| 1296 | break; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | if (phy_info->rphy) { | ||
| 1300 | printk("mptsas: trying to add existing device.\n"); | ||
| 1301 | break; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | /* fill attached info */ | ||
| 1305 | phy_info->attached.handle = ev->handle; | ||
| 1306 | phy_info->attached.phy_id = ev->phy_id; | ||
| 1307 | phy_info->attached.port_id = phy_info->identify.port_id; | ||
| 1308 | phy_info->attached.id = ev->id; | ||
| 1309 | phy_info->attached.channel = ev->channel; | ||
| 1310 | phy_info->attached.sas_address = ev->sas_address; | ||
| 1311 | phy_info->attached.device_info = ev->device_info; | ||
| 1312 | |||
| 1313 | rphy = sas_rphy_alloc(phy_info->phy); | ||
| 1314 | if (!rphy) | ||
| 1315 | break; /* non-fatal: an rphy can be added later */ | ||
| 1316 | |||
| 1317 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | ||
| 1318 | if (sas_rphy_add(rphy)) { | ||
| 1319 | sas_rphy_free(rphy); | ||
| 1320 | break; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | phy_info->rphy = rphy; | ||
| 1324 | break; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | kfree(ev); | ||
| 1328 | } | ||
| 1329 | |||
| 1330 | static void | ||
| 1331 | mptscsih_send_sas_event(MPT_ADAPTER *ioc, | ||
| 1332 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) | ||
| 1333 | { | ||
| 1334 | struct mptsas_hotplug_event *ev; | ||
| 1335 | u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); | ||
| 1336 | __le64 sas_address; | ||
| 1337 | |||
| 1338 | if ((device_info & | ||
| 1339 | (MPI_SAS_DEVICE_INFO_SSP_TARGET | | ||
| 1340 | MPI_SAS_DEVICE_INFO_STP_TARGET | | ||
| 1341 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) | ||
| 1342 | return; | ||
| 1343 | |||
| 1344 | if ((sas_event_data->ReasonCode & | ||
| 1345 | (MPI_EVENT_SAS_DEV_STAT_RC_ADDED | | ||
| 1346 | MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING)) == 0) | ||
| 1347 | return; | ||
| 1348 | |||
| 1349 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | ||
| 1350 | if (!ev) { | ||
| 1351 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | ||
| 1352 | return; | ||
| 1353 | } | ||
| 1354 | |||
| 1355 | |||
| 1356 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); | ||
| 1357 | ev->ioc = ioc; | ||
| 1358 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
| 1359 | ev->parent_handle = le16_to_cpu(sas_event_data->ParentDevHandle); | ||
| 1360 | ev->channel = sas_event_data->Bus; | ||
| 1361 | ev->id = sas_event_data->TargetID; | ||
| 1362 | ev->phy_id = sas_event_data->PhyNum; | ||
| 1363 | memcpy(&sas_address, &sas_event_data->SASAddress, sizeof(__le64)); | ||
| 1364 | ev->sas_address = le64_to_cpu(sas_address); | ||
| 1365 | ev->device_info = device_info; | ||
| 1366 | |||
| 1367 | if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | ||
| 1368 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
| 1369 | else | ||
| 1370 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
| 1371 | |||
| 1372 | schedule_work(&ev->work); | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | static int | ||
| 1376 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | ||
| 1377 | { | ||
| 1378 | u8 event = le32_to_cpu(reply->Event) & 0xFF; | ||
| 1379 | |||
| 1380 | if (!ioc->sh) | ||
| 1381 | return 1; | ||
| 1382 | |||
| 1383 | switch (event) { | ||
| 1384 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | ||
| 1385 | mptscsih_send_sas_event(ioc, | ||
| 1386 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); | ||
| 1387 | return 1; /* currently means nothing really */ | ||
| 1388 | |||
| 1389 | default: | ||
| 1390 | return mptscsih_event_process(ioc, reply); | ||
| 1391 | } | ||
| 1392 | } | ||
| 1393 | |||
| 1114 | static int | 1394 | static int |
| 1115 | mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 1395 | mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| 1116 | { | 1396 | { |
| @@ -1118,11 +1398,10 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1118 | MPT_SCSI_HOST *hd; | 1398 | MPT_SCSI_HOST *hd; |
| 1119 | MPT_ADAPTER *ioc; | 1399 | MPT_ADAPTER *ioc; |
| 1120 | unsigned long flags; | 1400 | unsigned long flags; |
| 1121 | int sz, ii; | 1401 | int ii; |
| 1122 | int numSGE = 0; | 1402 | int numSGE = 0; |
| 1123 | int scale; | 1403 | int scale; |
| 1124 | int ioc_cap; | 1404 | int ioc_cap; |
| 1125 | u8 *mem; | ||
| 1126 | int error=0; | 1405 | int error=0; |
| 1127 | int r; | 1406 | int r; |
| 1128 | 1407 | ||
| @@ -1203,7 +1482,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1203 | sh->unique_id = ioc->id; | 1482 | sh->unique_id = ioc->id; |
| 1204 | 1483 | ||
| 1205 | INIT_LIST_HEAD(&ioc->sas_topology); | 1484 | INIT_LIST_HEAD(&ioc->sas_topology); |
| 1206 | init_MUTEX(&ioc->sas_mgmt.mutex); | 1485 | mutex_init(&ioc->sas_topology_mutex); |
| 1486 | |||
| 1487 | mutex_init(&ioc->sas_mgmt.mutex); | ||
| 1207 | init_completion(&ioc->sas_mgmt.done); | 1488 | init_completion(&ioc->sas_mgmt.done); |
| 1208 | 1489 | ||
| 1209 | /* Verify that we won't exceed the maximum | 1490 | /* Verify that we won't exceed the maximum |
| @@ -1244,36 +1525,27 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1244 | /* SCSI needs scsi_cmnd lookup table! | 1525 | /* SCSI needs scsi_cmnd lookup table! |
| 1245 | * (with size equal to req_depth*PtrSz!) | 1526 | * (with size equal to req_depth*PtrSz!) |
| 1246 | */ | 1527 | */ |
| 1247 | sz = ioc->req_depth * sizeof(void *); | 1528 | hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); |
| 1248 | mem = kmalloc(sz, GFP_ATOMIC); | 1529 | if (!hd->ScsiLookup) { |
| 1249 | if (mem == NULL) { | ||
| 1250 | error = -ENOMEM; | 1530 | error = -ENOMEM; |
| 1251 | goto out_mptsas_probe; | 1531 | goto out_mptsas_probe; |
| 1252 | } | 1532 | } |
| 1253 | 1533 | ||
| 1254 | memset(mem, 0, sz); | 1534 | dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n", |
| 1255 | hd->ScsiLookup = (struct scsi_cmnd **) mem; | 1535 | ioc->name, hd->ScsiLookup)); |
| 1256 | |||
| 1257 | dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", | ||
| 1258 | ioc->name, hd->ScsiLookup, sz)); | ||
| 1259 | 1536 | ||
| 1260 | /* Allocate memory for the device structures. | 1537 | /* Allocate memory for the device structures. |
| 1261 | * A non-Null pointer at an offset | 1538 | * A non-Null pointer at an offset |
| 1262 | * indicates a device exists. | 1539 | * indicates a device exists. |
| 1263 | * max_id = 1 + maximum id (hosts.h) | 1540 | * max_id = 1 + maximum id (hosts.h) |
| 1264 | */ | 1541 | */ |
| 1265 | sz = sh->max_id * sizeof(void *); | 1542 | hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC); |
| 1266 | mem = kmalloc(sz, GFP_ATOMIC); | 1543 | if (!hd->Targets) { |
| 1267 | if (mem == NULL) { | ||
| 1268 | error = -ENOMEM; | 1544 | error = -ENOMEM; |
| 1269 | goto out_mptsas_probe; | 1545 | goto out_mptsas_probe; |
| 1270 | } | 1546 | } |
| 1271 | 1547 | ||
| 1272 | memset(mem, 0, sz); | 1548 | dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets)); |
| 1273 | hd->Targets = (VirtTarget **) mem; | ||
| 1274 | |||
| 1275 | dprintk((KERN_INFO | ||
| 1276 | " vtarget @ %p, sz=%d\n", hd->Targets, sz)); | ||
| 1277 | 1549 | ||
| 1278 | /* Clear the TM flags | 1550 | /* Clear the TM flags |
| 1279 | */ | 1551 | */ |
| @@ -1324,6 +1596,20 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1324 | 1596 | ||
| 1325 | mptsas_scan_sas_topology(ioc); | 1597 | mptsas_scan_sas_topology(ioc); |
| 1326 | 1598 | ||
| 1599 | /* | ||
| 1600 | Reporting RAID volumes. | ||
| 1601 | */ | ||
| 1602 | if (!ioc->raid_data.pIocPg2) | ||
| 1603 | return 0; | ||
| 1604 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
| 1605 | return 0; | ||
| 1606 | for (ii=0;ii<ioc->raid_data.pIocPg2->NumActiveVolumes;ii++) { | ||
| 1607 | scsi_add_device(sh, | ||
| 1608 | ioc->num_ports, | ||
| 1609 | ioc->raid_data.pIocPg2->RaidVolume[ii].VolumeID, | ||
| 1610 | 0); | ||
| 1611 | } | ||
| 1612 | |||
| 1327 | return 0; | 1613 | return 0; |
| 1328 | 1614 | ||
| 1329 | out_mptsas_probe: | 1615 | out_mptsas_probe: |
| @@ -1339,10 +1625,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
| 1339 | 1625 | ||
| 1340 | sas_remove_host(ioc->sh); | 1626 | sas_remove_host(ioc->sh); |
| 1341 | 1627 | ||
| 1628 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1342 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { | 1629 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { |
| 1343 | list_del(&p->list); | 1630 | list_del(&p->list); |
| 1344 | kfree(p); | 1631 | kfree(p); |
| 1345 | } | 1632 | } |
| 1633 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1346 | 1634 | ||
| 1347 | mptscsih_remove(pdev); | 1635 | mptscsih_remove(pdev); |
| 1348 | } | 1636 | } |
| @@ -1393,7 +1681,7 @@ mptsas_init(void) | |||
| 1393 | mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); | 1681 | mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); |
| 1394 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); | 1682 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); |
| 1395 | 1683 | ||
| 1396 | if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) { | 1684 | if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) { |
| 1397 | devtprintk((KERN_INFO MYNAM | 1685 | devtprintk((KERN_INFO MYNAM |
| 1398 | ": Registered for IOC event notifications\n")); | 1686 | ": Registered for IOC event notifications\n")); |
| 1399 | } | 1687 | } |
