aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mpt2sas/mpt2sas_transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_transport.c')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c283
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 */
70static struct _sas_node * 71static 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 */
479struct _sas_port * 479struct _sas_port *
480mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, 480mpt2sas_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 */
615void 611void
616mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, 612mpt2sas_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 */
809void 805void
810mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, 806mpt2sas_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
859static 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 */
1016static 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 */
1080static 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