diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_transport.c')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_transport.c | 283 |
1 files changed, 221 insertions, 62 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index eb98188c7f3f..bd7ca2b49f81 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/workqueue.h> | 49 | #include <linux/workqueue.h> |
50 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
51 | #include <linux/pci.h> | 51 | #include <linux/pci.h> |
52 | #include <linux/slab.h> | ||
52 | 53 | ||
53 | #include <scsi/scsi.h> | 54 | #include <scsi/scsi.h> |
54 | #include <scsi/scsi_cmnd.h> | 55 | #include <scsi/scsi_cmnd.h> |
@@ -59,24 +60,23 @@ | |||
59 | 60 | ||
60 | #include "mpt2sas_base.h" | 61 | #include "mpt2sas_base.h" |
61 | /** | 62 | /** |
62 | * _transport_sas_node_find_by_handle - sas node search | 63 | * _transport_sas_node_find_by_sas_address - sas node search |
63 | * @ioc: per adapter object | 64 | * @ioc: per adapter object |
64 | * @handle: expander or hba handle (assigned by firmware) | 65 | * @sas_address: sas address of expander or sas host |
65 | * Context: Calling function should acquire ioc->sas_node_lock. | 66 | * Context: Calling function should acquire ioc->sas_node_lock. |
66 | * | 67 | * |
67 | * Search for either hba phys or expander device based on handle, then returns | 68 | * Search for either hba phys or expander device based on handle, then returns |
68 | * the sas_node object. | 69 | * the sas_node object. |
69 | */ | 70 | */ |
70 | static struct _sas_node * | 71 | static struct _sas_node * |
71 | _transport_sas_node_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) | 72 | _transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, |
73 | u64 sas_address) | ||
72 | { | 74 | { |
73 | int i; | 75 | if (ioc->sas_hba.sas_address == sas_address) |
74 | 76 | return &ioc->sas_hba; | |
75 | for (i = 0; i < ioc->sas_hba.num_phys; i++) | 77 | else |
76 | if (ioc->sas_hba.phy[i].handle == handle) | 78 | return mpt2sas_scsih_expander_find_by_sas_address(ioc, |
77 | return &ioc->sas_hba; | 79 | sas_address); |
78 | |||
79 | return mpt2sas_scsih_expander_find_by_handle(ioc, handle); | ||
80 | } | 80 | } |
81 | 81 | ||
82 | /** | 82 | /** |
@@ -259,8 +259,7 @@ struct rep_manu_reply{ | |||
259 | u8 response_length; | 259 | u8 response_length; |
260 | u16 expander_change_count; | 260 | u16 expander_change_count; |
261 | u8 reserved0[2]; | 261 | u8 reserved0[2]; |
262 | u8 sas_format:1; | 262 | u8 sas_format; |
263 | u8 reserved1:7; | ||
264 | u8 reserved2[3]; | 263 | u8 reserved2[3]; |
265 | u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; | 264 | u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; |
266 | u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; | 265 | u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; |
@@ -375,7 +374,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
375 | mpi_request->VP_ID = 0; | 374 | mpi_request->VP_ID = 0; |
376 | sas_address_le = (u64 *)&mpi_request->SASAddress; | 375 | sas_address_le = (u64 *)&mpi_request->SASAddress; |
377 | *sas_address_le = cpu_to_le64(sas_address); | 376 | *sas_address_le = cpu_to_le64(sas_address); |
378 | mpi_request->RequestDataLength = sizeof(struct rep_manu_request); | 377 | mpi_request->RequestDataLength = |
378 | cpu_to_le16(sizeof(struct rep_manu_request)); | ||
379 | psge = &mpi_request->SGL; | 379 | psge = &mpi_request->SGL; |
380 | 380 | ||
381 | /* WRITE sgel first */ | 381 | /* WRITE sgel first */ |
@@ -438,8 +438,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
438 | SAS_EXPANDER_PRODUCT_ID_LEN); | 438 | SAS_EXPANDER_PRODUCT_ID_LEN); |
439 | strncpy(edev->product_rev, manufacture_reply->product_rev, | 439 | strncpy(edev->product_rev, manufacture_reply->product_rev, |
440 | SAS_EXPANDER_PRODUCT_REV_LEN); | 440 | SAS_EXPANDER_PRODUCT_REV_LEN); |
441 | edev->level = manufacture_reply->sas_format; | 441 | edev->level = manufacture_reply->sas_format & 1; |
442 | if (manufacture_reply->sas_format) { | 442 | if (edev->level) { |
443 | strncpy(edev->component_vendor_id, | 443 | strncpy(edev->component_vendor_id, |
444 | manufacture_reply->component_vendor_id, | 444 | manufacture_reply->component_vendor_id, |
445 | SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); | 445 | SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); |
@@ -469,7 +469,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
469 | * mpt2sas_transport_port_add - insert port to the list | 469 | * mpt2sas_transport_port_add - insert port to the list |
470 | * @ioc: per adapter object | 470 | * @ioc: per adapter object |
471 | * @handle: handle of attached device | 471 | * @handle: handle of attached device |
472 | * @parent_handle: parent handle(either hba or expander) | 472 | * @sas_address: sas address of parent expander or sas host |
473 | * Context: This function will acquire ioc->sas_node_lock. | 473 | * Context: This function will acquire ioc->sas_node_lock. |
474 | * | 474 | * |
475 | * Adding new port object to the sas_node->sas_port_list. | 475 | * Adding new port object to the sas_node->sas_port_list. |
@@ -478,7 +478,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, | |||
478 | */ | 478 | */ |
479 | struct _sas_port * | 479 | struct _sas_port * |
480 | mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | 480 | mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, |
481 | u16 parent_handle) | 481 | u64 sas_address) |
482 | { | 482 | { |
483 | struct _sas_phy *mpt2sas_phy, *next; | 483 | struct _sas_phy *mpt2sas_phy, *next; |
484 | struct _sas_port *mpt2sas_port; | 484 | struct _sas_port *mpt2sas_port; |
@@ -488,9 +488,6 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
488 | int i; | 488 | int i; |
489 | struct sas_port *port; | 489 | struct sas_port *port; |
490 | 490 | ||
491 | if (!parent_handle) | ||
492 | return NULL; | ||
493 | |||
494 | mpt2sas_port = kzalloc(sizeof(struct _sas_port), | 491 | mpt2sas_port = kzalloc(sizeof(struct _sas_port), |
495 | GFP_KERNEL); | 492 | GFP_KERNEL); |
496 | if (!mpt2sas_port) { | 493 | if (!mpt2sas_port) { |
@@ -502,17 +499,16 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
502 | INIT_LIST_HEAD(&mpt2sas_port->port_list); | 499 | INIT_LIST_HEAD(&mpt2sas_port->port_list); |
503 | INIT_LIST_HEAD(&mpt2sas_port->phy_list); | 500 | INIT_LIST_HEAD(&mpt2sas_port->phy_list); |
504 | spin_lock_irqsave(&ioc->sas_node_lock, flags); | 501 | spin_lock_irqsave(&ioc->sas_node_lock, flags); |
505 | sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle); | 502 | sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); |
506 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); | 503 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); |
507 | 504 | ||
508 | if (!sas_node) { | 505 | if (!sas_node) { |
509 | printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n", | 506 | printk(MPT2SAS_ERR_FMT "%s: Could not find " |
510 | ioc->name, __func__, parent_handle); | 507 | "parent sas_address(0x%016llx)!\n", ioc->name, |
508 | __func__, (unsigned long long)sas_address); | ||
511 | goto out_fail; | 509 | goto out_fail; |
512 | } | 510 | } |
513 | 511 | ||
514 | mpt2sas_port->handle = parent_handle; | ||
515 | mpt2sas_port->sas_address = sas_node->sas_address; | ||
516 | if ((_transport_set_identify(ioc, handle, | 512 | if ((_transport_set_identify(ioc, handle, |
517 | &mpt2sas_port->remote_identify))) { | 513 | &mpt2sas_port->remote_identify))) { |
518 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | 514 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", |
@@ -604,7 +600,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
604 | * mpt2sas_transport_port_remove - remove port from the list | 600 | * mpt2sas_transport_port_remove - remove port from the list |
605 | * @ioc: per adapter object | 601 | * @ioc: per adapter object |
606 | * @sas_address: sas address of attached device | 602 | * @sas_address: sas address of attached device |
607 | * @parent_handle: handle to the upstream parent(either hba or expander) | 603 | * @sas_address_parent: sas address of parent expander or sas host |
608 | * Context: This function will acquire ioc->sas_node_lock. | 604 | * Context: This function will acquire ioc->sas_node_lock. |
609 | * | 605 | * |
610 | * Removing object and freeing associated memory from the | 606 | * Removing object and freeing associated memory from the |
@@ -614,7 +610,7 @@ mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, | |||
614 | */ | 610 | */ |
615 | void | 611 | void |
616 | mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | 612 | mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, |
617 | u16 parent_handle) | 613 | u64 sas_address_parent) |
618 | { | 614 | { |
619 | int i; | 615 | int i; |
620 | unsigned long flags; | 616 | unsigned long flags; |
@@ -624,7 +620,8 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | |||
624 | struct _sas_phy *mpt2sas_phy, *next_phy; | 620 | struct _sas_phy *mpt2sas_phy, *next_phy; |
625 | 621 | ||
626 | spin_lock_irqsave(&ioc->sas_node_lock, flags); | 622 | spin_lock_irqsave(&ioc->sas_node_lock, flags); |
627 | sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle); | 623 | sas_node = _transport_sas_node_find_by_sas_address(ioc, |
624 | sas_address_parent); | ||
628 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); | 625 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); |
629 | if (!sas_node) | 626 | if (!sas_node) |
630 | return; | 627 | return; |
@@ -650,8 +647,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, | |||
650 | &mpt2sas_port->phy_list, port_siblings) { | 647 | &mpt2sas_port->phy_list, port_siblings) { |
651 | if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) | 648 | if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) |
652 | dev_printk(KERN_INFO, &mpt2sas_port->port->dev, | 649 | dev_printk(KERN_INFO, &mpt2sas_port->port->dev, |
653 | "remove: parent_handle(0x%04x), " | 650 | "remove: sas_addr(0x%016llx), phy(%d)\n", |
654 | "sas_addr(0x%016llx), phy(%d)\n", parent_handle, | ||
655 | (unsigned long long) | 651 | (unsigned long long) |
656 | mpt2sas_port->remote_identify.sas_address, | 652 | mpt2sas_port->remote_identify.sas_address, |
657 | mpt2sas_phy->phy_id); | 653 | mpt2sas_phy->phy_id); |
@@ -799,8 +795,8 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy | |||
799 | /** | 795 | /** |
800 | * mpt2sas_transport_update_links - refreshing phy link changes | 796 | * mpt2sas_transport_update_links - refreshing phy link changes |
801 | * @ioc: per adapter object | 797 | * @ioc: per adapter object |
802 | * @handle: handle to sas_host or expander | 798 | * @sas_address: sas address of parent expander or sas host |
803 | * @attached_handle: attached device handle | 799 | * @handle: attached device handle |
804 | * @phy_numberv: phy number | 800 | * @phy_numberv: phy number |
805 | * @link_rate: new link rate | 801 | * @link_rate: new link rate |
806 | * | 802 | * |
@@ -808,28 +804,25 @@ mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy | |||
808 | */ | 804 | */ |
809 | void | 805 | void |
810 | mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, | 806 | mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, |
811 | u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate) | 807 | u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) |
812 | { | 808 | { |
813 | unsigned long flags; | 809 | unsigned long flags; |
814 | struct _sas_node *sas_node; | 810 | struct _sas_node *sas_node; |
815 | struct _sas_phy *mpt2sas_phy; | 811 | struct _sas_phy *mpt2sas_phy; |
816 | 812 | ||
817 | if (ioc->shost_recovery) { | 813 | if (ioc->shost_recovery) |
818 | printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", | ||
819 | __func__, ioc->name); | ||
820 | return; | 814 | return; |
821 | } | ||
822 | 815 | ||
823 | spin_lock_irqsave(&ioc->sas_node_lock, flags); | 816 | spin_lock_irqsave(&ioc->sas_node_lock, flags); |
824 | sas_node = _transport_sas_node_find_by_handle(ioc, handle); | 817 | sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); |
825 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); | 818 | spin_unlock_irqrestore(&ioc->sas_node_lock, flags); |
826 | if (!sas_node) | 819 | if (!sas_node) |
827 | return; | 820 | return; |
828 | 821 | ||
829 | mpt2sas_phy = &sas_node->phy[phy_number]; | 822 | mpt2sas_phy = &sas_node->phy[phy_number]; |
830 | mpt2sas_phy->attached_handle = attached_handle; | 823 | mpt2sas_phy->attached_handle = handle; |
831 | if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) | 824 | if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) |
832 | _transport_set_identify(ioc, mpt2sas_phy->attached_handle, | 825 | _transport_set_identify(ioc, handle, |
833 | &mpt2sas_phy->remote_identify); | 826 | &mpt2sas_phy->remote_identify); |
834 | else | 827 | else |
835 | memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct | 828 | memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct |
@@ -841,13 +834,11 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, | |||
841 | 834 | ||
842 | if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) | 835 | if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) |
843 | dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, | 836 | dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, |
844 | "refresh: handle(0x%04x), sas_addr(0x%016llx),\n" | 837 | "refresh: parent sas_addr(0x%016llx),\n" |
845 | "\tlink_rate(0x%02x), phy(%d)\n" | 838 | "\tlink_rate(0x%02x), phy(%d)\n" |
846 | "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", | 839 | "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", |
847 | handle, (unsigned long long) | 840 | (unsigned long long)sas_address, |
848 | mpt2sas_phy->identify.sas_address, link_rate, | 841 | link_rate, phy_number, handle, (unsigned long long) |
849 | phy_number, attached_handle, | ||
850 | (unsigned long long) | ||
851 | mpt2sas_phy->remote_identify.sas_address); | 842 | mpt2sas_phy->remote_identify.sas_address); |
852 | } | 843 | } |
853 | 844 | ||
@@ -865,6 +856,17 @@ rphy_to_ioc(struct sas_rphy *rphy) | |||
865 | return shost_priv(shost); | 856 | return shost_priv(shost); |
866 | } | 857 | } |
867 | 858 | ||
859 | static struct _sas_phy * | ||
860 | _transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy) | ||
861 | { | ||
862 | int i; | ||
863 | |||
864 | for (i = 0; i < ioc->sas_hba.num_phys; i++) | ||
865 | if (ioc->sas_hba.phy[i].phy == phy) | ||
866 | return(&ioc->sas_hba.phy[i]); | ||
867 | return NULL; | ||
868 | } | ||
869 | |||
868 | /** | 870 | /** |
869 | * _transport_get_linkerrors - | 871 | * _transport_get_linkerrors - |
870 | * @phy: The sas phy object | 872 | * @phy: The sas phy object |
@@ -880,14 +882,8 @@ _transport_get_linkerrors(struct sas_phy *phy) | |||
880 | struct _sas_phy *mpt2sas_phy; | 882 | struct _sas_phy *mpt2sas_phy; |
881 | Mpi2ConfigReply_t mpi_reply; | 883 | Mpi2ConfigReply_t mpi_reply; |
882 | Mpi2SasPhyPage1_t phy_pg1; | 884 | Mpi2SasPhyPage1_t phy_pg1; |
883 | int i; | ||
884 | 885 | ||
885 | for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && | 886 | mpt2sas_phy = _transport_find_local_phy(ioc, phy); |
886 | !mpt2sas_phy; i++) { | ||
887 | if (ioc->sas_hba.phy[i].phy != phy) | ||
888 | continue; | ||
889 | mpt2sas_phy = &ioc->sas_hba.phy[i]; | ||
890 | } | ||
891 | 887 | ||
892 | if (!mpt2sas_phy) /* this phy not on sas_host */ | 888 | if (!mpt2sas_phy) /* this phy not on sas_host */ |
893 | return -EINVAL; | 889 | return -EINVAL; |
@@ -981,14 +977,8 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) | |||
981 | struct _sas_phy *mpt2sas_phy; | 977 | struct _sas_phy *mpt2sas_phy; |
982 | Mpi2SasIoUnitControlReply_t mpi_reply; | 978 | Mpi2SasIoUnitControlReply_t mpi_reply; |
983 | Mpi2SasIoUnitControlRequest_t mpi_request; | 979 | Mpi2SasIoUnitControlRequest_t mpi_request; |
984 | int i; | ||
985 | 980 | ||
986 | for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys && | 981 | mpt2sas_phy = _transport_find_local_phy(ioc, phy); |
987 | !mpt2sas_phy; i++) { | ||
988 | if (ioc->sas_hba.phy[i].phy != phy) | ||
989 | continue; | ||
990 | mpt2sas_phy = &ioc->sas_hba.phy[i]; | ||
991 | } | ||
992 | 982 | ||
993 | if (!mpt2sas_phy) /* this phy not on sas_host */ | 983 | if (!mpt2sas_phy) /* this phy not on sas_host */ |
994 | return -EINVAL; | 984 | return -EINVAL; |
@@ -1016,6 +1006,173 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) | |||
1016 | } | 1006 | } |
1017 | 1007 | ||
1018 | /** | 1008 | /** |
1009 | * _transport_phy_enable - enable/disable phys | ||
1010 | * @phy: The sas phy object | ||
1011 | * @enable: enable phy when true | ||
1012 | * | ||
1013 | * Only support sas_host direct attached phys. | ||
1014 | * Returns 0 for success, non-zero for failure. | ||
1015 | */ | ||
1016 | static int | ||
1017 | _transport_phy_enable(struct sas_phy *phy, int enable) | ||
1018 | { | ||
1019 | struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); | ||
1020 | struct _sas_phy *mpt2sas_phy; | ||
1021 | Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; | ||
1022 | Mpi2ConfigReply_t mpi_reply; | ||
1023 | u16 ioc_status; | ||
1024 | u16 sz; | ||
1025 | int rc = 0; | ||
1026 | |||
1027 | mpt2sas_phy = _transport_find_local_phy(ioc, phy); | ||
1028 | |||
1029 | if (!mpt2sas_phy) /* this phy not on sas_host */ | ||
1030 | return -EINVAL; | ||
1031 | |||
1032 | /* sas_iounit page 1 */ | ||
1033 | sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * | ||
1034 | sizeof(Mpi2SasIOUnit1PhyData_t)); | ||
1035 | sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); | ||
1036 | if (!sas_iounit_pg1) { | ||
1037 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1038 | ioc->name, __FILE__, __LINE__, __func__); | ||
1039 | rc = -ENOMEM; | ||
1040 | goto out; | ||
1041 | } | ||
1042 | if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, | ||
1043 | sas_iounit_pg1, sz))) { | ||
1044 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1045 | ioc->name, __FILE__, __LINE__, __func__); | ||
1046 | rc = -ENXIO; | ||
1047 | goto out; | ||
1048 | } | ||
1049 | ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & | ||
1050 | MPI2_IOCSTATUS_MASK; | ||
1051 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { | ||
1052 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1053 | ioc->name, __FILE__, __LINE__, __func__); | ||
1054 | rc = -EIO; | ||
1055 | goto out; | ||
1056 | } | ||
1057 | |||
1058 | if (enable) | ||
1059 | sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags | ||
1060 | &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; | ||
1061 | else | ||
1062 | sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags | ||
1063 | |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; | ||
1064 | |||
1065 | mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); | ||
1066 | |||
1067 | out: | ||
1068 | kfree(sas_iounit_pg1); | ||
1069 | return rc; | ||
1070 | } | ||
1071 | |||
1072 | /** | ||
1073 | * _transport_phy_speed - set phy min/max link rates | ||
1074 | * @phy: The sas phy object | ||
1075 | * @rates: rates defined in sas_phy_linkrates | ||
1076 | * | ||
1077 | * Only support sas_host direct attached phys. | ||
1078 | * Returns 0 for success, non-zero for failure. | ||
1079 | */ | ||
1080 | static int | ||
1081 | _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) | ||
1082 | { | ||
1083 | struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); | ||
1084 | struct _sas_phy *mpt2sas_phy; | ||
1085 | Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; | ||
1086 | Mpi2SasPhyPage0_t phy_pg0; | ||
1087 | Mpi2ConfigReply_t mpi_reply; | ||
1088 | u16 ioc_status; | ||
1089 | u16 sz; | ||
1090 | int i; | ||
1091 | int rc = 0; | ||
1092 | |||
1093 | mpt2sas_phy = _transport_find_local_phy(ioc, phy); | ||
1094 | |||
1095 | if (!mpt2sas_phy) /* this phy not on sas_host */ | ||
1096 | return -EINVAL; | ||
1097 | |||
1098 | if (!rates->minimum_linkrate) | ||
1099 | rates->minimum_linkrate = phy->minimum_linkrate; | ||
1100 | else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) | ||
1101 | rates->minimum_linkrate = phy->minimum_linkrate_hw; | ||
1102 | |||
1103 | if (!rates->maximum_linkrate) | ||
1104 | rates->maximum_linkrate = phy->maximum_linkrate; | ||
1105 | else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) | ||
1106 | rates->maximum_linkrate = phy->maximum_linkrate_hw; | ||
1107 | |||
1108 | /* sas_iounit page 1 */ | ||
1109 | sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * | ||
1110 | sizeof(Mpi2SasIOUnit1PhyData_t)); | ||
1111 | sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); | ||
1112 | if (!sas_iounit_pg1) { | ||
1113 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1114 | ioc->name, __FILE__, __LINE__, __func__); | ||
1115 | rc = -ENOMEM; | ||
1116 | goto out; | ||
1117 | } | ||
1118 | if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, | ||
1119 | sas_iounit_pg1, sz))) { | ||
1120 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1121 | ioc->name, __FILE__, __LINE__, __func__); | ||
1122 | rc = -ENXIO; | ||
1123 | goto out; | ||
1124 | } | ||
1125 | ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & | ||
1126 | MPI2_IOCSTATUS_MASK; | ||
1127 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { | ||
1128 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1129 | ioc->name, __FILE__, __LINE__, __func__); | ||
1130 | rc = -EIO; | ||
1131 | goto out; | ||
1132 | } | ||
1133 | |||
1134 | for (i = 0; i < ioc->sas_hba.num_phys; i++) { | ||
1135 | if (mpt2sas_phy->phy_id != i) { | ||
1136 | sas_iounit_pg1->PhyData[i].MaxMinLinkRate = | ||
1137 | (ioc->sas_hba.phy[i].phy->minimum_linkrate + | ||
1138 | (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); | ||
1139 | } else { | ||
1140 | sas_iounit_pg1->PhyData[i].MaxMinLinkRate = | ||
1141 | (rates->minimum_linkrate + | ||
1142 | (rates->maximum_linkrate << 4)); | ||
1143 | } | ||
1144 | } | ||
1145 | |||
1146 | if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, | ||
1147 | sz)) { | ||
1148 | printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", | ||
1149 | ioc->name, __FILE__, __LINE__, __func__); | ||
1150 | rc = -ENXIO; | ||
1151 | goto out; | ||
1152 | } | ||
1153 | |||
1154 | /* link reset */ | ||
1155 | _transport_phy_reset(phy, 0); | ||
1156 | |||
1157 | /* read phy page 0, then update the rates in the sas transport phy */ | ||
1158 | if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, | ||
1159 | mpt2sas_phy->phy_id)) { | ||
1160 | phy->minimum_linkrate = _transport_convert_phy_link_rate( | ||
1161 | phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); | ||
1162 | phy->maximum_linkrate = _transport_convert_phy_link_rate( | ||
1163 | phy_pg0.ProgrammedLinkRate >> 4); | ||
1164 | phy->negotiated_linkrate = _transport_convert_phy_link_rate( | ||
1165 | phy_pg0.NegotiatedLinkRate & | ||
1166 | MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); | ||
1167 | } | ||
1168 | |||
1169 | out: | ||
1170 | kfree(sas_iounit_pg1); | ||
1171 | return rc; | ||
1172 | } | ||
1173 | |||
1174 | |||
1175 | /** | ||
1019 | * _transport_smp_handler - transport portal for smp passthru | 1176 | * _transport_smp_handler - transport portal for smp passthru |
1020 | * @shost: shost object | 1177 | * @shost: shost object |
1021 | * @rphy: sas transport rphy object | 1178 | * @rphy: sas transport rphy object |
@@ -1126,7 +1283,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1126 | dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), | 1283 | dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), |
1127 | blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); | 1284 | blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); |
1128 | if (!dma_addr_out) { | 1285 | if (!dma_addr_out) { |
1129 | mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); | 1286 | mpt2sas_base_free_smid(ioc, smid); |
1130 | goto unmap; | 1287 | goto unmap; |
1131 | } | 1288 | } |
1132 | 1289 | ||
@@ -1144,7 +1301,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
1144 | dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), | 1301 | dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), |
1145 | blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); | 1302 | blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); |
1146 | if (!dma_addr_in) { | 1303 | if (!dma_addr_in) { |
1147 | mpt2sas_base_free_smid(ioc, le16_to_cpu(smid)); | 1304 | mpt2sas_base_free_smid(ioc, smid); |
1148 | goto unmap; | 1305 | goto unmap; |
1149 | } | 1306 | } |
1150 | 1307 | ||
@@ -1217,6 +1374,8 @@ struct sas_function_template mpt2sas_transport_functions = { | |||
1217 | .get_enclosure_identifier = _transport_get_enclosure_identifier, | 1374 | .get_enclosure_identifier = _transport_get_enclosure_identifier, |
1218 | .get_bay_identifier = _transport_get_bay_identifier, | 1375 | .get_bay_identifier = _transport_get_bay_identifier, |
1219 | .phy_reset = _transport_phy_reset, | 1376 | .phy_reset = _transport_phy_reset, |
1377 | .phy_enable = _transport_phy_enable, | ||
1378 | .set_phy_speed = _transport_phy_speed, | ||
1220 | .smp_handler = _transport_smp_handler, | 1379 | .smp_handler = _transport_smp_handler, |
1221 | }; | 1380 | }; |
1222 | 1381 | ||