summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorxun ni - Sun Microsystems - Beijing China <Xun.Ni@Sun.COM>2010-04-19 11:31:17 +0800
committerxun ni - Sun Microsystems - Beijing China <Xun.Ni@Sun.COM>2010-04-19 11:31:17 +0800
commitf2e8686e6101ad6ab3df43205537e610151b5434 (patch)
tree1a0e61b09d25476c8f2f61481d0da5046b49ca8a /usr
parent0870f17b1158eef95a9cbc509c015c6467c7cdec (diff)
downloadillumos-joyent-f2e8686e6101ad6ab3df43205537e610151b5434.tar.gz
6931122 Need SMHBA support for Mptsas driver
6932019 sun_sas lib should ignore the virtual port for mptsas driver
Diffstat (limited to 'usr')
-rw-r--r--usr/src/lib/sun_sas/common/devtree_hba_disco.c20
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c906
-rw-r--r--usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c449
-rw-r--r--usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c454
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h79
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h50
7 files changed, 1911 insertions, 49 deletions
diff --git a/usr/src/lib/sun_sas/common/devtree_hba_disco.c b/usr/src/lib/sun_sas/common/devtree_hba_disco.c
index 65b2212598..2ba9ef6e57 100644
--- a/usr/src/lib/sun_sas/common/devtree_hba_disco.c
+++ b/usr/src/lib/sun_sas/common/devtree_hba_disco.c
@@ -20,11 +20,9 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
-
#include <sun_sas.h>
#include <sys/modctl.h>
#include <sys/types.h>
@@ -332,6 +330,14 @@ refresh_hba(di_node_t hbaNode, struct sun_sas_hba *hba_ptr)
}
while (portNode != DI_NODE_NIL) {
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
+ "virtual-port", &propIntData) >= 0) {
+ if (*propIntData) {
+ /* ignore a virtual port. */
+ portNode = di_sibling_node(portNode);
+ continue;
+ }
+ }
if (add_hba_port_info(portNode, hba_ptr, protocol)
== HBA_STATUS_ERROR) {
S_FREE(hba_ptr->first_port);
@@ -540,6 +546,14 @@ devtree_get_one_hba(di_node_t hbaNode)
}
while (portNode != DI_NODE_NIL) {
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, portNode,
+ "virtual-port", &propIntData) >= 0) {
+ if (*propIntData) {
+ /* ignore a virtual port. */
+ portNode = di_sibling_node(portNode);
+ continue;
+ }
+ }
if (add_hba_port_info(portNode, new_hba, protocol)
== HBA_STATUS_ERROR) {
S_FREE(new_hba->first_port);
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 76217f1f73..09560f032d 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1796,7 +1796,7 @@ ZYD_OBJS += zyd.o zyd_usb.o zyd_hw.o zyd_fw.o
MXFE_OBJS += mxfe.o
-MPTSAS_OBJS += mptsas.o mptsas_impl.o mptsas_init.o mptsas_raid.o
+MPTSAS_OBJS += mptsas.o mptsas_impl.o mptsas_init.o mptsas_raid.o mptsas_smhba.o
SFE_OBJS += sfe.o sfe_util.o
diff --git a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c
index 49a705d57a..3108bab6fc 100644
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c
@@ -71,6 +71,8 @@
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dr.h>
#include <sys/sata/sata_defs.h>
+#include <sys/scsi/generic/sas.h>
+#include <sys/scsi/impl/scsi_sas.h>
#pragma pack(1)
#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
@@ -90,6 +92,7 @@
#include <sys/scsi/impl/scsi_reset_notify.h>
#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
#include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
#include <sys/raidioctl.h>
#include <sys/fs/dv_node.h> /* devfs_clean */
@@ -548,6 +551,7 @@ static struct modlinkage modlinkage = {
};
#define TARGET_PROP "target"
#define LUN_PROP "lun"
+#define LUN64_PROP "lun64"
#define SAS_PROP "sas-mpt"
#define MDI_GUID "wwn"
#define NDI_GUID "guid"
@@ -585,6 +589,12 @@ _NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_device scsi_address))
_NOTE(SCHEME_PROTECTS_DATA("No Mutex Needed", mptsas_tgt_private))
_NOTE(SCHEME_PROTECTS_DATA("No Mutex Needed", scsi_hba_tran::tran_tgt_private))
+/*
+ * SM - HBA statics
+ */
+
+static char *mptsas_driver_rev = MPTSAS_MOD_STRING;
+
#ifdef MPTSAS_DEBUG
void debug_enter(char *);
#endif
@@ -675,14 +685,21 @@ mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
char *iport = NULL;
char phymask[MPTSAS_MAX_PHYS];
mptsas_phymask_t phy_mask = 0;
- int physport = -1;
int dynamic_port = 0;
uint32_t page_address;
char initiator_wwnstr[MPTSAS_WWN_STRLEN];
int rval = DDI_FAILURE;
int i = 0;
- uint64_t wwid = 0;
- uint8_t portwidth = 0;
+ uint8_t numphys = 0;
+ uint8_t phy_id;
+ uint8_t phy_port = 0;
+ uint16_t attached_devhdl = 0;
+ uint32_t dev_info;
+ uint64_t attached_sas_wwn;
+ uint16_t dev_hdl;
+ uint16_t pdev_hdl;
+ uint16_t bay_num, enclosure;
+ char attached_wwnstr[MPTSAS_WWN_STRLEN];
/* CONSTCOND */
ASSERT(NO_COMPETING_THREADS);
@@ -734,13 +751,23 @@ mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
*/
iport = ddi_get_name_addr(dip);
if (iport && strncmp(iport, "v0", 2) == 0) {
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
+ MPTSAS_VIRTUAL_PORT, 1) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
+ MPTSAS_VIRTUAL_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas virtual port "
+ "prop update failed");
+ return (DDI_FAILURE);
+ }
return (DDI_SUCCESS);
}
mutex_enter(&mpt->m_mutex);
for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
bzero(phymask, sizeof (phymask));
- (void) sprintf(phymask, "%x", mpt->m_phy_info[i].phy_mask);
+ (void) sprintf(phymask,
+ "%x", mpt->m_phy_info[i].phy_mask);
if (strcmp(phymask, iport) == 0) {
break;
}
@@ -754,33 +781,48 @@ mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
}
phy_mask = mpt->m_phy_info[i].phy_mask;
- physport = mpt->m_phy_info[i].port_num;
if (mpt->m_phy_info[i].port_flags & AUTO_PORT_CONFIGURATION)
dynamic_port = 1;
else
dynamic_port = 0;
- page_address = (MPI2_SASPORT_PGAD_FORM_PORT_NUM |
- (MPI2_SASPORT_PGAD_PORTNUMBER_MASK & physport));
-
- rval = mptsas_get_sas_port_page0(mpt, page_address, &wwid, &portwidth);
- if (rval != DDI_SUCCESS) {
- mptsas_log(mpt, CE_WARN, "Failed attach port %s because get"
- "SAS address of initiator failed!", iport);
+ /*
+ * Update PHY info for smhba
+ */
+ if (mptsas_smhba_phy_init(mpt)) {
mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas phy update "
+ "failed");
return (DDI_FAILURE);
}
+
mutex_exit(&mpt->m_mutex);
+ numphys = 0;
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ if ((phy_mask >> i) & 0x01) {
+ numphys++;
+ }
+ }
+
bzero(initiator_wwnstr, sizeof (initiator_wwnstr));
- (void) sprintf(initiator_wwnstr, "%016"PRIx64,
- wwid);
+ (void) sprintf(initiator_wwnstr, "w%016"PRIx64,
+ mpt->un.m_base_wwid);
if (ddi_prop_update_string(DDI_DEV_T_NONE, dip,
- "initiator-port", initiator_wwnstr) !=
+ SCSI_ADDR_PROP_INITIATOR_PORT, initiator_wwnstr) !=
DDI_PROP_SUCCESS) {
- (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "initiator-port");
+ (void) ddi_prop_remove(DDI_DEV_T_NONE,
+ dip, SCSI_ADDR_PROP_INITIATOR_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas Initiator port "
+ "prop update failed");
+ return (DDI_FAILURE);
+ }
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
+ MPTSAS_NUM_PHYS, numphys) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, MPTSAS_NUM_PHYS);
return (DDI_FAILURE);
}
@@ -788,6 +830,8 @@ mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
"phymask", phy_mask) !=
DDI_PROP_SUCCESS) {
(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "phymask");
+ mptsas_log(mpt, CE_WARN, "mptsas phy mask "
+ "prop update failed");
return (DDI_FAILURE);
}
@@ -795,8 +839,62 @@ mptsas_iport_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
"dynamic-port", dynamic_port) !=
DDI_PROP_SUCCESS) {
(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "dynamic-port");
+ mptsas_log(mpt, CE_WARN, "mptsas dynamic port "
+ "prop update failed");
+ return (DDI_FAILURE);
+ }
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
+ MPTSAS_VIRTUAL_PORT, 0) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, dip,
+ MPTSAS_VIRTUAL_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas virtual port "
+ "prop update failed");
+ return (DDI_FAILURE);
+ }
+ mptsas_smhba_set_phy_props(mpt,
+ iport, dip, numphys, &attached_devhdl);
+
+ mutex_enter(&mpt->m_mutex);
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)attached_devhdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address, &dev_hdl,
+ &attached_sas_wwn, &dev_info, &phy_port, &phy_id,
+ &pdev_hdl, &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "Failed to get device page0 for handle:%d",
+ attached_devhdl);
+ mutex_exit(&mpt->m_mutex);
+ return (DDI_FAILURE);
+ }
+
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ bzero(phymask, sizeof (phymask));
+ (void) sprintf(phymask, "%x", mpt->m_phy_info[i].phy_mask);
+ if (strcmp(phymask, iport) == 0) {
+ (void) sprintf(&mpt->m_phy_info[i].smhba_info.path[0],
+ "%x",
+ mpt->m_phy_info[i].phy_mask);
+ }
+ }
+ mutex_exit(&mpt->m_mutex);
+
+ bzero(attached_wwnstr, sizeof (attached_wwnstr));
+ (void) sprintf(attached_wwnstr, "w%016"PRIx64,
+ attached_sas_wwn);
+ if (ddi_prop_update_string(DDI_DEV_T_NONE, dip,
+ SCSI_ADDR_PROP_ATTACHED_PORT, attached_wwnstr) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE,
+ dip, SCSI_ADDR_PROP_ATTACHED_PORT);
return (DDI_FAILURE);
}
+
+ /* Create kstats for each phy on this iport */
+
+ mptsas_create_phy_stats(mpt, iport, dip);
+
/*
* register sas hba iport with mdi (MPxIO/vhci)
*/
@@ -830,12 +928,17 @@ mptsas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
char event_taskq_create = 0;
char dr_taskq_create = 0;
char doneq_thread_create = 0;
+ char chiprev, hw_rev[24];
+ char serial_number[72];
scsi_hba_tran_t *hba_tran;
int intr_types;
uint_t mem_bar = MEM_SPACE;
mptsas_phymask_t mask = 0x0;
int tran_flags = 0;
int rval = DDI_FAILURE;
+ int sm_hba = 1;
+ int num_phys = 0;
+ int protocol = 0;
/* CONSTCOND */
ASSERT(NO_COMPETING_THREADS);
@@ -1131,6 +1234,12 @@ intr_done:
DDI_INTR_PRI(mpt->m_intr_pri));
mutex_init(&mpt->m_tx_waitq_mutex, NULL, MUTEX_DRIVER,
DDI_INTR_PRI(mpt->m_intr_pri));
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ mutex_init(&mpt->m_phy_info[i].smhba_info.phy_mutex,
+ NULL, MUTEX_DRIVER,
+ DDI_INTR_PRI(mpt->m_intr_pri));
+ }
+
cv_init(&mpt->m_cv, NULL, CV_DRIVER, NULL);
cv_init(&mpt->m_passthru_cv, NULL, CV_DRIVER, NULL);
cv_init(&mpt->m_fw_cv, NULL, CV_DRIVER, NULL);
@@ -1178,6 +1287,7 @@ intr_done:
mptsas_log(mpt, CE_WARN, "mptsas chip initialization failed");
goto fail;
}
+
mutex_exit(&mpt->m_mutex);
/*
@@ -1267,10 +1377,12 @@ intr_done:
mutex_enter(&mpt->m_mutex);
}
mutex_exit(&mpt->m_mutex);
+
/*
* register a virtual port for RAID volume always
*/
(void) scsi_hba_iport_register(dip, "v0");
+
/*
* All children of the HBA are iports. We need tran was cloned.
* So we pass the flags to SCSA. SCSI_HBA_TRAN_CLONE will be
@@ -1365,6 +1477,17 @@ intr_done:
mutex_exit(&mpt->m_mutex);
goto fail;
}
+
+ /*
+ * Initialize PHY info for smhba
+ */
+ if (mptsas_smhba_phy_init(mpt)) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas phy initialization "
+ "failed");
+ goto fail;
+ }
+
mutex_exit(&mpt->m_mutex);
@@ -1430,6 +1553,50 @@ intr_done:
/* Print message of HBA present */
ddi_report_dev(dip);
+ /* SM-HBA support */
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_INT32, MPTSAS_SMHBA_SUPPORTED,
+ &sm_hba);
+
+ /* SM-HBA driver version */
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_STRING, MPTSAS_DRV_VERSION,
+ mptsas_driver_rev);
+
+ /* SM-HBA hardware version */
+ chiprev = 'A' + mpt->m_revid;
+ (void) snprintf(hw_rev, 2, "%s", &chiprev);
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_STRING, MPTSAS_HWARE_VERSION,
+ hw_rev);
+
+ /* SM-HBA phy number per HBA */
+ num_phys = mpt->m_num_phys;
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_INT32, MPTSAS_NUM_PHYS_HBA,
+ &num_phys);
+
+ /* SM-HBA protocal support */
+ protocol = SAS_SSP_SUPPORT | SAS_SATA_SUPPORT | SAS_SMP_SUPPORT;
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_INT32,
+ MPTSAS_SUPPORTED_PROTOCOL, &protocol);
+
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_STRING, MPTSAS_MANUFACTURER,
+ mpt->m_MANU_page0.ChipName);
+
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_STRING, MPTSAS_MODEL_NAME,
+ mpt->m_MANU_page0.BoardName);
+
+ /*
+ * VPD data is not available, we make a serial number for this.
+ */
+
+ (void) sprintf(serial_number, "%s%s%s%s%s",
+ mpt->m_MANU_page0.ChipName,
+ mpt->m_MANU_page0.ChipRevision,
+ mpt->m_MANU_page0.BoardName,
+ mpt->m_MANU_page0.BoardAssembly,
+ mpt->m_MANU_page0.BoardTracerNumber);
+
+ mptsas_smhba_add_hba_prop(mpt, DATA_TYPE_STRING, MPTSAS_SERIAL_NUMBER,
+ &serial_number[0]);
+
/* report idle status to pm framework */
if (mpt->m_options & MPTSAS_OPT_PM) {
(void) pm_idle_component(dip, 0);
@@ -1503,6 +1670,10 @@ fail:
if (mutex_init_done) {
mutex_destroy(&mpt->m_tx_waitq_mutex);
mutex_destroy(&mpt->m_mutex);
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ mutex_destroy(
+ &mpt->m_phy_info[i].smhba_info.phy_mutex);
+ }
cv_destroy(&mpt->m_cv);
cv_destroy(&mpt->m_passthru_cv);
cv_destroy(&mpt->m_fw_cv);
@@ -1928,6 +2099,11 @@ mptsas_do_detach(dev_info_t *dip)
mutex_exit(&mptsas_global_mutex);
/*
+ * Delete Phy stats
+ */
+ mptsas_destroy_phy_stats(mpt);
+
+ /*
* Delete nt_active.
*/
active = mpt->m_active;
@@ -1962,6 +2138,9 @@ mptsas_do_detach(dev_info_t *dip)
mutex_destroy(&mpt->m_tx_waitq_mutex);
mutex_destroy(&mpt->m_mutex);
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ mutex_destroy(&mpt->m_phy_info[i].smhba_info.phy_mutex);
+ }
cv_destroy(&mpt->m_cv);
cv_destroy(&mpt->m_passthru_cv);
cv_destroy(&mpt->m_fw_cv);
@@ -2749,19 +2928,20 @@ mptsas_name_child(dev_info_t *lun_dip, char *name, int len)
lun = ddi_prop_get_int(DDI_DEV_T_ANY, lun_dip, DDI_PROP_DONTPASS,
LUN_PROP, 0);
- if (ddi_prop_lookup_string(DDI_DEV_T_ANY, lun_dip, DDI_PROP_DONTPASS,
- SCSI_ADDR_PROP_TARGET_PORT, &sas_wwn) == DDI_PROP_SUCCESS) {
- /*
- * Stick in the address of the form "wWWN,LUN"
- */
- reallen = snprintf(name, len, "w%s,%x", sas_wwn, lun);
- ddi_prop_free(sas_wwn);
- } else if ((phynum = ddi_prop_get_int(DDI_DEV_T_ANY, lun_dip,
+ if ((phynum = ddi_prop_get_int(DDI_DEV_T_ANY, lun_dip,
DDI_PROP_DONTPASS, "sata-phy", -1)) != -1) {
/*
* Stick in the address of form "pPHY,LUN"
*/
reallen = snprintf(name, len, "p%x,%x", phynum, lun);
+ } else if (ddi_prop_lookup_string(DDI_DEV_T_ANY, lun_dip,
+ DDI_PROP_DONTPASS, SCSI_ADDR_PROP_TARGET_PORT, &sas_wwn)
+ == DDI_PROP_SUCCESS) {
+ /*
+ * Stick in the address of the form "wWWN,LUN"
+ */
+ reallen = snprintf(name, len, "%s,%x", sas_wwn, lun);
+ ddi_prop_free(sas_wwn);
} else {
return (DDI_FAILURE);
}
@@ -5837,6 +6017,7 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
mptsas_smp_t *psmp = NULL;
mptsas_t *mpt = (void *)topo_node->mpt;
uint16_t devhdl;
+ uint16_t attached_devhdl;
uint64_t sas_wwn = 0;
int rval = 0;
uint32_t page_address;
@@ -5844,6 +6025,7 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
char *addr = NULL;
dev_info_t *lundip;
int circ = 0, circ1 = 0;
+ char attached_wwnstr[MPTSAS_WWN_STRLEN];
NDBG20(("mptsas%d handle_topo_change enter", mpt->m_instance));
@@ -5942,6 +6124,61 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
ndi_devi_exit(parent, circ1);
ndi_devi_exit(scsi_vhci_dip, circ);
+ /*
+ * Add parent's props for SMHBA support
+ */
+ if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) {
+ bzero(attached_wwnstr,
+ sizeof (attached_wwnstr));
+ (void) sprintf(attached_wwnstr, "w%016"PRIx64,
+ ptgt->m_sas_wwn);
+ if (ddi_prop_update_string(DDI_DEV_T_NONE,
+ parent,
+ SCSI_ADDR_PROP_ATTACHED_PORT,
+ attached_wwnstr)
+ != DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE,
+ parent,
+ SCSI_ADDR_PROP_ATTACHED_PORT);
+ mptsas_log(mpt, CE_WARN, "Failed to"
+ "attached-port props");
+ return;
+ }
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+ MPTSAS_NUM_PHYS, 1) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE,
+ parent, MPTSAS_NUM_PHYS);
+ mptsas_log(mpt, CE_WARN, "Failed to"
+ " create num-phys props");
+ return;
+ }
+
+ /*
+ * Update PHY info for smhba
+ */
+ mutex_enter(&mpt->m_mutex);
+ if (mptsas_smhba_phy_init(mpt)) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas phy"
+ " update failed");
+ return;
+ }
+ mutex_exit(&mpt->m_mutex);
+ mptsas_smhba_set_phy_props(mpt,
+ ddi_get_name_addr(parent), parent,
+ 1, &attached_devhdl);
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+ MPTSAS_VIRTUAL_PORT, 0) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE,
+ parent, MPTSAS_VIRTUAL_PORT);
+ mptsas_log(mpt, CE_WARN,
+ "mptsas virtual-port"
+ "port prop update failed");
+ return;
+ }
+ }
}
mutex_enter(&mpt->m_mutex);
@@ -6003,6 +6240,41 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
kmem_free(addr, SCSI_MAXNAMELEN);
+ /*
+ * Clear parent's props for SMHBA support
+ */
+ flags = topo_node->flags;
+ if (flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) {
+ bzero(attached_wwnstr, sizeof (attached_wwnstr));
+ if (ddi_prop_update_string(DDI_DEV_T_NONE, parent,
+ SCSI_ADDR_PROP_ATTACHED_PORT, attached_wwnstr) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+ SCSI_ADDR_PROP_ATTACHED_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas attached port "
+ "prop update failed");
+ break;
+ }
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+ MPTSAS_NUM_PHYS, 0) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+ MPTSAS_NUM_PHYS);
+ mptsas_log(mpt, CE_WARN, "mptsas num phys "
+ "prop update failed");
+ break;
+ }
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+ MPTSAS_VIRTUAL_PORT, 1) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+ MPTSAS_VIRTUAL_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas virtual port "
+ "prop update failed");
+ break;
+ }
+ }
+
mutex_enter(&mpt->m_mutex);
if (rval == DDI_SUCCESS) {
mptsas_tgt_free(&mpt->m_active->m_tgttbl,
@@ -6024,7 +6296,6 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
/*
* Send SAS IO Unit Control to free the dev handle
*/
- flags = topo_node->flags;
if ((flags == MPTSAS_TOPO_FLAG_DIRECT_ATTACHED_DEVICE) ||
(flags == MPTSAS_TOPO_FLAG_EXPANDER_ATTACHED_DEVICE)) {
rval = mptsas_free_devhdl(mpt, devhdl);
@@ -6033,6 +6304,7 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
"devhdl:%x, rval:%x", mpt->m_instance, devhdl,
rval));
}
+
break;
}
case MPTSAS_TOPO_FLAG_REMOVE_HANDLE:
@@ -6085,6 +6357,7 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
ndi_devi_enter(parent, &circ1);
(void) mptsas_online_smp(parent, psmp, &smpdip);
ndi_devi_exit(parent, circ1);
+
mutex_enter(&mpt->m_mutex);
break;
}
@@ -6092,6 +6365,8 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
{
mptsas_hash_table_t *smptbl = &mpt->m_active->m_smptbl;
devhdl = topo_node->devhdl;
+ uint32_t dev_info;
+
psmp = mptsas_search_by_devhdl(smptbl, devhdl);
if (psmp == NULL)
break;
@@ -6100,9 +6375,50 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
* successfully.
*/
mutex_exit(&mpt->m_mutex);
+
ndi_devi_enter(parent, &circ1);
rval = mptsas_offline_smp(parent, psmp, NDI_DEVI_REMOVE);
ndi_devi_exit(parent, circ1);
+
+ dev_info = psmp->m_deviceinfo;
+ if ((dev_info & DEVINFO_DIRECT_ATTACHED) ==
+ DEVINFO_DIRECT_ATTACHED) {
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+ MPTSAS_VIRTUAL_PORT, 1) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+ MPTSAS_VIRTUAL_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas virtual port "
+ "prop update failed");
+ return;
+ }
+ /*
+ * Check whether the smp connected to the iport,
+ */
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, parent,
+ MPTSAS_NUM_PHYS, 0) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+ MPTSAS_NUM_PHYS);
+ mptsas_log(mpt, CE_WARN, "mptsas num phys"
+ "prop update failed");
+ return;
+ }
+ /*
+ * Clear parent's attached-port props
+ */
+ bzero(attached_wwnstr, sizeof (attached_wwnstr));
+ if (ddi_prop_update_string(DDI_DEV_T_NONE, parent,
+ SCSI_ADDR_PROP_ATTACHED_PORT, attached_wwnstr) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, parent,
+ SCSI_ADDR_PROP_ATTACHED_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas attached port "
+ "prop update failed");
+ return;
+ }
+ }
+
mutex_enter(&mpt->m_mutex);
NDBG20(("mptsas%d handle_topo_change to remove devhdl:%x, "
"rval:%x", mpt->m_instance, psmp->m_devhdl, rval));
@@ -6112,6 +6428,9 @@ mptsas_handle_topo_change(mptsas_topo_change_list_t *topo_node,
} else {
psmp->m_devhdl = MPTSAS_INVALID_DEVHDL;
}
+
+ bzero(attached_wwnstr, sizeof (attached_wwnstr));
+
break;
}
default:
@@ -6266,6 +6585,7 @@ mptsas_handle_event_sync(void *args)
mptsas_smp_t *psmp;
mptsas_hash_table_t *tgttbl, *smptbl;
uint8_t flags = 0, exp_flag;
+ smhba_info_t *pSmhba = NULL;
NDBG20(("mptsas_handle_event_sync: SAS topology change"));
@@ -6542,7 +6862,6 @@ mptsas_handle_event_sync(void *args)
topo_tail->next = topo_node;
topo_tail = topo_node;
}
-
break;
}
case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
@@ -6551,13 +6870,26 @@ mptsas_handle_event_sync(void *args)
state = (link_rate &
MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK) >>
MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT;
+ pSmhba = &mpt->m_phy_info[i].smhba_info;
+ pSmhba->negotiated_link_rate = state;
switch (state) {
case MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED:
(void) sprintf(curr, "is disabled");
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_PHY_EVENT,
+ SAS_PHY_REMOVE,
+ &mpt->m_phy_info[i].smhba_info);
+ mpt->m_phy_info[i].smhba_info.
+ negotiated_link_rate
+ = 0x1;
break;
case MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED:
(void) sprintf(curr, "is offline, "
"failed speed negotiation");
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_PHY_EVENT,
+ SAS_PHY_OFFLINE,
+ &mpt->m_phy_info[i].smhba_info);
break;
case MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE:
(void) sprintf(curr, "SATA OOB "
@@ -6574,6 +6906,10 @@ mptsas_handle_event_sync(void *args)
(enc_handle == 1)) {
mpt->m_port_chng = 1;
}
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_PHY_EVENT,
+ SAS_PHY_ONLINE,
+ &mpt->m_phy_info[i].smhba_info);
break;
case MPI2_EVENT_SAS_TOPO_LR_RATE_3_0:
(void) sprintf(curr, "is online at 3.0 "
@@ -6582,6 +6918,10 @@ mptsas_handle_event_sync(void *args)
(enc_handle == 1)) {
mpt->m_port_chng = 1;
}
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_PHY_EVENT,
+ SAS_PHY_ONLINE,
+ &mpt->m_phy_info[i].smhba_info);
break;
case MPI2_EVENT_SAS_TOPO_LR_RATE_6_0:
(void) sprintf(curr, "is online at "
@@ -6590,6 +6930,10 @@ mptsas_handle_event_sync(void *args)
(enc_handle == 1)) {
mpt->m_port_chng = 1;
}
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_PHY_EVENT,
+ SAS_PHY_ONLINE,
+ &mpt->m_phy_info[i].smhba_info);
break;
default:
(void) sprintf(curr, "state is "
@@ -7112,6 +7456,80 @@ mptsas_handle_event(void *args)
mpt->m_instance, reason_str, handle, percent));
break;
}
+ case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
+ {
+ pMpi2EventDataSasBroadcastPrimitive_t sas_broadcast;
+ uint8_t phy_num;
+ uint8_t primitive;
+
+ sas_broadcast = (pMpi2EventDataSasBroadcastPrimitive_t)
+ eventreply->EventData;
+
+ phy_num = ddi_get8(mpt->m_acc_reply_frame_hdl,
+ &sas_broadcast->PhyNum);
+ primitive = ddi_get8(mpt->m_acc_reply_frame_hdl,
+ &sas_broadcast->Primitive);
+
+ switch (primitive) {
+ case MPI2_EVENT_PRIMITIVE_CHANGE:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_CHANGE,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_SES:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_SES,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_EXPANDER:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_D01_4,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_D04_7,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_RESERVED3:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_D16_7,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_RESERVED4:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_D29_7,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_D24_0,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ case MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED:
+ mptsas_smhba_log_sysevent(mpt,
+ ESC_SAS_HBA_PORT_BROADCAST,
+ SAS_PORT_BROADCAST_D27_4,
+ &mpt->m_phy_info[phy_num].smhba_info);
+ break;
+ default:
+ NDBG20(("mptsas%d: unknown BROADCAST PRIMITIVE"
+ " %x received",
+ mpt->m_instance, primitive));
+ break;
+ }
+ NDBG20(("mptsas%d sas broadcast primitive: "
+ "\tprimitive(0x%04x), phy(%d) complete\n",
+ mpt->m_instance, primitive, phy_num));
+ break;
+ }
case MPI2_EVENT_IR_VOLUME:
{
Mpi2EventDataIrVolume_t *irVolume;
@@ -11609,6 +12027,12 @@ mptsas_init_chip(mptsas_t *mpt, int first_time)
"mptsas_get_sas_io_unit_page_hndshk failed!");
goto fail;
}
+
+ if (mptsas_get_manufacture_page0(mpt) == DDI_FAILURE) {
+ mptsas_log(mpt, CE_WARN,
+ "mptsas_get_manufacture_page0 failed!");
+ goto fail;
+ }
}
/*
@@ -12023,13 +12447,15 @@ mptsas_get_target_device_info(mptsas_t *mpt, uint32_t page_address,
uint8_t physport, phynum, config, disk;
mptsas_slots_t *slots = mpt->m_active;
uint64_t devicename;
+ uint16_t pdev_hdl;
mptsas_target_t *tmp_tgt = NULL;
uint16_t bay_num, enclosure;
ASSERT(*pptgt == NULL);
rval = mptsas_get_sas_device_page0(mpt, page_address, dev_handle,
- &sas_wwn, &dev_info, &physport, &phynum, &bay_num, &enclosure);
+ &sas_wwn, &dev_info, &physport, &phynum, &pdev_hdl,
+ &bay_num, &enclosure);
if (rval != DDI_SUCCESS) {
rval = DEV_INFO_FAIL_PAGE0;
return (rval);
@@ -12359,7 +12785,6 @@ mptsas_bus_config(dev_info_t *pdip, uint_t flag,
if (!mpt) {
return (DDI_FAILURE);
}
-
/*
* Hold the nexus across the bus_config
*/
@@ -13451,6 +13876,7 @@ create_lun:
if (rval != DDI_SUCCESS) {
rval = mptsas_create_phys_lun(pdip, sd_inq, guid, lun_dip,
ptgt, lun);
+
}
out:
if (guid != NULL) {
@@ -13478,10 +13904,23 @@ mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
mptsas_t *mpt = DIP2MPT(pdip);
char *lun_addr = NULL;
char *wwn_str = NULL;
+ char *attached_wwn_str = NULL;
char *component = NULL;
uint8_t phy = 0xFF;
uint64_t sas_wwn;
+ int64_t lun64 = 0;
uint32_t devinfo;
+ uint16_t dev_hdl;
+ uint16_t pdev_hdl;
+ uint64_t dev_sas_wwn;
+ uint64_t pdev_sas_wwn;
+ uint32_t pdev_info;
+ uint8_t physport;
+ uint8_t phy_id;
+ uint32_t page_address;
+ uint16_t bay_num, enclosure;
+ char pdev_wwn_str[MPTSAS_WWN_STRLEN];
+ uint32_t dev_info;
mutex_enter(&mpt->m_mutex);
target = ptgt->m_devhdl;
@@ -13583,10 +14022,13 @@ mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
(void) sprintf(wwn_str, "%016"PRIx64, sas_wwn);
lun_addr = kmem_zalloc(SCSI_MAXNAMELEN, KM_SLEEP);
- if (sas_wwn)
+ if (guid) {
(void) sprintf(lun_addr, "w%s,%x", wwn_str, lun);
- else
+ (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
+ } else {
(void) sprintf(lun_addr, "p%x,%x", phy, lun);
+ (void) sprintf(wwn_str, "p%x", phy);
+ }
mdi_rtn = mdi_pi_alloc_compatible(pdip, nodename,
guid, lun_addr, compatible, ncompatible,
@@ -13596,7 +14038,7 @@ mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
if (mdi_prop_update_string(*pip, MDI_GUID,
guid) != DDI_SUCCESS) {
mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
- "create property for target %d lun %d (MDI_GUID)",
+ "create prop for target %d lun %d (MDI_GUID)",
target, lun);
mdi_rtn = MDI_FAILURE;
goto virt_create_done;
@@ -13605,16 +14047,25 @@ mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
if (mdi_prop_update_int(*pip, LUN_PROP,
lun) != DDI_SUCCESS) {
mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
- "create property for target %d lun %d (LUN_PROP)",
+ "create prop for target %d lun %d (LUN_PROP)",
target, lun);
mdi_rtn = MDI_FAILURE;
goto virt_create_done;
}
+ lun64 = (int64_t)lun;
+ if (mdi_prop_update_int64(*pip, LUN64_PROP,
+ lun64) != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
+ "create prop for target %d (LUN64_PROP)",
+ target);
+ mdi_rtn = MDI_FAILURE;
+ goto virt_create_done;
+ }
if (mdi_prop_update_string_array(*pip, "compatible",
compatible, ncompatible) !=
DDI_PROP_SUCCESS) {
mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
- "create property for target %d lun %d (COMPATIBLE)",
+ "create prop for target %d lun %d (COMPATIBLE)",
target, lun);
mdi_rtn = MDI_FAILURE;
goto virt_create_done;
@@ -13622,7 +14073,7 @@ mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
if (sas_wwn && (mdi_prop_update_string(*pip,
SCSI_ADDR_PROP_TARGET_PORT, wwn_str) != DDI_PROP_SUCCESS)) {
mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
- "create property for target %d lun %d "
+ "create prop for target %d lun %d "
"(target-port)", target, lun);
mdi_rtn = MDI_FAILURE;
goto virt_create_done;
@@ -13632,12 +14083,86 @@ mptsas_create_virt_lun(dev_info_t *pdip, struct scsi_inquiry *inq, char *guid,
* Direct attached SATA device without DeviceName
*/
mptsas_log(mpt, CE_WARN, "mptsas driver unable to "
- "create property for SAS target %d lun %d "
+ "create prop for SAS target %d lun %d "
"(sata-phy)", target, lun);
- mdi_rtn = NDI_FAILURE;
+ mdi_rtn = MDI_FAILURE;
+ goto virt_create_done;
+ }
+ mutex_enter(&mpt->m_mutex);
+
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
+ (uint32_t)ptgt->m_devhdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address,
+ &dev_hdl, &dev_sas_wwn, &dev_info, &physport,
+ &phy_id, &pdev_hdl, &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas unable to get "
+ "parent device for handle %d", page_address);
+ mdi_rtn = MDI_FAILURE;
goto virt_create_done;
}
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address,
+ &dev_hdl, &pdev_sas_wwn, &pdev_info, &physport,
+ &phy_id, &pdev_hdl, &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas unable to get"
+ "device info for handle %d", page_address);
+ mdi_rtn = MDI_FAILURE;
+ goto virt_create_done;
+ }
+
+ mutex_exit(&mpt->m_mutex);
+
+ /*
+ * If this device direct attached to the controller
+ * set the attached-port to the base wwid
+ */
+ if ((ptgt->m_deviceinfo & DEVINFO_DIRECT_ATTACHED)
+ != DEVINFO_DIRECT_ATTACHED) {
+ (void) sprintf(pdev_wwn_str, "w%016"PRIx64,
+ pdev_sas_wwn);
+ } else {
+ /*
+ * Update the iport's attached-port to guid
+ */
+ if (sas_wwn == 0) {
+ (void) sprintf(wwn_str, "p%x", phy);
+ } else {
+ (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
+ }
+ if (ddi_prop_update_string(DDI_DEV_T_NONE,
+ pdip, SCSI_ADDR_PROP_ATTACHED_PORT, wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "mptsas unable to create "
+ "property for iport target-port"
+ " %s (sas_wwn)",
+ wwn_str);
+ mdi_rtn = MDI_FAILURE;
+ goto virt_create_done;
+ }
+
+ (void) sprintf(pdev_wwn_str, "w%016"PRIx64,
+ mpt->un.m_base_wwid);
+ }
+
+ if (mdi_prop_update_string(*pip,
+ SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+ "property for iport attached-port %s (sas_wwn)",
+ attached_wwn_str);
+ mdi_rtn = MDI_FAILURE;
+ goto virt_create_done;
+ }
+
+
if (inq->inq_dtype == 0) {
component = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
/*
@@ -13710,6 +14235,7 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
char *guid, dev_info_t **lun_dip, mptsas_target_t *ptgt, int lun)
{
int target;
+ int rval;
int ndi_rtn = NDI_FAILURE;
uint64_t be_sas_wwn;
char *nodename = NULL;
@@ -13719,9 +14245,22 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
mptsas_t *mpt = DIP2MPT(pdip);
char *wwn_str = NULL;
char *component = NULL;
+ char *attached_wwn_str = NULL;
uint8_t phy = 0xFF;
uint64_t sas_wwn;
uint32_t devinfo;
+ uint16_t dev_hdl;
+ uint16_t pdev_hdl;
+ uint64_t pdev_sas_wwn;
+ uint64_t dev_sas_wwn;
+ uint32_t pdev_info;
+ uint8_t physport;
+ uint8_t phy_id;
+ uint32_t page_address;
+ uint16_t bay_num, enclosure;
+ char pdev_wwn_str[MPTSAS_WWN_STRLEN];
+ uint32_t dev_info;
+ int64_t lun64 = 0;
mutex_enter(&mpt->m_mutex);
target = ptgt->m_devhdl;
@@ -13763,6 +14302,16 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
goto phys_create_done;
}
+ lun64 = (int64_t)lun;
+ if (ndi_prop_update_int64(DDI_DEV_T_NONE,
+ *lun_dip, LUN64_PROP, lun64) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+ "property for target %d lun64 %d (LUN64_PROP)",
+ target, lun);
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
if (ndi_prop_update_string_array(DDI_DEV_T_NONE,
*lun_dip, "compatible", compatible, ncompatible)
!= DDI_PROP_SUCCESS) {
@@ -13780,7 +14329,7 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
* a WWN (e.g. parallel SCSI), don't create the prop.
*/
wwn_str = kmem_zalloc(MPTSAS_WWN_STRLEN, KM_SLEEP);
- (void) sprintf(wwn_str, "%016"PRIx64, sas_wwn);
+ (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
if (sas_wwn && ndi_prop_update_string(DDI_DEV_T_NONE,
*lun_dip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str)
!= DDI_PROP_SUCCESS) {
@@ -13790,6 +14339,7 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
ndi_rtn = NDI_FAILURE;
goto phys_create_done;
}
+
be_sas_wwn = BE_64(sas_wwn);
if (sas_wwn && ndi_prop_update_byte_array(
DDI_DEV_T_NONE, *lun_dip, "port-wwn",
@@ -13811,6 +14361,7 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
ndi_rtn = NDI_FAILURE;
goto phys_create_done;
}
+
if (ndi_prop_create_boolean(DDI_DEV_T_NONE,
*lun_dip, SAS_PROP) != DDI_PROP_SUCCESS) {
mptsas_log(mpt, CE_WARN, "mptsas unable to"
@@ -13828,6 +14379,106 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
goto phys_create_done;
}
+ mutex_enter(&mpt->m_mutex);
+
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
+ (uint32_t)ptgt->m_devhdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address,
+ &dev_hdl, &dev_sas_wwn, &dev_info,
+ &physport, &phy_id, &pdev_hdl,
+ &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas unable to get"
+ "parent device for handle %d.", page_address);
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
+
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) | (uint32_t)pdev_hdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address,
+ &dev_hdl, &pdev_sas_wwn, &pdev_info,
+ &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+ "device for handle %d.", page_address);
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
+
+ mutex_exit(&mpt->m_mutex);
+
+ /*
+ * If this device direct attached to the controller
+ * set the attached-port to the base wwid
+ */
+ if ((ptgt->m_deviceinfo & DEVINFO_DIRECT_ATTACHED)
+ != DEVINFO_DIRECT_ATTACHED) {
+ (void) sprintf(pdev_wwn_str, "w%016"PRIx64,
+ pdev_sas_wwn);
+ } else {
+ /*
+ * Update the iport's attached-port to guid
+ */
+ if (sas_wwn == 0) {
+ (void) sprintf(wwn_str, "p%x", phy);
+ } else {
+ (void) sprintf(wwn_str, "w%016"PRIx64, sas_wwn);
+ }
+ if (ddi_prop_update_string(DDI_DEV_T_NONE,
+ pdip, SCSI_ADDR_PROP_ATTACHED_PORT, wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "mptsas unable to create "
+ "property for iport target-port"
+ " %s (sas_wwn)",
+ wwn_str);
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
+
+ (void) sprintf(pdev_wwn_str, "w%016"PRIx64,
+ mpt->un.m_base_wwid);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE,
+ *lun_dip, SCSI_ADDR_PROP_ATTACHED_PORT, pdev_wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "mptsas unable to create "
+ "property for iport attached-port %s (sas_wwn)",
+ attached_wwn_str);
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
+
+ if (IS_ATAPI_DEVICE(dev_info)) {
+ if (ndi_prop_update_string(DDI_DEV_T_NONE,
+ *lun_dip, MPTSAS_VARIANT, "atapi") !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "mptsas unable to create "
+ "property for device variant ");
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
+ }
+
+ if (IS_SATA_DEVICE(dev_info)) {
+ if (ndi_prop_update_string(DDI_DEV_T_NONE,
+ *lun_dip, MPTSAS_VARIANT, "sata") !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "mptsas unable to create "
+ "property for device variant ");
+ ndi_rtn = NDI_FAILURE;
+ goto phys_create_done;
+ }
+ }
+
/*
* if this is a SAS controller, and the target is a SATA
* drive, set the 'pm-capable' property for sd and if on
@@ -13856,8 +14507,10 @@ mptsas_create_phys_lun(dev_info_t *pdip, struct scsi_inquiry *inq,
/*
* add 'obp-path' properties for devinfo
*/
+ bzero(wwn_str, sizeof (wwn_str));
+ (void) sprintf(wwn_str, "%016"PRIx64, sas_wwn);
component = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
- if (sas_wwn) {
+ if (guid) {
(void) snprintf(component, MAXPATHLEN,
"disk@w%s,%x", wwn_str, lun);
} else {
@@ -13915,6 +14568,7 @@ phys_create_done:
kmem_free(component, MAXPATHLEN);
}
+
return ((ndi_rtn == NDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
}
@@ -13967,8 +14621,25 @@ mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
dev_info_t **smp_dip)
{
char wwn_str[MPTSAS_WWN_STRLEN];
+ char attached_wwn_str[MPTSAS_WWN_STRLEN];
int ndi_rtn = NDI_FAILURE;
+ int rval = 0;
+ mptsas_smp_t dev_info;
+ uint32_t page_address;
mptsas_t *mpt = DIP2MPT(pdip);
+ uint16_t dev_hdl;
+ uint64_t sas_wwn;
+ uint64_t smp_sas_wwn;
+ uint8_t physport;
+ uint8_t phy_id;
+ uint16_t pdev_hdl;
+ uint8_t numphys = 0;
+ uint16_t i = 0;
+ char phymask[MPTSAS_MAX_PHYS];
+ char *iport = NULL;
+ mptsas_phymask_t phy_mask = 0;
+ uint16_t attached_devhdl;
+ uint16_t bay_num, enclosure;
(void) sprintf(wwn_str, "%"PRIx64, smp_node->m_sasaddr);
@@ -14004,6 +14675,84 @@ mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
ndi_rtn = NDI_FAILURE;
goto smp_create_done;
}
+ (void) sprintf(wwn_str, "w%"PRIx64, smp_node->m_sasaddr);
+ if (ndi_prop_update_string(DDI_DEV_T_NONE,
+ *smp_dip, SCSI_ADDR_PROP_TARGET_PORT, wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+ "property for iport target-port %s (sas_wwn)",
+ wwn_str);
+ ndi_rtn = NDI_FAILURE;
+ goto smp_create_done;
+ }
+
+ mutex_enter(&mpt->m_mutex);
+
+ page_address = (MPI2_SAS_EXPAND_PGAD_FORM_HNDL &
+ MPI2_SAS_EXPAND_PGAD_FORM_MASK) | smp_node->m_devhdl;
+ rval = mptsas_get_sas_expander_page0(mpt, page_address,
+ &dev_info);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN,
+ "mptsas unable to get expander "
+ "parent device info for %x", page_address);
+ ndi_rtn = NDI_FAILURE;
+ goto smp_create_done;
+ }
+
+ smp_node->m_pdevhdl = dev_info.m_pdevhdl;
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
+ (uint32_t)dev_info.m_pdevhdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address,
+ &dev_hdl, &sas_wwn, &smp_node->m_pdevinfo,
+ &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas unable to get "
+ "device info for %x", page_address);
+ ndi_rtn = NDI_FAILURE;
+ goto smp_create_done;
+ }
+
+ page_address = (MPI2_SAS_DEVICE_PGAD_FORM_HANDLE &
+ MPI2_SAS_DEVICE_PGAD_FORM_MASK) |
+ (uint32_t)dev_info.m_devhdl;
+ rval = mptsas_get_sas_device_page0(mpt, page_address,
+ &dev_hdl, &smp_sas_wwn, &smp_node->m_deviceinfo,
+ &physport, &phy_id, &pdev_hdl, &bay_num, &enclosure);
+ if (rval != DDI_SUCCESS) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas unable to get "
+ "device info for %x", page_address);
+ ndi_rtn = NDI_FAILURE;
+ goto smp_create_done;
+ }
+ mutex_exit(&mpt->m_mutex);
+
+ /*
+ * If this smp direct attached to the controller
+ * set the attached-port to the base wwid
+ */
+ if ((smp_node->m_deviceinfo & DEVINFO_DIRECT_ATTACHED)
+ != DEVINFO_DIRECT_ATTACHED) {
+ (void) sprintf(attached_wwn_str, "w%016"PRIx64,
+ sas_wwn);
+ } else {
+ (void) sprintf(attached_wwn_str, "w%016"PRIx64,
+ mpt->un.m_base_wwid);
+ }
+
+ if (ndi_prop_update_string(DDI_DEV_T_NONE,
+ *smp_dip, SCSI_ADDR_PROP_ATTACHED_PORT, attached_wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ mptsas_log(mpt, CE_WARN, "mptsas unable to create "
+ "property for smp attached-port %s (sas_wwn)",
+ attached_wwn_str);
+ ndi_rtn = NDI_FAILURE;
+ goto smp_create_done;
+ }
if (ndi_prop_create_boolean(DDI_DEV_T_NONE,
*smp_dip, SMP_PROP) != DDI_PROP_SUCCESS) {
@@ -14014,6 +14763,87 @@ mptsas_online_smp(dev_info_t *pdip, mptsas_smp_t *smp_node,
goto smp_create_done;
}
+ /*
+ * check the smp to see whether it direct
+ * attached to the controller
+ */
+ if ((smp_node->m_deviceinfo & DEVINFO_DIRECT_ATTACHED)
+ != DEVINFO_DIRECT_ATTACHED) {
+ goto smp_create_done;
+ }
+ numphys = ddi_prop_get_int(DDI_DEV_T_ANY, pdip,
+ DDI_PROP_DONTPASS, MPTSAS_NUM_PHYS, -1);
+ if (numphys > 0) {
+ goto smp_create_done;
+ }
+ /*
+ * this iport is an old iport, we need to
+ * reconfig the props for it.
+ */
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, pdip,
+ MPTSAS_VIRTUAL_PORT, 0) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, pdip,
+ MPTSAS_VIRTUAL_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas virtual port "
+ "prop update failed");
+ goto smp_create_done;
+ }
+
+ mutex_enter(&mpt->m_mutex);
+ numphys = 0;
+ iport = ddi_get_name_addr(pdip);
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ bzero(phymask, sizeof (phymask));
+ (void) sprintf(phymask,
+ "%x", mpt->m_phy_info[i].phy_mask);
+ if (strcmp(phymask, iport) == 0) {
+ phy_mask = mpt->m_phy_info[i].phy_mask;
+ break;
+ }
+ }
+
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ if ((phy_mask >> i) & 0x01) {
+ numphys++;
+ }
+ }
+ /*
+ * Update PHY info for smhba
+ */
+ if (mptsas_smhba_phy_init(mpt)) {
+ mutex_exit(&mpt->m_mutex);
+ mptsas_log(mpt, CE_WARN, "mptsas phy update "
+ "failed");
+ goto smp_create_done;
+ }
+ mutex_exit(&mpt->m_mutex);
+
+ mptsas_smhba_set_phy_props(mpt, iport, pdip,
+ numphys, &attached_devhdl);
+
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, pdip,
+ MPTSAS_NUM_PHYS, numphys) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, pdip,
+ MPTSAS_NUM_PHYS);
+ mptsas_log(mpt, CE_WARN, "mptsas update "
+ "num phys props failed");
+ goto smp_create_done;
+ }
+ /*
+ * Add parent's props for SMHBA support
+ */
+ if (ddi_prop_update_string(DDI_DEV_T_NONE, pdip,
+ SCSI_ADDR_PROP_ATTACHED_PORT, wwn_str) !=
+ DDI_PROP_SUCCESS) {
+ (void) ddi_prop_remove(DDI_DEV_T_NONE, pdip,
+ SCSI_ADDR_PROP_ATTACHED_PORT);
+ mptsas_log(mpt, CE_WARN, "mptsas update iport"
+ "attached-port failed");
+ goto smp_create_done;
+ }
+
smp_create_done:
/*
* If props were setup ok, online the lun
diff --git a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
index 270c50393b..24b16ab450 100644
--- a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c
@@ -80,6 +80,7 @@
* private header files.
*/
#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
/*
* FMA header files.
@@ -1395,6 +1396,7 @@ mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
uint64_t *sas_wwn;
uint32_t *dev_info;
uint8_t *physport, *phynum;
+ uint16_t *pdevhdl;
uint32_t page_address;
if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
@@ -1425,9 +1427,11 @@ mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
dev_info = va_arg(ap, uint32_t *);
physport = va_arg(ap, uint8_t *);
phynum = va_arg(ap, uint8_t *);
+ pdevhdl = va_arg(ap, uint16_t *);
bay_num = va_arg(ap, uint16_t *);
enclosure = va_arg(ap, uint16_t *);
+
sasdevpage = (pMpi2SasDevicePage0_t)page_memp;
*dev_info = ddi_get32(accessp, &sasdevpage->DeviceInfo);
@@ -1440,6 +1444,7 @@ mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
*sas_wwn = LE_64(*sas_wwn);
*physport = ddi_get8(accessp, &sasdevpage->PhysicalPort);
*phynum = ddi_get8(accessp, &sasdevpage->PhyNum);
+ *pdevhdl = ddi_get16(accessp, &sasdevpage->ParentDevHandle);
*bay_num = ddi_get16(accessp, &sasdevpage->Slot);
*enclosure = ddi_get16(accessp, &sasdevpage->EnclosureHandle);
return (rval);
@@ -1452,7 +1457,8 @@ mptsas_sasdevpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
int
mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
- uint8_t *physport, uint8_t *phynum, uint16_t *bay_num, uint16_t *enclosure)
+ uint8_t *physport, uint8_t *phynum, uint16_t *pdev_handle,
+ uint16_t *bay_num, uint16_t *enclosure)
{
int rval = DDI_SUCCESS;
@@ -1466,7 +1472,8 @@ mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE, 0, page_address,
mptsas_sasdevpage_0_cb, page_address, dev_handle, sas_wwn,
- dev_info, physport, phynum, bay_num, enclosure);
+ dev_info, physport, phynum, pdev_handle,
+ bay_num, enclosure);
return (rval);
}
@@ -1487,6 +1494,7 @@ mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
uint64_t *sas_wwn;
uint8_t physport;
mptsas_phymask_t *phymask;
+ uint16_t *pdevhdl;
uint32_t page_address;
if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
@@ -1515,18 +1523,21 @@ mptsas_sasexpdpage_0_cb(mptsas_t *mpt, caddr_t page_memp,
devhdl = va_arg(ap, uint16_t *);
sas_wwn = va_arg(ap, uint64_t *);
phymask = va_arg(ap, mptsas_phymask_t *);
+ pdevhdl = va_arg(ap, uint16_t *);
expddevpage = (pMpi2ExpanderPage0_t)page_memp;
*devhdl = ddi_get16(accessp, &expddevpage->DevHandle);
physport = ddi_get8(accessp, &expddevpage->PhysicalPort);
*phymask = mptsas_physport_to_phymask(mpt, physport);
+ *pdevhdl = ddi_get16(accessp, &expddevpage->ParentDevHandle);
sas_addr = (uint8_t *)(&expddevpage->SASAddress);
for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
}
bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
*sas_wwn = LE_64(*sas_wwn);
+
return (rval);
}
@@ -1550,7 +1561,7 @@ mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER, 0, page_address,
mptsas_sasexpdpage_0_cb, page_address, &info->m_devhdl,
- &info->m_sasaddr, &info->m_phymask);
+ &info->m_sasaddr, &info->m_phymask, &info->m_pdevhdl);
return (rval);
}
@@ -1724,7 +1735,6 @@ mptsas_sasiou_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
&sasioupage1->PhyData[i].Port);
mpt->m_phy_info[i].port_flags = port_flags;
mpt->m_phy_info[i].phy_device_type = cpdi[i];
-
}
return (rval);
}
@@ -2448,3 +2458,434 @@ done:
return (rval);
}
+
+static int
+mptsas_sasphypage_0_cb(mptsas_t *mpt, caddr_t page_memp,
+ ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+ va_list ap)
+{
+#ifndef __lock_lint
+ _NOTE(ARGUNUSED(ap))
+#endif
+ pMpi2SasPhyPage0_t sasphypage;
+ int rval = DDI_SUCCESS;
+ uint16_t *owner_devhdl, *attached_devhdl;
+ uint8_t *attached_phy_identify;
+ uint32_t *attached_phy_info;
+ uint8_t *programmed_link_rate;
+ uint8_t *hw_link_rate;
+ uint8_t *change_count;
+ uint32_t *phy_info;
+ uint8_t *negotiated_link_rate;
+ uint32_t page_address;
+
+ if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
+ (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
+ mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page0 "
+ "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+ iocstatus, iocloginfo);
+ rval = DDI_FAILURE;
+ return (rval);
+ }
+ page_address = va_arg(ap, uint32_t);
+ /*
+ * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
+ * are no more pages. If everything is OK up to this point but the
+ * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
+ * signal that device traversal is complete.
+ */
+ if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
+ mpt->m_done_traverse_smp = 1;
+ }
+ rval = DDI_FAILURE;
+ return (rval);
+ }
+ owner_devhdl = va_arg(ap, uint16_t *);
+ attached_devhdl = va_arg(ap, uint16_t *);
+ attached_phy_identify = va_arg(ap, uint8_t *);
+ attached_phy_info = va_arg(ap, uint32_t *);
+ programmed_link_rate = va_arg(ap, uint8_t *);
+ hw_link_rate = va_arg(ap, uint8_t *);
+ change_count = va_arg(ap, uint8_t *);
+ phy_info = va_arg(ap, uint32_t *);
+ negotiated_link_rate = va_arg(ap, uint8_t *);
+
+ sasphypage = (pMpi2SasPhyPage0_t)page_memp;
+
+ *owner_devhdl =
+ ddi_get16(accessp, &sasphypage->OwnerDevHandle);
+ *attached_devhdl =
+ ddi_get16(accessp, &sasphypage->AttachedDevHandle);
+ *attached_phy_identify =
+ ddi_get8(accessp, &sasphypage->AttachedPhyIdentifier);
+ *attached_phy_info =
+ ddi_get32(accessp, &sasphypage->AttachedPhyInfo);
+ *programmed_link_rate =
+ ddi_get8(accessp, &sasphypage->ProgrammedLinkRate);
+ *hw_link_rate =
+ ddi_get8(accessp, &sasphypage->HwLinkRate);
+ *change_count =
+ ddi_get8(accessp, &sasphypage->ChangeCount);
+ *phy_info =
+ ddi_get32(accessp, &sasphypage->PhyInfo);
+ *negotiated_link_rate =
+ ddi_get8(accessp, &sasphypage->NegotiatedLinkRate);
+
+ return (rval);
+}
+
+/*
+ * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
+ * and SAS address.
+ */
+int
+mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
+ smhba_info_t *info)
+{
+ int rval = DDI_SUCCESS;
+
+ ASSERT(mutex_owned(&mpt->m_mutex));
+
+ /*
+ * Get the header and config page. reply contains the reply frame,
+ * which holds status info for the request.
+ */
+ rval = mptsas_access_config_page(mpt,
+ MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 0, page_address,
+ mptsas_sasphypage_0_cb, page_address, &info->owner_devhdl,
+ &info->attached_devhdl, &info->attached_phy_identify,
+ &info->attached_phy_info, &info->programmed_link_rate,
+ &info->hw_link_rate, &info->change_count,
+ &info->phy_info, &info->negotiated_link_rate);
+
+ return (rval);
+}
+
+static int
+mptsas_sasphypage_1_cb(mptsas_t *mpt, caddr_t page_memp,
+ ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
+ va_list ap)
+{
+#ifndef __lock_lint
+ _NOTE(ARGUNUSED(ap))
+#endif
+ pMpi2SasPhyPage1_t sasphypage;
+ int rval = DDI_SUCCESS;
+
+ uint32_t *invalid_dword_count;
+ uint32_t *running_disparity_error_count;
+ uint32_t *loss_of_dword_sync_count;
+ uint32_t *phy_reset_problem_count;
+ uint32_t page_address;
+
+ if ((iocstatus != MPI2_IOCSTATUS_SUCCESS) &&
+ (iocstatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)) {
+ mptsas_log(mpt, CE_WARN, "mptsas_get_sas_expander_page1 "
+ "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
+ iocstatus, iocloginfo);
+ rval = DDI_FAILURE;
+ return (rval);
+ }
+ page_address = va_arg(ap, uint32_t);
+ /*
+ * The INVALID_PAGE status is normal if using GET_NEXT_HANDLE and there
+ * are no more pages. If everything is OK up to this point but the
+ * status is INVALID_PAGE, change rval to FAILURE and quit. Also,
+ * signal that device traversal is complete.
+ */
+ if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ if ((page_address & MPI2_SAS_EXPAND_PGAD_FORM_MASK) ==
+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL) {
+ mpt->m_done_traverse_smp = 1;
+ }
+ rval = DDI_FAILURE;
+ return (rval);
+ }
+
+ invalid_dword_count = va_arg(ap, uint32_t *);
+ running_disparity_error_count = va_arg(ap, uint32_t *);
+ loss_of_dword_sync_count = va_arg(ap, uint32_t *);
+ phy_reset_problem_count = va_arg(ap, uint32_t *);
+
+ sasphypage = (pMpi2SasPhyPage1_t)page_memp;
+
+ *invalid_dword_count =
+ ddi_get32(accessp, &sasphypage->InvalidDwordCount);
+ *running_disparity_error_count =
+ ddi_get32(accessp, &sasphypage->RunningDisparityErrorCount);
+ *loss_of_dword_sync_count =
+ ddi_get32(accessp, &sasphypage->LossDwordSynchCount);
+ *phy_reset_problem_count =
+ ddi_get32(accessp, &sasphypage->PhyResetProblemCount);
+
+ return (rval);
+}
+
+/*
+ * Request MPI configuration page SAS phy page 0 to get DevHandle, phymask
+ * and SAS address.
+ */
+int
+mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
+ smhba_info_t *info)
+{
+ int rval = DDI_SUCCESS;
+
+ ASSERT(mutex_owned(&mpt->m_mutex));
+
+ /*
+ * Get the header and config page. reply contains the reply frame,
+ * which holds status info for the request.
+ */
+ rval = mptsas_access_config_page(mpt,
+ MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_PHY, 1, page_address,
+ mptsas_sasphypage_1_cb, page_address,
+ &info->invalid_dword_count,
+ &info->running_disparity_error_count,
+ &info->loss_of_dword_sync_count,
+ &info->phy_reset_problem_count);
+
+ return (rval);
+}
+/*
+ * mptsas_get_manufacture_page0
+ *
+ * This function will retrieve the base
+ * Chip name, Board Name,Board Trace number from the adapter.
+ * Since this function is only called during the
+ * initialization process, use handshaking.
+ */
+int
+mptsas_get_manufacture_page0(mptsas_t *mpt)
+{
+ ddi_dma_attr_t recv_dma_attrs, page_dma_attrs;
+ ddi_dma_cookie_t recv_cookie, page_cookie;
+ ddi_dma_handle_t recv_dma_handle, page_dma_handle;
+ ddi_acc_handle_t recv_accessp, page_accessp;
+ size_t recv_alloc_len, page_alloc_len;
+ pMpi2ConfigReply_t configreply;
+ uint_t recv_ncookie, page_ncookie;
+ caddr_t recv_memp, page_memp;
+ int recv_numbytes;
+ pMpi2ManufacturingPage0_t m0;
+ int recv_dmastate = 0;
+ int page_dmastate = 0;
+ uint32_t flagslength;
+ int rval = DDI_SUCCESS;
+ uint_t iocstatus;
+ uint8_t i = 0;
+
+ MPTSAS_DISABLE_INTR(mpt);
+
+ if (mptsas_send_config_request_msg(mpt, MPI2_CONFIG_ACTION_PAGE_HEADER,
+ MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0, 0, 0, 0, 0)) {
+ rval = DDI_FAILURE;
+ goto done;
+ }
+
+ /*
+ * dynamically create a customized dma attribute structure
+ * that describes the MPT's config reply page request structure.
+ */
+ recv_dma_attrs = mpt->m_msg_dma_attr;
+ recv_dma_attrs.dma_attr_sgllen = 1;
+ recv_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_REPLY));
+
+ if (ddi_dma_alloc_handle(mpt->m_dip, &recv_dma_attrs,
+ DDI_DMA_SLEEP, NULL, &recv_dma_handle) != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "(unable to allocate dma handle.");
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ recv_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+ if (ddi_dma_mem_alloc(recv_dma_handle,
+ (sizeof (MPI2_CONFIG_REPLY)),
+ &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+ &recv_memp, &recv_alloc_len, &recv_accessp) != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "unable to allocate config_reply structure.");
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ recv_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+ if (ddi_dma_addr_bind_handle(recv_dma_handle, NULL, recv_memp,
+ recv_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+ NULL, &recv_cookie, &recv_ncookie) != DDI_DMA_MAPPED) {
+ mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ recv_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+ bzero(recv_memp, sizeof (MPI2_CONFIG_REPLY));
+ configreply = (pMpi2ConfigReply_t)recv_memp;
+ recv_numbytes = sizeof (MPI2_CONFIG_REPLY);
+
+ /*
+ * get config reply message
+ */
+ if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+ recv_accessp)) {
+ rval = DDI_FAILURE;
+ goto done;
+ }
+
+ if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
+ mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page5 update: "
+ "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+ ddi_get32(recv_accessp, &configreply->IOCLogInfo));
+ goto done;
+ }
+
+ /*
+ * dynamically create a customized dma attribute structure
+ * that describes the MPT's config page structure.
+ */
+ page_dma_attrs = mpt->m_msg_dma_attr;
+ page_dma_attrs.dma_attr_sgllen = 1;
+ page_dma_attrs.dma_attr_granular = (sizeof (MPI2_CONFIG_PAGE_MAN_0));
+
+ if (ddi_dma_alloc_handle(mpt->m_dip, &page_dma_attrs,
+ DDI_DMA_SLEEP, NULL, &page_dma_handle) != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "(unable to allocate dma handle.");
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ page_dmastate |= MPTSAS_DMA_HANDLE_ALLOCD;
+
+ if (ddi_dma_mem_alloc(page_dma_handle,
+ (sizeof (MPI2_CONFIG_PAGE_MAN_0)),
+ &mpt->m_dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
+ &page_memp, &page_alloc_len, &page_accessp) != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "unable to allocate manufacturing page structure.");
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ page_dmastate |= MPTSAS_DMA_MEMORY_ALLOCD;
+
+ if (ddi_dma_addr_bind_handle(page_dma_handle, NULL, page_memp,
+ page_alloc_len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+ NULL, &page_cookie, &page_ncookie) != DDI_DMA_MAPPED) {
+ mptsas_log(mpt, CE_WARN, "unable to bind DMA resources.");
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ page_dmastate |= MPTSAS_DMA_HANDLE_BOUND;
+ bzero(page_memp, sizeof (MPI2_CONFIG_PAGE_MAN_0));
+ m0 = (pMpi2ManufacturingPage0_t)page_memp;
+
+ /*
+ * Give reply address to IOC to store config page in and send
+ * config request out.
+ */
+
+ flagslength = sizeof (MPI2_CONFIG_PAGE_MAN_0);
+ flagslength |= ((uint32_t)(MPI2_SGE_FLAGS_LAST_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_SYSTEM_ADDRESS | MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
+ MPI2_SGE_FLAGS_IOC_TO_HOST |
+ MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+
+ if (mptsas_send_config_request_msg(mpt,
+ MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
+ MPI2_CONFIG_PAGETYPE_MANUFACTURING, 0, 0,
+ ddi_get8(recv_accessp, &configreply->Header.PageVersion),
+ ddi_get8(recv_accessp, &configreply->Header.PageLength),
+ flagslength, page_cookie.dmac_address)) {
+ rval = DDI_FAILURE;
+ goto done;
+ }
+
+ /*
+ * get reply view handshake
+ */
+ if (mptsas_get_handshake_msg(mpt, recv_memp, recv_numbytes,
+ recv_accessp)) {
+ rval = DDI_FAILURE;
+ goto done;
+ }
+
+ if (iocstatus = ddi_get16(recv_accessp, &configreply->IOCStatus)) {
+ mptsas_log(mpt, CE_WARN, "mptsas_get_manufacture_page0 config: "
+ "IOCStatus=0x%x, IOCLogInfo=0x%x", iocstatus,
+ ddi_get32(recv_accessp, &configreply->IOCLogInfo));
+ goto done;
+ }
+
+ (void) ddi_dma_sync(page_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
+
+ /*
+ * Fusion-MPT stores fields in little-endian format. This is
+ * why the low-order 32 bits are stored first.
+ */
+
+ for (i = 0; i < 16; i++) {
+ mpt->m_MANU_page0.ChipName[i] =
+ ddi_get8(page_accessp,
+ (uint8_t *)(void *)&m0->ChipName[i]);
+ }
+
+ for (i = 0; i < 8; i++) {
+ mpt->m_MANU_page0.ChipRevision[i] =
+ ddi_get8(page_accessp,
+ (uint8_t *)(void *)&m0->ChipRevision[i]);
+ }
+
+ for (i = 0; i < 16; i++) {
+ mpt->m_MANU_page0.BoardName[i] =
+ ddi_get8(page_accessp,
+ (uint8_t *)(void *)&m0->BoardName[i]);
+ }
+
+ for (i = 0; i < 16; i++) {
+ mpt->m_MANU_page0.BoardAssembly[i] =
+ ddi_get8(page_accessp,
+ (uint8_t *)(void *)&m0->BoardAssembly[i]);
+ }
+
+ for (i = 0; i < 16; i++) {
+ mpt->m_MANU_page0.BoardTracerNumber[i] =
+ ddi_get8(page_accessp,
+ (uint8_t *)(void *)&m0->BoardTracerNumber[i]);
+ }
+
+ if ((mptsas_check_dma_handle(recv_dma_handle) != DDI_SUCCESS) ||
+ (mptsas_check_dma_handle(page_dma_handle) != DDI_SUCCESS)) {
+ ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+ rval = DDI_FAILURE;
+ goto done;
+ }
+ if ((mptsas_check_acc_handle(recv_accessp) != DDI_SUCCESS) ||
+ (mptsas_check_acc_handle(page_accessp) != DDI_SUCCESS)) {
+ ddi_fm_service_impact(mpt->m_dip, DDI_SERVICE_UNAFFECTED);
+ rval = DDI_FAILURE;
+ }
+done:
+ /*
+ * free up memory
+ */
+ if (recv_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+ (void) ddi_dma_unbind_handle(recv_dma_handle);
+ if (page_dmastate & MPTSAS_DMA_HANDLE_BOUND)
+ (void) ddi_dma_unbind_handle(page_dma_handle);
+ if (recv_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+ (void) ddi_dma_mem_free(&recv_accessp);
+ if (page_dmastate & MPTSAS_DMA_MEMORY_ALLOCD)
+ (void) ddi_dma_mem_free(&page_accessp);
+ if (recv_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+ ddi_dma_free_handle(&recv_dma_handle);
+ if (page_dmastate & MPTSAS_DMA_HANDLE_ALLOCD)
+ ddi_dma_free_handle(&page_dma_handle);
+
+ MPTSAS_ENABLE_INTR(mpt);
+
+ return (rval);
+}
diff --git a/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c
new file mode 100644
index 0000000000..e0f26181af
--- /dev/null
+++ b/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c
@@ -0,0 +1,454 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ * This file contains SM-HBA support for MPT SAS driver
+ */
+
+#if defined(lint) || defined(DEBUG)
+#define MPTSAS_DEBUG
+#endif
+
+/*
+ * standard header files
+ */
+#include <sys/note.h>
+#include <sys/scsi/scsi.h>
+#include <sys/pci.h>
+
+#pragma pack(1)
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_sas.h>
+#pragma pack()
+
+/*
+ * private header files.
+ */
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_smhba.h>
+
+void
+mptsas_smhba_add_hba_prop(mptsas_t *mpt, data_type_t dt,
+ char *prop_name, void *prop_val);
+
+void
+mptsas_smhba_show_phy_info(mptsas_t *mpt);
+
+void
+mptsas_smhba_add_hba_prop(mptsas_t *mpt, data_type_t dt,
+ char *prop_name, void *prop_val)
+{
+ ASSERT(mpt != NULL);
+
+ switch (dt) {
+ case DATA_TYPE_INT32:
+ if (ddi_prop_update_int(DDI_DEV_T_NONE, mpt->m_dip,
+ prop_name, *(int *)prop_val)) {
+ mptsas_log(mpt, CE_WARN,
+ "%s: %s prop update failed", __func__, prop_name);
+ }
+ break;
+ case DATA_TYPE_STRING:
+ if (ddi_prop_update_string(DDI_DEV_T_NONE, mpt->m_dip,
+ prop_name, (char *)prop_val)) {
+ mptsas_log(mpt, CE_WARN,
+ "%s: %s prop update failed", __func__, prop_name);
+ }
+ break;
+ default:
+ mptsas_log(mpt, CE_WARN, "%s: "
+ "Unhandled datatype(%d) for (%s). Skipping prop update.",
+ __func__, dt, prop_name);
+ }
+}
+
+void
+mptsas_smhba_show_phy_info(mptsas_t *mpt)
+{
+ int i;
+
+ ASSERT(mpt != NULL);
+
+ for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
+ mptsas_log(mpt, CE_WARN,
+ "phy %d, Owner hdl:0x%x, attached hdl: 0x%x,"
+ "attached phy identifier %d,Program link rate 0x%x,"
+ "hw link rate 0x%x, negotiator link rate 0x%x, path %s",
+ i, mpt->m_phy_info[i].smhba_info.owner_devhdl,
+ mpt->m_phy_info[i].smhba_info.attached_devhdl,
+ mpt->m_phy_info[i].smhba_info.attached_phy_identify,
+ mpt->m_phy_info[i].smhba_info.programmed_link_rate,
+ mpt->m_phy_info[i].smhba_info.hw_link_rate,
+ mpt->m_phy_info[i].smhba_info.negotiated_link_rate,
+ mpt->m_phy_info[i].smhba_info.path);
+ }
+}
+
+void
+mptsas_smhba_set_phy_props(mptsas_t *mpt, char *iport, dev_info_t *dip,
+ uint8_t phy_nums, uint16_t *attached_devhdl)
+{
+ int i;
+ int j = 0;
+ int rval;
+ size_t packed_size;
+ char *packed_data = NULL;
+ char phymask[MPTSAS_MAX_PHYS];
+ nvlist_t **phy_props;
+ nvlist_t *nvl;
+ smhba_info_t *pSmhba = NULL;
+
+ if (phy_nums == 0) {
+ return;
+ }
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
+ mptsas_log(mpt, CE_WARN, "%s: nvlist_alloc() failed", __func__);
+ }
+
+ phy_props = kmem_zalloc(sizeof (nvlist_t *) * phy_nums,
+ KM_SLEEP);
+
+ for (i = 0; i < mpt->m_num_phys; i++) {
+
+ bzero(phymask, sizeof (phymask));
+ (void) sprintf(phymask, "%x", mpt->m_phy_info[i].phy_mask);
+ if (strcmp(phymask, iport) == 0) {
+ pSmhba = &mpt->m_phy_info[i].smhba_info;
+ (void) nvlist_alloc(&phy_props[j], NV_UNIQUE_NAME, 0);
+ (void) nvlist_add_uint8(phy_props[j], SAS_PHY_ID, i);
+ (void) nvlist_add_uint8(phy_props[j],
+ "phyState",
+ (pSmhba->negotiated_link_rate
+ & 0x0f));
+ (void) nvlist_add_int8(phy_props[j],
+ SAS_NEG_LINK_RATE,
+ (pSmhba->negotiated_link_rate
+ & 0x0f));
+ (void) nvlist_add_int8(phy_props[j],
+ SAS_PROG_MIN_LINK_RATE,
+ (pSmhba->programmed_link_rate
+ & 0x0f));
+ (void) nvlist_add_int8(phy_props[j],
+ SAS_HW_MIN_LINK_RATE,
+ (pSmhba->hw_link_rate
+ & 0x0f));
+ (void) nvlist_add_int8(phy_props[j],
+ SAS_PROG_MAX_LINK_RATE,
+ ((pSmhba->programmed_link_rate
+ & 0xf0) >> 4));
+ (void) nvlist_add_int8(phy_props[j],
+ SAS_HW_MAX_LINK_RATE,
+ ((pSmhba->hw_link_rate
+ & 0xf0) >> 4));
+
+ j++;
+
+ if (pSmhba->attached_devhdl &&
+ (attached_devhdl != NULL)) {
+ *attached_devhdl =
+ pSmhba->attached_devhdl;
+ }
+ }
+ }
+
+ rval = nvlist_add_nvlist_array(nvl, SAS_PHY_INFO_NVL, phy_props,
+ phy_nums);
+ if (rval) {
+ mptsas_log(mpt, CE_WARN,
+ " nv list array add failed, return value %d.",
+ rval);
+ goto exit;
+ }
+ (void) nvlist_size(nvl, &packed_size, NV_ENCODE_NATIVE);
+ packed_data = kmem_zalloc(packed_size, KM_SLEEP);
+ (void) nvlist_pack(nvl, &packed_data, &packed_size,
+ NV_ENCODE_NATIVE, 0);
+
+ (void) ddi_prop_update_byte_array(DDI_DEV_T_NONE, dip,
+ SAS_PHY_INFO, (uchar_t *)packed_data, packed_size);
+
+exit:
+ for (i = 0; i < phy_nums && phy_props[i] != NULL; i++) {
+ nvlist_free(phy_props[i]);
+ }
+ nvlist_free(nvl);
+ kmem_free(phy_props, sizeof (nvlist_t *) * phy_nums);
+
+ if (packed_data != NULL) {
+ kmem_free(packed_data, packed_size);
+ }
+}
+
+/*
+ * Called with PHY lock held on phyp
+ */
+void
+mptsas_smhba_log_sysevent(mptsas_t *mpt, char *subclass, char *etype,
+ smhba_info_t *phyp)
+{
+ nvlist_t *attr_list;
+ char *pname;
+ char sas_addr[MPTSAS_WWN_STRLEN];
+ uint8_t phynum = 0;
+ uint8_t lrate = 0;
+
+ if (mpt->m_dip == NULL)
+ return;
+ if (phyp == NULL)
+ return;
+
+ pname = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP);
+ if (pname == NULL)
+ return;
+
+ if ((strcmp(subclass, ESC_SAS_PHY_EVENT) == 0) ||
+ (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0)) {
+ ASSERT(phyp != NULL);
+ (void) strncpy(pname, phyp->path, strlen(phyp->path));
+ phynum = phyp->phy_id;
+ bzero(sas_addr, sizeof (sas_addr));
+ (void) sprintf(sas_addr, "w%016"PRIx64, phyp->sas_addr);
+ if (strcmp(etype, SAS_PHY_ONLINE) == 0) {
+ lrate = phyp->negotiated_link_rate;
+ }
+ }
+ if (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0) {
+ (void) ddi_pathname(mpt->m_dip, pname);
+ }
+
+ if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 0) != 0) {
+ mptsas_log(mpt, CE_WARN,
+ "%s: Failed to post sysevent", __func__);
+ kmem_free(pname, MAXPATHLEN);
+ return;
+ }
+
+ if (nvlist_add_int32(attr_list, SAS_DRV_INST,
+ ddi_get_instance(mpt->m_dip)) != 0)
+ goto fail;
+
+ if (nvlist_add_string(attr_list, SAS_PORT_ADDR, sas_addr) != 0)
+ goto fail;
+
+ if (nvlist_add_string(attr_list, SAS_DEVFS_PATH, pname) != 0)
+ goto fail;
+
+ if (nvlist_add_uint8(attr_list, SAS_PHY_ID, phynum) != 0)
+ goto fail;
+
+ if (strcmp(etype, SAS_PHY_ONLINE) == 0) {
+ if (nvlist_add_uint8(attr_list, SAS_LINK_RATE, lrate) != 0)
+ goto fail;
+ }
+
+ if (nvlist_add_string(attr_list, SAS_EVENT_TYPE, etype) != 0)
+ goto fail;
+
+ (void) ddi_log_sysevent(mpt->m_dip, DDI_VENDOR_SUNW, EC_HBA, subclass,
+ attr_list, NULL, DDI_NOSLEEP);
+
+fail:
+ kmem_free(pname, MAXPATHLEN);
+ nvlist_free(attr_list);
+}
+
+void
+mptsas_create_phy_stats(mptsas_t *mpt, char *iport, dev_info_t *dip)
+{
+ sas_phy_stats_t *ps;
+ smhba_info_t *phyp;
+ int ndata;
+ char ks_name[KSTAT_STRLEN];
+ char phymask[MPTSAS_MAX_PHYS];
+ int i;
+
+ ASSERT(iport != NULL);
+ ASSERT(mpt != NULL);
+
+ for (i = 0; i < mpt->m_num_phys; i++) {
+
+ bzero(phymask, sizeof (phymask));
+ (void) sprintf(phymask, "%x", mpt->m_phy_info[i].phy_mask);
+ if (strcmp(phymask, iport) == 0) {
+
+ phyp = &mpt->m_phy_info[i].smhba_info;
+ mutex_enter(&phyp->phy_mutex);
+
+ if (phyp->phy_stats != NULL) {
+ mutex_exit(&phyp->phy_mutex);
+ /* We've already created this kstat instance */
+ continue;
+ }
+
+ ndata = (sizeof (sas_phy_stats_t)/
+ sizeof (kstat_named_t));
+ (void) snprintf(ks_name, sizeof (ks_name),
+ "%s.%llx.%d.%d", ddi_driver_name(dip),
+ (longlong_t)mpt->un.m_base_wwid,
+ ddi_get_instance(dip), i);
+
+ phyp->phy_stats = kstat_create("mptsas",
+ ddi_get_instance(dip), ks_name, KSTAT_SAS_PHY_CLASS,
+ KSTAT_TYPE_NAMED, ndata, 0);
+
+ if (phyp->phy_stats == NULL) {
+ mutex_exit(&phyp->phy_mutex);
+ mptsas_log(mpt, CE_WARN,
+ "%s: Failed to create %s kstats", __func__,
+ ks_name);
+ continue;
+ }
+
+ ps = (sas_phy_stats_t *)phyp->phy_stats->ks_data;
+
+ kstat_named_init(&ps->seconds_since_last_reset,
+ "SecondsSinceLastReset", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->tx_frames,
+ "TxFrames", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->rx_frames,
+ "RxFrames", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->tx_words,
+ "TxWords", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->rx_words,
+ "RxWords", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->invalid_dword_count,
+ "InvalidDwordCount", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->running_disparity_error_count,
+ "RunningDisparityErrorCount", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->loss_of_dword_sync_count,
+ "LossofDwordSyncCount", KSTAT_DATA_ULONGLONG);
+ kstat_named_init(&ps->phy_reset_problem_count,
+ "PhyResetProblemCount", KSTAT_DATA_ULONGLONG);
+
+ phyp->phy_stats->ks_private = phyp;
+ phyp->phy_stats->ks_update = mptsas_update_phy_stats;
+ kstat_install(phyp->phy_stats);
+ mutex_exit(&phyp->phy_mutex);
+ }
+ }
+}
+
+int
+mptsas_update_phy_stats(kstat_t *ks, int rw)
+{
+ int ret = DDI_FAILURE;
+ smhba_info_t *pptr = NULL;
+ sas_phy_stats_t *ps = ks->ks_data;
+ uint32_t page_address;
+ mptsas_t *mpt;
+
+ _NOTE(ARGUNUSED(rw));
+
+ pptr = (smhba_info_t *)ks->ks_private;
+ ASSERT((pptr != NULL));
+ mpt = (mptsas_t *)pptr->mpt;
+ ASSERT((mpt != NULL));
+ page_address = (MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | pptr->phy_id);
+
+ /*
+ * We just want to lock against other invocations of kstat;
+ * we don't need to pmcs_lock_phy() for this.
+ */
+ mutex_enter(&mpt->m_mutex);
+
+ ret = mptsas_get_sas_phy_page1(pptr->mpt, page_address, pptr);
+
+ if (ret == DDI_FAILURE)
+ goto fail;
+
+ ps->invalid_dword_count.value.ull =
+ (unsigned long long)pptr->invalid_dword_count;
+
+ ps->running_disparity_error_count.value.ull =
+ (unsigned long long)pptr->running_disparity_error_count;
+
+ ps->loss_of_dword_sync_count.value.ull =
+ (unsigned long long)pptr->loss_of_dword_sync_count;
+
+ ps->phy_reset_problem_count.value.ull =
+ (unsigned long long)pptr->phy_reset_problem_count;
+
+ ret = DDI_SUCCESS;
+fail:
+ mutex_exit(&mpt->m_mutex);
+
+ return (ret);
+}
+
+void
+mptsas_destroy_phy_stats(mptsas_t *mpt)
+{
+ smhba_info_t *phyp;
+ int i = 0;
+
+ ASSERT(mpt != NULL);
+
+ for (i = 0; i < mpt->m_num_phys; i++) {
+ phyp = &mpt->m_phy_info[i].smhba_info;
+ if (phyp == NULL) {
+ continue;
+ }
+
+ mutex_enter(&phyp->phy_mutex);
+ if (phyp->phy_stats != NULL) {
+ kstat_delete(phyp->phy_stats);
+ phyp->phy_stats = NULL;
+ }
+ mutex_exit(&phyp->phy_mutex);
+ }
+}
+
+int
+mptsas_smhba_phy_init(mptsas_t *mpt)
+{
+ int i = 0;
+ int rval = DDI_SUCCESS;
+ uint32_t page_address;
+
+ ASSERT(mutex_owned(&mpt->m_mutex));
+
+ for (i = 0; i < mpt->m_num_phys; i++) {
+ page_address =
+ (MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER |
+ (MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK & i));
+ rval = mptsas_get_sas_phy_page0(mpt,
+ page_address, &mpt->m_phy_info[i].smhba_info);
+ if (rval != DDI_SUCCESS) {
+ mptsas_log(mpt, CE_WARN,
+ "Failed to get sas phy page 0"
+ " for each phy");
+ return (DDI_FAILURE);
+ }
+ mpt->m_phy_info[i].smhba_info.phy_id = (uint8_t)i;
+ mpt->m_phy_info[i].smhba_info.sas_addr =
+ mpt->un.m_base_wwid + i;
+ mpt->m_phy_info[i].smhba_info.mpt = mpt;
+ }
+
+ return (DDI_SUCCESS);
+}
diff --git a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h
new file mode 100644
index 0000000000..6148f8781d
--- /dev/null
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * SM-HBA interfaces/definitions for MPT SAS driver.
+ */
+
+#ifndef _MPTSAS_SMHBA_H
+#define _MPTSAS_SMHBA_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Leverage definition of data_type_t in nvpair.h */
+#include <sys/nvpair.h>
+#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
+
+#define MPTSAS_NUM_PHYS "num-phys"
+#define MPTSAS_NUM_PHYS_HBA "num-phys-hba"
+#define MPTSAS_SMHBA_SUPPORTED "sm-hba-supported"
+#define MPTSAS_DRV_VERSION "driver-version"
+#define MPTSAS_HWARE_VERSION "hardware-version"
+#define MPTSAS_FWARE_VERSION "firmware-version"
+#define MPTSAS_SUPPORTED_PROTOCOL "supported-protocol"
+#define MPTSAS_VIRTUAL_PORT "virtual-port"
+
+#define MPTSAS_MANUFACTURER "Manufacturer"
+#define MPTSAS_SERIAL_NUMBER "SerialNumber"
+#define MPTSAS_MODEL_NAME "ModelName"
+#define MPTSAS_VARIANT "variant"
+
+#define IS_ATAPI_DEVICE(x) ((x) & 0x2000)
+#define IS_SATA_DEVICE(x) ((x) & 0x80)
+#define DEVINFO_DIRECT_ATTACHED 0x0800
+
+/*
+ * Interfaces to add properties required for SM-HBA
+ *
+ * _add_xxx_prop() interfaces add only 1 prop that is specified in the args.
+ * _set_xxx_props() interfaces add more than 1 prop for a set of phys/devices.
+ */
+void mptsas_smhba_add_hba_prop(mptsas_t *, data_type_t, char *, void *);
+void mptsas_smhba_show_phy_info(mptsas_t *);
+void mptsas_smhba_set_phy_props(mptsas_t *mpt, char *iport, dev_info_t *dip,
+ uint8_t phy_nums, uint16_t *attached_devhdl);
+void mptsas_smhba_log_sysevent(mptsas_t *mpt, char *subclass, char *etype,
+ smhba_info_t *phyp);
+void
+mptsas_create_phy_stats(mptsas_t *mpt, char *iport, dev_info_t *dip);
+int mptsas_update_phy_stats(kstat_t *ks, int rw);
+void mptsas_destroy_phy_stats(mptsas_t *mpt);
+int mptsas_smhba_phy_init(mptsas_t *mpt);
+int mptsas_smhba_phy_state_update(mptsas_t *mpt, uint8_t phy);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _MPTSAS_SMHBA_H */
diff --git a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
index 0b2986c7ea..1a87fcadc0 100644
--- a/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
+++ b/usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h
@@ -58,6 +58,8 @@
#include <sys/sunmdi.h>
#include <sys/mdi_impldefs.h>
#include <sys/scsi/adapters/mpt_sas/mptsas_ioctl.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_tool.h>
+#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
#ifdef __cplusplus
extern "C" {
@@ -83,6 +85,7 @@ extern "C" {
typedef uint16_t mptsas_phymask_t;
#define MPTSAS_INVALID_DEVHDL 0xffff
+#define MPTSAS_SATA_GUID "sata-guid"
/*
* MPT HW defines
@@ -213,6 +216,8 @@ typedef struct mptsas_smp {
uint8_t reserved1;
uint16_t m_devhdl;
uint32_t m_deviceinfo;
+ uint16_t m_pdevhdl;
+ uint32_t m_pdevinfo;
} mptsas_smp_t;
typedef struct mptsas_hash_data {
@@ -590,6 +595,30 @@ typedef struct mptsas_tgt_private {
/*
* Macro for phy_flags
*/
+
+typedef struct smhba_info {
+ kmutex_t phy_mutex;
+ uint8_t phy_id;
+ uint64_t sas_addr;
+ char path[8];
+ uint16_t owner_devhdl;
+ uint16_t attached_devhdl;
+ uint8_t attached_phy_identify;
+ uint32_t attached_phy_info;
+ uint8_t programmed_link_rate;
+ uint8_t hw_link_rate;
+ uint8_t change_count;
+ uint32_t phy_info;
+ uint8_t negotiated_link_rate;
+ uint8_t port_num;
+ kstat_t *phy_stats;
+ uint32_t invalid_dword_count;
+ uint32_t running_disparity_error_count;
+ uint32_t loss_of_dword_sync_count;
+ uint32_t phy_reset_problem_count;
+ void *mpt;
+} smhba_info_t;
+
typedef struct mptsas_phy_info {
uint8_t port_num;
uint8_t port_flags;
@@ -597,8 +626,10 @@ typedef struct mptsas_phy_info {
uint32_t phy_device_type;
uint16_t attached_devhdl;
mptsas_phymask_t phy_mask;
+ smhba_info_t smhba_info;
} mptsas_phy_info_t;
+
typedef struct mptsas_doneq_thread_arg {
void *mpt;
uint64_t t;
@@ -818,6 +849,8 @@ typedef struct mptsas {
uint8_t m_num_phys; /* # of PHYs */
mptsas_phy_info_t m_phy_info[MPTSAS_MAX_PHYS];
uint8_t m_port_chng; /* initiator port changes */
+ MPI2_CONFIG_PAGE_MAN_0 m_MANU_page0; /* Manufactor page 0 info */
+ MPI2_CONFIG_PAGE_MAN_1 m_MANU_page1; /* Manufactor page 1 info */
/* FMA Capabilities */
int m_fm_capabilities;
@@ -1279,8 +1312,8 @@ int mptsas_ioc_init(mptsas_t *mpt);
*/
int mptsas_get_sas_device_page0(mptsas_t *mpt, uint32_t page_address,
uint16_t *dev_handle, uint64_t *sas_wwn, uint32_t *dev_info,
- uint8_t *physport, uint8_t *phynum, uint16_t *slot_num,
- uint16_t *enclosure);
+ uint8_t *physport, uint8_t *phynum, uint16_t *pdevhandle,
+ uint16_t *slot_num, uint16_t *enclosure);
int mptsas_get_sas_io_unit_page(mptsas_t *mpt);
int mptsas_get_sas_io_unit_page_hndshk(mptsas_t *mpt);
int mptsas_get_sas_expander_page0(mptsas_t *mpt, uint32_t page_address,
@@ -1290,7 +1323,18 @@ int mptsas_get_manufacture_page5(mptsas_t *mpt);
int mptsas_get_sas_port_page0(mptsas_t *mpt, uint32_t page_address,
uint64_t *sas_wwn, uint8_t *portwidth);
int mptsas_get_bios_page3(mptsas_t *mpt, uint32_t *bios_version);
-
+int
+mptsas_get_sas_phy_page0(mptsas_t *mpt, uint32_t page_address,
+ smhba_info_t *info);
+int
+mptsas_get_sas_phy_page1(mptsas_t *mpt, uint32_t page_address,
+ smhba_info_t *info);
+int
+mptsas_get_manufacture_page0(mptsas_t *mpt);
+void
+mptsas_create_phy_stats(mptsas_t *mpt, char *iport, dev_info_t *dip);
+void mptsas_destroy_phy_stats(mptsas_t *mpt);
+int mptsas_smhba_phy_init(mptsas_t *mpt);
/*
* RAID functions
*/