diff options
| author | xun ni - Sun Microsystems - Beijing China <Xun.Ni@Sun.COM> | 2010-04-19 11:31:17 +0800 |
|---|---|---|
| committer | xun ni - Sun Microsystems - Beijing China <Xun.Ni@Sun.COM> | 2010-04-19 11:31:17 +0800 |
| commit | f2e8686e6101ad6ab3df43205537e610151b5434 (patch) | |
| tree | 1a0e61b09d25476c8f2f61481d0da5046b49ca8a /usr/src | |
| parent | 0870f17b1158eef95a9cbc509c015c6467c7cdec (diff) | |
| download | illumos-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/src')
| -rw-r--r-- | usr/src/lib/sun_sas/common/devtree_hba_disco.c | 20 | ||||
| -rw-r--r-- | usr/src/uts/common/Makefile.files | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c | 906 | ||||
| -rw-r--r-- | usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_impl.c | 449 | ||||
| -rw-r--r-- | usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas_smhba.c | 454 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_smhba.h | 79 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/scsi/adapters/mpt_sas/mptsas_var.h | 50 |
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 */ |
