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 | } |