diff options
author | Kashyap, Desai <kashyap.desai@lsi.com> | 2010-11-12 18:05:30 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-21 13:24:05 -0500 |
commit | 7f6f794dee50ba33710145140f39de59f5ec764e (patch) | |
tree | 0a08ef98b9ecc0a58bb8b024735c8bc02b65f2e7 /drivers/scsi | |
parent | 35f805b52c94f8e6cb22907ef32517132a15cb96 (diff) |
[SCSI] mpt2sas: Modify code to support Expander switch
Issue : Switch swap doesn't work when device missing delay is enabled.
(1) add support to individually add and remove phys to and from
existing ports. This replaces the routine
_transport_delete_duplicate_port.
(2) _scsih_sas_host_refresh - was modified to change the link rate
from zero to 1.5 GB rate when the firmware reports there is an
attached device with zero link.
(3) add new function mpt2sas_device_remove, this is wrapper function
deletes some redundant code through out driver by combining into one
subrountine
(4) two subroutines were modified so the sas_device, raid_device, and
port lists are traversed once when objects are deleted from the list.
Previously it was looping back each time an object was deleted from the
list.
Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 2 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 143 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 185 |
3 files changed, 206 insertions, 124 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index edf1a028db6c..428a8c2cf7e0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -849,6 +849,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
849 | ulong timeout, struct scsi_cmnd *scmd); | 849 | ulong timeout, struct scsi_cmnd *scmd); |
850 | void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); | 850 | void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); |
851 | void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); | 851 | void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); |
852 | void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); | ||
853 | void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); | ||
852 | struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, | 854 | struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, |
853 | u16 handle); | 855 | u16 handle); |
854 | struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER | 856 | struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 3e9c78aa4ccb..50c6bdf3fddd 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
@@ -2584,9 +2584,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, | |||
2584 | &sas_expander->sas_port_list, port_list) { | 2584 | &sas_expander->sas_port_list, port_list) { |
2585 | 2585 | ||
2586 | if (mpt2sas_port->remote_identify.device_type == | 2586 | if (mpt2sas_port->remote_identify.device_type == |
2587 | MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || | 2587 | SAS_EDGE_EXPANDER_DEVICE || |
2588 | mpt2sas_port->remote_identify.device_type == | 2588 | mpt2sas_port->remote_identify.device_type == |
2589 | MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) { | 2589 | SAS_FANOUT_EXPANDER_DEVICE) { |
2590 | 2590 | ||
2591 | spin_lock_irqsave(&ioc->sas_node_lock, flags); | 2591 | spin_lock_irqsave(&ioc->sas_node_lock, flags); |
2592 | expander_sibling = | 2592 | expander_sibling = |
@@ -3972,6 +3972,7 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc) | |||
3972 | Mpi2ConfigReply_t mpi_reply; | 3972 | Mpi2ConfigReply_t mpi_reply; |
3973 | Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; | 3973 | Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; |
3974 | u16 attached_handle; | 3974 | u16 attached_handle; |
3975 | u8 link_rate; | ||
3975 | 3976 | ||
3976 | dtmprintk(ioc, printk(MPT2SAS_INFO_FMT | 3977 | dtmprintk(ioc, printk(MPT2SAS_INFO_FMT |
3977 | "updating handles for sas_host(0x%016llx)\n", | 3978 | "updating handles for sas_host(0x%016llx)\n", |
@@ -3993,15 +3994,17 @@ _scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc) | |||
3993 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) | 3994 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) |
3994 | goto out; | 3995 | goto out; |
3995 | for (i = 0; i < ioc->sas_hba.num_phys ; i++) { | 3996 | for (i = 0; i < ioc->sas_hba.num_phys ; i++) { |
3997 | link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; | ||
3996 | if (i == 0) | 3998 | if (i == 0) |
3997 | ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> | 3999 | ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> |
3998 | PhyData[0].ControllerDevHandle); | 4000 | PhyData[0].ControllerDevHandle); |
3999 | ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; | 4001 | ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; |
4000 | attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. | 4002 | attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. |
4001 | AttachedDevHandle); | 4003 | AttachedDevHandle); |
4004 | if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) | ||
4005 | link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; | ||
4002 | mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, | 4006 | mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, |
4003 | attached_handle, i, sas_iounit_pg0->PhyData[i]. | 4007 | attached_handle, i, link_rate); |
4004 | NegotiatedLinkRate >> 4); | ||
4005 | } | 4008 | } |
4006 | out: | 4009 | out: |
4007 | kfree(sas_iounit_pg0); | 4010 | kfree(sas_iounit_pg0); |
@@ -4345,14 +4348,14 @@ _scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) | |||
4345 | } | 4348 | } |
4346 | 4349 | ||
4347 | /** | 4350 | /** |
4348 | * _scsih_expander_remove - removing expander object | 4351 | * mpt2sas_expander_remove - removing expander object |
4349 | * @ioc: per adapter object | 4352 | * @ioc: per adapter object |
4350 | * @sas_address: expander sas_address | 4353 | * @sas_address: expander sas_address |
4351 | * | 4354 | * |
4352 | * Return nothing. | 4355 | * Return nothing. |
4353 | */ | 4356 | */ |
4354 | static void | 4357 | void |
4355 | _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) | 4358 | mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) |
4356 | { | 4359 | { |
4357 | struct _sas_node *sas_expander; | 4360 | struct _sas_node *sas_expander; |
4358 | unsigned long flags; | 4361 | unsigned long flags; |
@@ -4363,6 +4366,11 @@ _scsih_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) | |||
4363 | spin_lock_irqsave(&ioc->sas_node_lock, flags); | 4366 | spin_lock_irqsave(&ioc->sas_node_lock, flags); |
4364 | sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, | 4367 | sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, |
4365 | sas_address); | 4368 | sas_address); |
4369 | if (!sas_expander) { | ||
4370 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); | ||
4371 | return; | ||
4372 | } | ||
4373 | list_del(&sas_expander->list); | ||
4366 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); | 4374 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); |
4367 | _scsih_expander_node_remove(ioc, sas_expander); | 4375 | _scsih_expander_node_remove(ioc, sas_expander); |
4368 | } | 4376 | } |
@@ -4652,6 +4660,33 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, | |||
4652 | sas_device_backup.sas_address)); | 4660 | sas_device_backup.sas_address)); |
4653 | } | 4661 | } |
4654 | 4662 | ||
4663 | /** | ||
4664 | * mpt2sas_device_remove - removing device object | ||
4665 | * @ioc: per adapter object | ||
4666 | * @sas_address: expander sas_address | ||
4667 | * | ||
4668 | * Return nothing. | ||
4669 | */ | ||
4670 | void | ||
4671 | mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) | ||
4672 | { | ||
4673 | struct _sas_device *sas_device; | ||
4674 | unsigned long flags; | ||
4675 | |||
4676 | if (ioc->shost_recovery) | ||
4677 | return; | ||
4678 | |||
4679 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | ||
4680 | sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, | ||
4681 | sas_address); | ||
4682 | if (!sas_device) { | ||
4683 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
4684 | return; | ||
4685 | } | ||
4686 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
4687 | _scsih_remove_device(ioc, sas_device); | ||
4688 | } | ||
4689 | |||
4655 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | 4690 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING |
4656 | /** | 4691 | /** |
4657 | * _scsih_sas_topology_change_event_debug - debug for topology event | 4692 | * _scsih_sas_topology_change_event_debug - debug for topology event |
@@ -4853,7 +4888,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, | |||
4853 | /* handle expander removal */ | 4888 | /* handle expander removal */ |
4854 | if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && | 4889 | if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && |
4855 | sas_expander) | 4890 | sas_expander) |
4856 | _scsih_expander_remove(ioc, sas_address); | 4891 | mpt2sas_expander_remove(ioc, sas_address); |
4857 | 4892 | ||
4858 | } | 4893 | } |
4859 | 4894 | ||
@@ -6228,7 +6263,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) | |||
6228 | sas_expander->responding = 0; | 6263 | sas_expander->responding = 0; |
6229 | continue; | 6264 | continue; |
6230 | } | 6265 | } |
6231 | _scsih_expander_remove(ioc, sas_expander->sas_address); | 6266 | mpt2sas_expander_remove(ioc, sas_expander->sas_address); |
6232 | goto retry_expander_search; | 6267 | goto retry_expander_search; |
6233 | } | 6268 | } |
6234 | } | 6269 | } |
@@ -6499,56 +6534,23 @@ static void | |||
6499 | _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, | 6534 | _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, |
6500 | struct _sas_node *sas_expander) | 6535 | struct _sas_node *sas_expander) |
6501 | { | 6536 | { |
6502 | struct _sas_port *mpt2sas_port; | 6537 | struct _sas_port *mpt2sas_port, *next; |
6503 | struct _sas_device *sas_device; | ||
6504 | struct _sas_node *expander_sibling; | ||
6505 | unsigned long flags; | ||
6506 | |||
6507 | if (!sas_expander) | ||
6508 | return; | ||
6509 | 6538 | ||
6510 | /* remove sibling ports attached to this expander */ | 6539 | /* remove sibling ports attached to this expander */ |
6511 | retry_device_search: | 6540 | list_for_each_entry_safe(mpt2sas_port, next, |
6512 | list_for_each_entry(mpt2sas_port, | ||
6513 | &sas_expander->sas_port_list, port_list) { | ||
6514 | if (mpt2sas_port->remote_identify.device_type == | ||
6515 | SAS_END_DEVICE) { | ||
6516 | spin_lock_irqsave(&ioc->sas_device_lock, flags); | ||
6517 | sas_device = | ||
6518 | mpt2sas_scsih_sas_device_find_by_sas_address(ioc, | ||
6519 | mpt2sas_port->remote_identify.sas_address); | ||
6520 | spin_unlock_irqrestore(&ioc->sas_device_lock, flags); | ||
6521 | if (!sas_device) | ||
6522 | continue; | ||
6523 | _scsih_remove_device(ioc, sas_device); | ||
6524 | if (ioc->shost_recovery) | ||
6525 | return; | ||
6526 | goto retry_device_search; | ||
6527 | } | ||
6528 | } | ||
6529 | |||
6530 | retry_expander_search: | ||
6531 | list_for_each_entry(mpt2sas_port, | ||
6532 | &sas_expander->sas_port_list, port_list) { | 6541 | &sas_expander->sas_port_list, port_list) { |
6533 | 6542 | if (ioc->shost_recovery) | |
6543 | return; | ||
6534 | if (mpt2sas_port->remote_identify.device_type == | 6544 | if (mpt2sas_port->remote_identify.device_type == |
6535 | MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || | 6545 | SAS_END_DEVICE) |
6546 | mpt2sas_device_remove(ioc, | ||
6547 | mpt2sas_port->remote_identify.sas_address); | ||
6548 | else if (mpt2sas_port->remote_identify.device_type == | ||
6549 | SAS_EDGE_EXPANDER_DEVICE || | ||
6536 | mpt2sas_port->remote_identify.device_type == | 6550 | mpt2sas_port->remote_identify.device_type == |
6537 | MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) { | 6551 | SAS_FANOUT_EXPANDER_DEVICE) |
6538 | 6552 | mpt2sas_expander_remove(ioc, | |
6539 | spin_lock_irqsave(&ioc->sas_node_lock, flags); | 6553 | mpt2sas_port->remote_identify.sas_address); |
6540 | expander_sibling = | ||
6541 | mpt2sas_scsih_expander_find_by_sas_address( | ||
6542 | ioc, mpt2sas_port->remote_identify.sas_address); | ||
6543 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); | ||
6544 | if (!expander_sibling) | ||
6545 | continue; | ||
6546 | _scsih_expander_remove(ioc, | ||
6547 | expander_sibling->sas_address); | ||
6548 | if (ioc->shost_recovery) | ||
6549 | return; | ||
6550 | goto retry_expander_search; | ||
6551 | } | ||
6552 | } | 6554 | } |
6553 | 6555 | ||
6554 | mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, | 6556 | mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, |
@@ -6559,7 +6561,6 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, | |||
6559 | sas_expander->handle, (unsigned long long) | 6561 | sas_expander->handle, (unsigned long long) |
6560 | sas_expander->sas_address); | 6562 | sas_expander->sas_address); |
6561 | 6563 | ||
6562 | list_del(&sas_expander->list); | ||
6563 | kfree(sas_expander->phy); | 6564 | kfree(sas_expander->phy); |
6564 | kfree(sas_expander); | 6565 | kfree(sas_expander); |
6565 | } | 6566 | } |
@@ -6677,9 +6678,7 @@ _scsih_remove(struct pci_dev *pdev) | |||
6677 | { | 6678 | { |
6678 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | 6679 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
6679 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | 6680 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); |
6680 | struct _sas_port *mpt2sas_port; | 6681 | struct _sas_port *mpt2sas_port, *next_port; |
6681 | struct _sas_device *sas_device; | ||
6682 | struct _sas_node *expander_sibling; | ||
6683 | struct _raid_device *raid_device, *next; | 6682 | struct _raid_device *raid_device, *next; |
6684 | struct MPT2SAS_TARGET *sas_target_priv_data; | 6683 | struct MPT2SAS_TARGET *sas_target_priv_data; |
6685 | struct workqueue_struct *wq; | 6684 | struct workqueue_struct *wq; |
@@ -6711,28 +6710,18 @@ _scsih_remove(struct pci_dev *pdev) | |||
6711 | } | 6710 | } |
6712 | 6711 | ||
6713 | /* free ports attached to the sas_host */ | 6712 | /* free ports attached to the sas_host */ |
6714 | retry_again: | 6713 | list_for_each_entry_safe(mpt2sas_port, next_port, |
6715 | list_for_each_entry(mpt2sas_port, | ||
6716 | &ioc->sas_hba.sas_port_list, port_list) { | 6714 | &ioc->sas_hba.sas_port_list, port_list) { |
6717 | if (mpt2sas_port->remote_identify.device_type == | 6715 | if (mpt2sas_port->remote_identify.device_type == |
6718 | SAS_END_DEVICE) { | 6716 | SAS_END_DEVICE) |
6719 | sas_device = | 6717 | mpt2sas_device_remove(ioc, |
6720 | mpt2sas_scsih_sas_device_find_by_sas_address(ioc, | 6718 | mpt2sas_port->remote_identify.sas_address); |
6721 | mpt2sas_port->remote_identify.sas_address); | 6719 | else if (mpt2sas_port->remote_identify.device_type == |
6722 | if (sas_device) { | 6720 | SAS_EDGE_EXPANDER_DEVICE || |
6723 | _scsih_remove_device(ioc, sas_device); | 6721 | mpt2sas_port->remote_identify.device_type == |
6724 | goto retry_again; | 6722 | SAS_FANOUT_EXPANDER_DEVICE) |
6725 | } | 6723 | mpt2sas_expander_remove(ioc, |
6726 | } else { | ||
6727 | expander_sibling = | ||
6728 | mpt2sas_scsih_expander_find_by_sas_address(ioc, | ||
6729 | mpt2sas_port->remote_identify.sas_address); | 6724 | mpt2sas_port->remote_identify.sas_address); |
6730 | if (expander_sibling) { | ||
6731 | _scsih_expander_remove(ioc, | ||
6732 | expander_sibling->sas_address); | ||
6733 | goto retry_again; | ||
6734 | } | ||
6735 | } | ||
6736 | } | 6725 | } |
6737 | 6726 | ||
6738 | /* free phys attached to the sas_host */ | 6727 | /* free phys attached to the sas_host */ |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index b55c6dc07470..cb1cdecbe0f8 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c | |||
@@ -465,62 +465,149 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
465 | return rc; | 465 | return rc; |
466 | } | 466 | } |
467 | 467 | ||
468 | /** | ||
469 | * _transport_delete_port - helper function to removing a port | ||
470 | * @ioc: per adapter object | ||
471 | * @mpt2sas_port: mpt2sas per port object | ||
472 | * | ||
473 | * Returns nothing. | ||
474 | */ | ||
475 | static void | ||
476 | _transport_delete_port(struct MPT2SAS_ADAPTER *ioc, | ||
477 | struct _sas_port *mpt2sas_port) | ||
478 | { | ||
479 | u64 sas_address = mpt2sas_port->remote_identify.sas_address; | ||
480 | enum sas_device_type device_type = | ||
481 | mpt2sas_port->remote_identify.device_type; | ||
482 | |||
483 | dev_printk(KERN_INFO, &mpt2sas_port->port->dev, | ||
484 | "remove: sas_addr(0x%016llx)\n", | ||
485 | (unsigned long long) sas_address); | ||
486 | |||
487 | ioc->logging_level |= MPT_DEBUG_TRANSPORT; | ||
488 | if (device_type == SAS_END_DEVICE) | ||
489 | mpt2sas_device_remove(ioc, sas_address); | ||
490 | else if (device_type == SAS_EDGE_EXPANDER_DEVICE || | ||
491 | device_type == SAS_FANOUT_EXPANDER_DEVICE) | ||
492 | mpt2sas_expander_remove(ioc, sas_address); | ||
493 | ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; | ||
494 | } | ||
468 | 495 | ||
469 | /** | 496 | /** |
470 | * _transport_delete_duplicate_port - (see below description) | 497 | * _transport_delete_phy - helper function to removing single phy from port |
471 | * @ioc: per adapter object | 498 | * @ioc: per adapter object |
472 | * @sas_node: sas node object (either expander or sas host) | 499 | * @mpt2sas_port: mpt2sas per port object |
473 | * @sas_address: sas address of device being added | 500 | * @mpt2sas_phy: mpt2sas per phy object |
474 | * @phy_num: phy number | ||
475 | * | 501 | * |
476 | * This function is called when attempting to add a new port that is claiming | 502 | * Returns nothing. |
477 | * the same phy resources already in use by another port. If we don't release | 503 | */ |
478 | * the claimed phy resources, the sas transport layer will hang from the BUG | 504 | static void |
479 | * in sas_port_add_phy. | 505 | _transport_delete_phy(struct MPT2SAS_ADAPTER *ioc, |
506 | struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) | ||
507 | { | ||
508 | u64 sas_address = mpt2sas_port->remote_identify.sas_address; | ||
509 | |||
510 | dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, | ||
511 | "remove: sas_addr(0x%016llx), phy(%d)\n", | ||
512 | (unsigned long long) sas_address, mpt2sas_phy->phy_id); | ||
513 | |||
514 | list_del(&mpt2sas_phy->port_siblings); | ||
515 | mpt2sas_port->num_phys--; | ||
516 | sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); | ||
517 | mpt2sas_phy->phy_belongs_to_port = 0; | ||
518 | } | ||
519 | |||
520 | /** | ||
521 | * _transport_add_phy - helper function to adding single phy to port | ||
522 | * @ioc: per adapter object | ||
523 | * @mpt2sas_port: mpt2sas per port object | ||
524 | * @mpt2sas_phy: mpt2sas per phy object | ||
480 | * | 525 | * |
481 | * The reason we would hit this issue is becuase someone is changing the | 526 | * Returns nothing. |
482 | * sas address of a device on the fly, meanwhile controller firmware sends | ||
483 | * EVENTs out of order when removing the previous instance of the device. | ||
484 | */ | 527 | */ |
485 | static void | 528 | static void |
486 | _transport_delete_duplicate_port(struct MPT2SAS_ADAPTER *ioc, | 529 | _transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, |
487 | struct _sas_node *sas_node, u64 sas_address, int phy_num) | 530 | struct _sas_phy *mpt2sas_phy) |
488 | { | 531 | { |
489 | struct _sas_port *mpt2sas_port, *mpt2sas_port_duplicate; | 532 | u64 sas_address = mpt2sas_port->remote_identify.sas_address; |
490 | struct _sas_phy *mpt2sas_phy; | ||
491 | 533 | ||
492 | printk(MPT2SAS_ERR_FMT "new device located at sas_addr(0x%016llx), " | 534 | dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, |
493 | "phy_id(%d)\n", ioc->name, (unsigned long long)sas_address, | 535 | "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) |
494 | phy_num); | 536 | sas_address, mpt2sas_phy->phy_id); |
495 | 537 | ||
496 | mpt2sas_port_duplicate = NULL; | 538 | list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); |
497 | list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, port_list) { | 539 | mpt2sas_port->num_phys++; |
498 | dev_printk(KERN_ERR, &mpt2sas_port->port->dev, | 540 | sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); |
499 | "existing device at sas_addr(0x%016llx), num_phys(%d)\n", | 541 | mpt2sas_phy->phy_belongs_to_port = 1; |
500 | (unsigned long long) | 542 | } |
501 | mpt2sas_port->remote_identify.sas_address, | 543 | |
502 | mpt2sas_port->num_phys); | 544 | /** |
503 | list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, | 545 | * _transport_add_phy_to_an_existing_port - adding new phy to existing port |
546 | * @ioc: per adapter object | ||
547 | * @sas_node: sas node object (either expander or sas host) | ||
548 | * @mpt2sas_phy: mpt2sas per phy object | ||
549 | * @sas_address: sas address of device/expander were phy needs to be added to | ||
550 | * | ||
551 | * Returns nothing. | ||
552 | */ | ||
553 | static void | ||
554 | _transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc, | ||
555 | struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address) | ||
556 | { | ||
557 | struct _sas_port *mpt2sas_port; | ||
558 | struct _sas_phy *phy_srch; | ||
559 | |||
560 | if (mpt2sas_phy->phy_belongs_to_port == 1) | ||
561 | return; | ||
562 | |||
563 | list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, | ||
564 | port_list) { | ||
565 | if (mpt2sas_port->remote_identify.sas_address != | ||
566 | sas_address) | ||
567 | continue; | ||
568 | list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, | ||
504 | port_siblings) { | 569 | port_siblings) { |
505 | dev_printk(KERN_ERR, &mpt2sas_phy->phy->dev, | 570 | if (phy_srch == mpt2sas_phy) |
506 | "phy_number(%d)\n", mpt2sas_phy->phy_id); | 571 | return; |
507 | if (mpt2sas_phy->phy_id == phy_num) | ||
508 | mpt2sas_port_duplicate = mpt2sas_port; | ||
509 | } | 572 | } |
573 | _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); | ||
574 | return; | ||
510 | } | 575 | } |
511 | 576 | ||
512 | if (!mpt2sas_port_duplicate) | 577 | } |
578 | |||
579 | /** | ||
580 | * _transport_del_phy_from_an_existing_port - delete phy from existing port | ||
581 | * @ioc: per adapter object | ||
582 | * @sas_node: sas node object (either expander or sas host) | ||
583 | * @mpt2sas_phy: mpt2sas per phy object | ||
584 | * | ||
585 | * Returns nothing. | ||
586 | */ | ||
587 | static void | ||
588 | _transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc, | ||
589 | struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) | ||
590 | { | ||
591 | struct _sas_port *mpt2sas_port, *next; | ||
592 | struct _sas_phy *phy_srch; | ||
593 | |||
594 | if (mpt2sas_phy->phy_belongs_to_port == 0) | ||
513 | return; | 595 | return; |
514 | 596 | ||
515 | dev_printk(KERN_ERR, &mpt2sas_port_duplicate->port->dev, | 597 | list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, |
516 | "deleting duplicate device at sas_addr(0x%016llx), phy(%d)!!!!\n", | 598 | port_list) { |
517 | (unsigned long long) | 599 | list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, |
518 | mpt2sas_port_duplicate->remote_identify.sas_address, phy_num); | 600 | port_siblings) { |
519 | ioc->logging_level |= MPT_DEBUG_TRANSPORT; | 601 | if (phy_srch != mpt2sas_phy) |
520 | mpt2sas_transport_port_remove(ioc, | 602 | continue; |
521 | mpt2sas_port_duplicate->remote_identify.sas_address, | 603 | if (mpt2sas_port->num_phys == 1) |
522 | sas_node->sas_address); | 604 | _transport_delete_port(ioc, mpt2sas_port); |
523 | ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; | 605 | else |
606 | _transport_delete_phy(ioc, mpt2sas_port, | ||
607 | mpt2sas_phy); | ||
608 | return; | ||
609 | } | ||
610 | } | ||
524 | } | 611 | } |
525 | 612 | ||
526 | /** | 613 | /** |
@@ -537,11 +624,13 @@ _transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, | |||
537 | { | 624 | { |
538 | int i; | 625 | int i; |
539 | 626 | ||
540 | for (i = 0; i < sas_node->num_phys; i++) | 627 | for (i = 0; i < sas_node->num_phys; i++) { |
541 | if (sas_node->phy[i].remote_identify.sas_address == sas_address) | 628 | if (sas_node->phy[i].remote_identify.sas_address != sas_address) |
542 | if (sas_node->phy[i].phy_belongs_to_port) | 629 | continue; |
543 | _transport_delete_duplicate_port(ioc, sas_node, | 630 | if (sas_node->phy[i].phy_belongs_to_port == 1) |
544 | sas_address, i); | 631 | _transport_del_phy_from_an_existing_port(ioc, sas_node, |
632 | &sas_node->phy[i]); | ||
633 | } | ||
545 | } | 634 | } |
546 | 635 | ||
547 | /** | 636 | /** |
@@ -905,10 +994,12 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, | |||
905 | 994 | ||
906 | mpt2sas_phy = &sas_node->phy[phy_number]; | 995 | mpt2sas_phy = &sas_node->phy[phy_number]; |
907 | mpt2sas_phy->attached_handle = handle; | 996 | mpt2sas_phy->attached_handle = handle; |
908 | if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) | 997 | if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { |
909 | _transport_set_identify(ioc, handle, | 998 | _transport_set_identify(ioc, handle, |
910 | &mpt2sas_phy->remote_identify); | 999 | &mpt2sas_phy->remote_identify); |
911 | else | 1000 | _transport_add_phy_to_an_existing_port(ioc, sas_node, |
1001 | mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); | ||
1002 | } else | ||
912 | memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct | 1003 | memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct |
913 | sas_identify)); | 1004 | sas_identify)); |
914 | 1005 | ||