14c06356bSdh /*
24c06356bSdh  * CDDL HEADER START
34c06356bSdh  *
44c06356bSdh  * The contents of this file are subject to the terms of the
54c06356bSdh  * Common Development and Distribution License (the "License").
64c06356bSdh  * You may not use this file except in compliance with the License.
74c06356bSdh  *
84c06356bSdh  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c06356bSdh  * or http://www.opensolaris.org/os/licensing.
104c06356bSdh  * See the License for the specific language governing permissions
114c06356bSdh  * and limitations under the License.
124c06356bSdh  *
134c06356bSdh  * When distributing Covered Code, include this CDDL HEADER in each
144c06356bSdh  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c06356bSdh  * If applicable, add the following below this CDDL HEADER, with the
164c06356bSdh  * fields enclosed by brackets "[]" replaced with your own identifying
174c06356bSdh  * information: Portions Copyright [yyyy] [name of copyright owner]
184c06356bSdh  *
194c06356bSdh  * CDDL HEADER END
20658280b6SDavid Hollister  */
21658280b6SDavid Hollister /*
22658280b6SDavid Hollister  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
234c06356bSdh  */
244c06356bSdh /*
254c06356bSdh  * This file contains SM-HBA support for PMC-S driver
264c06356bSdh  */
274c06356bSdh 
284c06356bSdh #include <sys/scsi/adapters/pmcs/pmcs.h>
294c06356bSdh 
304c06356bSdh 
314c06356bSdh void
pmcs_smhba_add_hba_prop(pmcs_hw_t * pwp,data_type_t dt,char * prop_name,void * prop_val)324c06356bSdh pmcs_smhba_add_hba_prop(pmcs_hw_t *pwp, data_type_t dt,
334c06356bSdh     char *prop_name, void *prop_val)
344c06356bSdh {
354c06356bSdh 	ASSERT(pwp != NULL);
364c06356bSdh 
374c06356bSdh 	switch (dt) {
384c06356bSdh 	case DATA_TYPE_INT32:
394c06356bSdh 		if (ddi_prop_update_int(DDI_DEV_T_NONE, pwp->dip,
404c06356bSdh 		    prop_name, *(int *)prop_val)) {
41c3bc407cSdh 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
424c06356bSdh 			    "%s: %s prop update failed", __func__, prop_name);
434c06356bSdh 		}
444c06356bSdh 		break;
454c06356bSdh 	case DATA_TYPE_STRING:
464c06356bSdh 		if (ddi_prop_update_string(DDI_DEV_T_NONE, pwp->dip,
474c06356bSdh 		    prop_name, (char *)prop_val)) {
48c3bc407cSdh 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
494c06356bSdh 			    "%s: %s prop update failed", __func__, prop_name);
504c06356bSdh 		}
514c06356bSdh 		break;
524c06356bSdh 	default:
53c3bc407cSdh 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: "
54c3bc407cSdh 		    "Unhandled datatype(%d) for (%s). Skipping prop update.",
55c3bc407cSdh 		    __func__, dt, prop_name);
564c06356bSdh 	}
574c06356bSdh }
584c06356bSdh 
594c06356bSdh 
60145e0143Sdh /*
61145e0143Sdh  * Called with iport lock held.
62145e0143Sdh  */
634c06356bSdh void
pmcs_smhba_add_iport_prop(pmcs_iport_t * iport,data_type_t dt,char * prop_name,void * prop_val)644c06356bSdh pmcs_smhba_add_iport_prop(pmcs_iport_t *iport, data_type_t dt,
654c06356bSdh     char *prop_name, void *prop_val)
664c06356bSdh {
674c06356bSdh 	ASSERT(iport != NULL);
68145e0143Sdh 	ASSERT(mutex_owned(&iport->lock));
694c06356bSdh 
704c06356bSdh 	switch (dt) {
714c06356bSdh 	case DATA_TYPE_INT32:
724c06356bSdh 		if (ddi_prop_update_int(DDI_DEV_T_NONE, iport->dip,
734c06356bSdh 		    prop_name, *(int *)prop_val)) {
74c3bc407cSdh 			pmcs_prt(iport->pwp, PMCS_PRT_DEBUG, NULL, NULL,
754c06356bSdh 			    "%s: %s prop update failed", __func__, prop_name);
764c06356bSdh 		}
774c06356bSdh 		break;
784c06356bSdh 	case DATA_TYPE_STRING:
794c06356bSdh 		if (ddi_prop_update_string(DDI_DEV_T_NONE, iport->dip,
804c06356bSdh 		    prop_name, (char *)prop_val)) {
81c3bc407cSdh 			pmcs_prt(iport->pwp, PMCS_PRT_DEBUG, NULL, NULL,
824c06356bSdh 			    "%s: %s prop update failed", __func__, prop_name);
834c06356bSdh 		}
844c06356bSdh 		break;
854c06356bSdh 	default:
86c3bc407cSdh 		pmcs_prt(iport->pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: "
87c3bc407cSdh 		    "Unhandled datatype(%d) for(%s). Skipping prop update.",
884c06356bSdh 		    __func__, dt, prop_name);
894c06356bSdh 	}
90145e0143Sdh 
91145e0143Sdh 	pmcs_smhba_set_phy_props(iport);
924c06356bSdh }
934c06356bSdh 
944c06356bSdh 
954c06356bSdh void
pmcs_smhba_add_tgt_prop(pmcs_xscsi_t * tgt,data_type_t dt,char * prop_name,void * prop_val)964c06356bSdh pmcs_smhba_add_tgt_prop(pmcs_xscsi_t *tgt, data_type_t dt,
974c06356bSdh     char *prop_name, void *prop_val)
984c06356bSdh {
994c06356bSdh 	ASSERT(tgt != NULL);
1004c06356bSdh 
1014c06356bSdh 	switch (dt) {
1024c06356bSdh 	case DATA_TYPE_INT32:
1034c06356bSdh 		if (ddi_prop_update_int(DDI_DEV_T_NONE, tgt->dip,
1044c06356bSdh 		    prop_name, *(int *)prop_val)) {
105c3bc407cSdh 			pmcs_prt(tgt->pwp, PMCS_PRT_DEBUG, NULL, NULL,
1064c06356bSdh 			    "%s: %s prop update failed", __func__, prop_name);
1074c06356bSdh 		}
1084c06356bSdh 		break;
1094c06356bSdh 	case DATA_TYPE_STRING:
1104c06356bSdh 		if (ddi_prop_update_string(DDI_DEV_T_NONE, tgt->dip,
1114c06356bSdh 		    prop_name, (char *)prop_val)) {
112c3bc407cSdh 			pmcs_prt(tgt->pwp, PMCS_PRT_DEBUG, NULL, NULL,
1134c06356bSdh 			    "%s: %s prop update failed", __func__, prop_name);
1144c06356bSdh 		}
1154c06356bSdh 		break;
1164c06356bSdh 	default:
117c3bc407cSdh 		pmcs_prt(tgt->pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: "
118c3bc407cSdh 		    "Unhandled datatype(%d) for (%s). Skipping prop update.",
119c3bc407cSdh 		    __func__, dt, prop_name);
1204c06356bSdh 	}
1214c06356bSdh }
1224c06356bSdh 
1234c06356bSdh /* ARGSUSED */
1244c06356bSdh void
pmcs_smhba_set_scsi_device_props(pmcs_hw_t * pwp,pmcs_phy_t * pptr,struct scsi_device * sd)1254c06356bSdh pmcs_smhba_set_scsi_device_props(pmcs_hw_t *pwp, pmcs_phy_t *pptr,
1264c06356bSdh     struct scsi_device *sd)
1274c06356bSdh {
128*c80dec56SDavid Hollister 	char		*paddr, *addr;
1294c06356bSdh 	int		ua_form = 1;
130*c80dec56SDavid Hollister 	uint64_t	wwn, pwwn;
1314c06356bSdh 	pmcs_phy_t	*pphy;
1324c06356bSdh 
1334c06356bSdh 	pphy = pptr->parent;
1344c06356bSdh 
1354c06356bSdh 	if (pphy != NULL) {
136*c80dec56SDavid Hollister 		paddr = kmem_zalloc(PMCS_MAX_UA_SIZE, KM_SLEEP);
137*c80dec56SDavid Hollister 		pwwn = pmcs_barray2wwn(pphy->sas_address);
138*c80dec56SDavid Hollister 		(void) scsi_wwn_to_wwnstr(pwwn, ua_form, paddr);
139*c80dec56SDavid Hollister 
1404c06356bSdh 		addr = kmem_zalloc(PMCS_MAX_UA_SIZE, KM_SLEEP);
141*c80dec56SDavid Hollister 		wwn = pmcs_barray2wwn(pptr->sas_address);
1424c06356bSdh 		(void) scsi_wwn_to_wwnstr(wwn, ua_form, addr);
1434c06356bSdh 
144*c80dec56SDavid Hollister 		if ((pptr->dtype == SATA) || pptr->virtual) {
1454c06356bSdh 			(void) scsi_device_prop_update_string(sd,
1464c06356bSdh 			    SCSI_DEVICE_PROP_PATH,
1474c06356bSdh 			    SCSI_ADDR_PROP_BRIDGE_PORT, addr);
1484c06356bSdh 		}
1494c06356bSdh 		if (pphy->dtype == EXPANDER) {
1504c06356bSdh 			(void) scsi_device_prop_update_string(sd,
1514c06356bSdh 			    SCSI_DEVICE_PROP_PATH,
152*c80dec56SDavid Hollister 			    SCSI_ADDR_PROP_ATTACHED_PORT, paddr);
1534c06356bSdh 		}
1544c06356bSdh 		kmem_free(addr, PMCS_MAX_UA_SIZE);
155*c80dec56SDavid Hollister 		kmem_free(paddr, PMCS_MAX_UA_SIZE);
1564c06356bSdh 	}
157658280b6SDavid Hollister 
158658280b6SDavid Hollister 	if (pptr->dtype != EXPANDER) {
159658280b6SDavid Hollister 		(void) scsi_device_prop_update_int(sd,
160658280b6SDavid Hollister 		    SCSI_DEVICE_PROP_PATH, SCSI_ADDR_PROP_TARGET_PORT_DEPTH,
161658280b6SDavid Hollister 		    pptr->level);
162658280b6SDavid Hollister 	}
1634c06356bSdh }
1644c06356bSdh 
1654c06356bSdh void
pmcs_smhba_set_phy_props(pmcs_iport_t * iport)1664c06356bSdh pmcs_smhba_set_phy_props(pmcs_iport_t *iport)
1674c06356bSdh {
1684c06356bSdh 	int		i;
1694c06356bSdh 	size_t		packed_size;
1704c06356bSdh 	char		*packed_data;
1714c06356bSdh 	pmcs_hw_t	*pwp = iport->pwp;
1724c06356bSdh 	pmcs_phy_t	*phy_ptr;
1734c06356bSdh 	nvlist_t	**phy_props;
1744c06356bSdh 	nvlist_t	*nvl;
1754c06356bSdh 
176145e0143Sdh 	ASSERT(mutex_owned(&iport->lock));
1774c06356bSdh 	if (iport->nphy == 0) {
1784c06356bSdh 		return;
1794c06356bSdh 	}
1804c06356bSdh 
1814c06356bSdh 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
182c3bc407cSdh 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
183c3bc407cSdh 		    "%s: nvlist_alloc() failed", __func__);
1844c06356bSdh 	}
1854c06356bSdh 
1864c06356bSdh 	phy_props = kmem_zalloc(sizeof (nvlist_t *) * iport->nphy, KM_SLEEP);
1874c06356bSdh 
1884c06356bSdh 	for (phy_ptr = list_head(&iport->phys), i = 0;
1894c06356bSdh 	    phy_ptr != NULL;
1904c06356bSdh 	    phy_ptr = list_next(&iport->phys, phy_ptr), i++) {
1914c06356bSdh 		pmcs_lock_phy(phy_ptr);
1924c06356bSdh 
1934c06356bSdh 		(void) nvlist_alloc(&phy_props[i], NV_UNIQUE_NAME, 0);
1944c06356bSdh 
1954c06356bSdh 		(void) nvlist_add_uint8(phy_props[i], SAS_PHY_ID,
1964c06356bSdh 		    phy_ptr->phynum);
1974c06356bSdh 		(void) nvlist_add_int8(phy_props[i], SAS_NEG_LINK_RATE,
1984c06356bSdh 		    phy_ptr->link_rate);
1994c06356bSdh 		(void) nvlist_add_int8(phy_props[i], SAS_PROG_MIN_LINK_RATE,
2004c06356bSdh 		    phy_ptr->state.prog_min_rate);
2014c06356bSdh 		(void) nvlist_add_int8(phy_props[i], SAS_HW_MIN_LINK_RATE,
2024c06356bSdh 		    phy_ptr->state.hw_min_rate);
2034c06356bSdh 		(void) nvlist_add_int8(phy_props[i], SAS_PROG_MAX_LINK_RATE,
2044c06356bSdh 		    phy_ptr->state.prog_max_rate);
2054c06356bSdh 		(void) nvlist_add_int8(phy_props[i], SAS_HW_MAX_LINK_RATE,
2064c06356bSdh 		    phy_ptr->state.hw_max_rate);
2074c06356bSdh 
2084c06356bSdh 		pmcs_unlock_phy(phy_ptr);
2094c06356bSdh 	}
2104c06356bSdh 
2114c06356bSdh 	(void) nvlist_add_nvlist_array(nvl, SAS_PHY_INFO_NVL, phy_props,
2124c06356bSdh 	    iport->nphy);
2134c06356bSdh 
2144c06356bSdh 	(void) nvlist_size(nvl, &packed_size, NV_ENCODE_NATIVE);
2154c06356bSdh 	packed_data = kmem_zalloc(packed_size, KM_SLEEP);
2164c06356bSdh 	(void) nvlist_pack(nvl, &packed_data, &packed_size,
2174c06356bSdh 	    NV_ENCODE_NATIVE, 0);
2184c06356bSdh 
2194c06356bSdh 	(void) ddi_prop_update_byte_array(DDI_DEV_T_NONE, iport->dip,
2204c06356bSdh 	    SAS_PHY_INFO, (uchar_t *)packed_data, packed_size);
2214c06356bSdh 
2224c06356bSdh 	for (i = 0; i < iport->nphy && phy_props[i] != NULL; i++) {
2234c06356bSdh 		nvlist_free(phy_props[i]);
2244c06356bSdh 	}
2254c06356bSdh 	nvlist_free(nvl);
2264c06356bSdh 	kmem_free(phy_props, sizeof (nvlist_t *) * iport->nphy);
2274c06356bSdh 	kmem_free(packed_data, packed_size);
2284c06356bSdh }
2294c06356bSdh 
2304c06356bSdh /*
2314c06356bSdh  * Called with PHY lock held on phyp
2324c06356bSdh  */
2334c06356bSdh void
pmcs_smhba_log_sysevent(pmcs_hw_t * pwp,char * subclass,char * etype,pmcs_phy_t * phyp)2344c06356bSdh pmcs_smhba_log_sysevent(pmcs_hw_t *pwp, char *subclass, char *etype,
2354c06356bSdh     pmcs_phy_t *phyp)
2364c06356bSdh {
2374c06356bSdh 	nvlist_t	*attr_list;
2384c06356bSdh 	char		*pname;
2394c06356bSdh 	char		sas_addr[PMCS_MAX_UA_SIZE];
2404c06356bSdh 	uint8_t		phynum = 0;
2414c06356bSdh 	uint8_t		lrate = 0;
2424c06356bSdh 	uint64_t	wwn;
2434c06356bSdh 	int		ua_form = 0;
2444c06356bSdh 
2454c06356bSdh 	if (pwp->dip == NULL)
2464c06356bSdh 		return;
2474c06356bSdh 	if (phyp == NULL)
2484c06356bSdh 		return;
2494c06356bSdh 
2504c06356bSdh 	pname = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP);
2514c06356bSdh 	if (pname == NULL)
2524c06356bSdh 		return;
2534c06356bSdh 
2544c06356bSdh 	if ((strcmp(subclass, ESC_SAS_PHY_EVENT) == 0) ||
2554c06356bSdh 	    (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0)) {
2564c06356bSdh 		ASSERT(phyp != NULL);
2574c06356bSdh 		(void) strncpy(pname, phyp->path, strlen(phyp->path));
2584c06356bSdh 		phynum = phyp->phynum;
2594c06356bSdh 		wwn = pmcs_barray2wwn(phyp->sas_address);
2604c06356bSdh 		(void) scsi_wwn_to_wwnstr(wwn, ua_form, sas_addr);
2614c06356bSdh 		if (strcmp(etype, SAS_PHY_ONLINE) == 0) {
2624c06356bSdh 			lrate = phyp->link_rate;
2634c06356bSdh 		}
2644c06356bSdh 	}
2654c06356bSdh 	if (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0) {
2664c06356bSdh 		(void) ddi_pathname(pwp->dip, pname);
2674c06356bSdh 	}
2684c06356bSdh 
2694c06356bSdh 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 0) != 0) {
270c3bc407cSdh 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
271c3bc407cSdh 		    "%s: Failed to post sysevent", __func__);
2724c06356bSdh 		kmem_free(pname, MAXPATHLEN);
2734c06356bSdh 		return;
2744c06356bSdh 	}
2754c06356bSdh 
2764c06356bSdh 	if (nvlist_add_int32(attr_list, SAS_DRV_INST,
2774c06356bSdh 	    ddi_get_instance(pwp->dip)) != 0)
2784c06356bSdh 		goto fail;
2794c06356bSdh 
2804c06356bSdh 	if (nvlist_add_string(attr_list, SAS_PORT_ADDR, sas_addr) != 0)
2814c06356bSdh 		goto fail;
2824c06356bSdh 
2834c06356bSdh 	if (nvlist_add_string(attr_list, SAS_DEVFS_PATH, pname) != 0)
2844c06356bSdh 		goto fail;
2854c06356bSdh 
2864c06356bSdh 	if (nvlist_add_uint8(attr_list, SAS_PHY_ID, phynum) != 0)
2874c06356bSdh 		goto fail;
2884c06356bSdh 
2894c06356bSdh 	if (strcmp(etype, SAS_PHY_ONLINE) == 0) {
2904c06356bSdh 		if (nvlist_add_uint8(attr_list, SAS_LINK_RATE, lrate) != 0)
2914c06356bSdh 			goto fail;
2924c06356bSdh 	}
2934c06356bSdh 
2944c06356bSdh 	if (nvlist_add_string(attr_list, SAS_EVENT_TYPE, etype) != 0)
2954c06356bSdh 		goto fail;
2964c06356bSdh 
2974c06356bSdh 	(void) ddi_log_sysevent(pwp->dip, DDI_VENDOR_SUNW, EC_HBA, subclass,
2984c06356bSdh 	    attr_list, NULL, DDI_NOSLEEP);
2994c06356bSdh 
3004c06356bSdh fail:
3014c06356bSdh 	kmem_free(pname, MAXPATHLEN);
3024c06356bSdh 	nvlist_free(attr_list);
3034c06356bSdh }
304