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