1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 /* 25 * This file contains SM-HBA support for PMC-S driver 26 */ 27 28 #include <sys/scsi/adapters/pmcs/pmcs.h> 29 30 31 void 32 pmcs_smhba_add_hba_prop(pmcs_hw_t *pwp, data_type_t dt, 33 char *prop_name, void *prop_val) 34 { 35 ASSERT(pwp != NULL); 36 37 switch (dt) { 38 case DATA_TYPE_INT32: 39 if (ddi_prop_update_int(DDI_DEV_T_NONE, pwp->dip, 40 prop_name, *(int *)prop_val)) { 41 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 42 "%s: %s prop update failed", __func__, prop_name); 43 } 44 break; 45 case DATA_TYPE_STRING: 46 if (ddi_prop_update_string(DDI_DEV_T_NONE, pwp->dip, 47 prop_name, (char *)prop_val)) { 48 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 49 "%s: %s prop update failed", __func__, prop_name); 50 } 51 break; 52 default: 53 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: " 54 "Unhandled datatype(%d) for (%s). Skipping prop update.", 55 __func__, dt, prop_name); 56 } 57 } 58 59 60 /* 61 * Called with iport lock held. 62 */ 63 void 64 pmcs_smhba_add_iport_prop(pmcs_iport_t *iport, data_type_t dt, 65 char *prop_name, void *prop_val) 66 { 67 ASSERT(iport != NULL); 68 ASSERT(mutex_owned(&iport->lock)); 69 70 switch (dt) { 71 case DATA_TYPE_INT32: 72 if (ddi_prop_update_int(DDI_DEV_T_NONE, iport->dip, 73 prop_name, *(int *)prop_val)) { 74 pmcs_prt(iport->pwp, PMCS_PRT_DEBUG, NULL, NULL, 75 "%s: %s prop update failed", __func__, prop_name); 76 } 77 break; 78 case DATA_TYPE_STRING: 79 if (ddi_prop_update_string(DDI_DEV_T_NONE, iport->dip, 80 prop_name, (char *)prop_val)) { 81 pmcs_prt(iport->pwp, PMCS_PRT_DEBUG, NULL, NULL, 82 "%s: %s prop update failed", __func__, prop_name); 83 } 84 break; 85 default: 86 pmcs_prt(iport->pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: " 87 "Unhandled datatype(%d) for(%s). Skipping prop update.", 88 __func__, dt, prop_name); 89 } 90 91 pmcs_smhba_set_phy_props(iport); 92 } 93 94 95 void 96 pmcs_smhba_add_tgt_prop(pmcs_xscsi_t *tgt, data_type_t dt, 97 char *prop_name, void *prop_val) 98 { 99 ASSERT(tgt != NULL); 100 101 switch (dt) { 102 case DATA_TYPE_INT32: 103 if (ddi_prop_update_int(DDI_DEV_T_NONE, tgt->dip, 104 prop_name, *(int *)prop_val)) { 105 pmcs_prt(tgt->pwp, PMCS_PRT_DEBUG, NULL, NULL, 106 "%s: %s prop update failed", __func__, prop_name); 107 } 108 break; 109 case DATA_TYPE_STRING: 110 if (ddi_prop_update_string(DDI_DEV_T_NONE, tgt->dip, 111 prop_name, (char *)prop_val)) { 112 pmcs_prt(tgt->pwp, PMCS_PRT_DEBUG, NULL, NULL, 113 "%s: %s prop update failed", __func__, prop_name); 114 } 115 break; 116 default: 117 pmcs_prt(tgt->pwp, PMCS_PRT_DEBUG, NULL, NULL, "%s: " 118 "Unhandled datatype(%d) for (%s). Skipping prop update.", 119 __func__, dt, prop_name); 120 } 121 } 122 123 /* ARGSUSED */ 124 void 125 pmcs_smhba_set_scsi_device_props(pmcs_hw_t *pwp, pmcs_phy_t *pptr, 126 struct scsi_device *sd) 127 { 128 char *paddr, *addr; 129 int ua_form = 1; 130 uint64_t wwn, pwwn; 131 pmcs_phy_t *pphy; 132 133 pphy = pptr->parent; 134 135 if (pphy != NULL) { 136 paddr = kmem_zalloc(PMCS_MAX_UA_SIZE, KM_SLEEP); 137 pwwn = pmcs_barray2wwn(pphy->sas_address); 138 (void) scsi_wwn_to_wwnstr(pwwn, ua_form, paddr); 139 140 addr = kmem_zalloc(PMCS_MAX_UA_SIZE, KM_SLEEP); 141 wwn = pmcs_barray2wwn(pptr->sas_address); 142 (void) scsi_wwn_to_wwnstr(wwn, ua_form, addr); 143 144 if ((pptr->dtype == SATA) || pptr->virtual) { 145 (void) scsi_device_prop_update_string(sd, 146 SCSI_DEVICE_PROP_PATH, 147 SCSI_ADDR_PROP_BRIDGE_PORT, addr); 148 } 149 if (pphy->dtype == EXPANDER) { 150 (void) scsi_device_prop_update_string(sd, 151 SCSI_DEVICE_PROP_PATH, 152 SCSI_ADDR_PROP_ATTACHED_PORT, paddr); 153 } 154 kmem_free(addr, PMCS_MAX_UA_SIZE); 155 kmem_free(paddr, PMCS_MAX_UA_SIZE); 156 } 157 158 if (pptr->dtype != EXPANDER) { 159 (void) scsi_device_prop_update_int(sd, 160 SCSI_DEVICE_PROP_PATH, SCSI_ADDR_PROP_TARGET_PORT_DEPTH, 161 pptr->level); 162 } 163 } 164 165 void 166 pmcs_smhba_set_phy_props(pmcs_iport_t *iport) 167 { 168 int i; 169 size_t packed_size; 170 char *packed_data; 171 pmcs_hw_t *pwp = iport->pwp; 172 pmcs_phy_t *phy_ptr; 173 nvlist_t **phy_props; 174 nvlist_t *nvl; 175 176 ASSERT(mutex_owned(&iport->lock)); 177 if (iport->nphy == 0) { 178 return; 179 } 180 181 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 182 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 183 "%s: nvlist_alloc() failed", __func__); 184 } 185 186 phy_props = kmem_zalloc(sizeof (nvlist_t *) * iport->nphy, KM_SLEEP); 187 188 for (phy_ptr = list_head(&iport->phys), i = 0; 189 phy_ptr != NULL; 190 phy_ptr = list_next(&iport->phys, phy_ptr), i++) { 191 pmcs_lock_phy(phy_ptr); 192 193 (void) nvlist_alloc(&phy_props[i], NV_UNIQUE_NAME, 0); 194 195 (void) nvlist_add_uint8(phy_props[i], SAS_PHY_ID, 196 phy_ptr->phynum); 197 (void) nvlist_add_int8(phy_props[i], SAS_NEG_LINK_RATE, 198 phy_ptr->link_rate); 199 (void) nvlist_add_int8(phy_props[i], SAS_PROG_MIN_LINK_RATE, 200 phy_ptr->state.prog_min_rate); 201 (void) nvlist_add_int8(phy_props[i], SAS_HW_MIN_LINK_RATE, 202 phy_ptr->state.hw_min_rate); 203 (void) nvlist_add_int8(phy_props[i], SAS_PROG_MAX_LINK_RATE, 204 phy_ptr->state.prog_max_rate); 205 (void) nvlist_add_int8(phy_props[i], SAS_HW_MAX_LINK_RATE, 206 phy_ptr->state.hw_max_rate); 207 208 pmcs_unlock_phy(phy_ptr); 209 } 210 211 (void) nvlist_add_nvlist_array(nvl, SAS_PHY_INFO_NVL, phy_props, 212 iport->nphy); 213 214 (void) nvlist_size(nvl, &packed_size, NV_ENCODE_NATIVE); 215 packed_data = kmem_zalloc(packed_size, KM_SLEEP); 216 (void) nvlist_pack(nvl, &packed_data, &packed_size, 217 NV_ENCODE_NATIVE, 0); 218 219 (void) ddi_prop_update_byte_array(DDI_DEV_T_NONE, iport->dip, 220 SAS_PHY_INFO, (uchar_t *)packed_data, packed_size); 221 222 for (i = 0; i < iport->nphy && phy_props[i] != NULL; i++) { 223 nvlist_free(phy_props[i]); 224 } 225 nvlist_free(nvl); 226 kmem_free(phy_props, sizeof (nvlist_t *) * iport->nphy); 227 kmem_free(packed_data, packed_size); 228 } 229 230 /* 231 * Called with PHY lock held on phyp 232 */ 233 void 234 pmcs_smhba_log_sysevent(pmcs_hw_t *pwp, char *subclass, char *etype, 235 pmcs_phy_t *phyp) 236 { 237 nvlist_t *attr_list; 238 char *pname; 239 char sas_addr[PMCS_MAX_UA_SIZE]; 240 uint8_t phynum = 0; 241 uint8_t lrate = 0; 242 uint64_t wwn; 243 int ua_form = 0; 244 245 if (pwp->dip == NULL) 246 return; 247 if (phyp == NULL) 248 return; 249 250 pname = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP); 251 if (pname == NULL) 252 return; 253 254 if ((strcmp(subclass, ESC_SAS_PHY_EVENT) == 0) || 255 (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0)) { 256 ASSERT(phyp != NULL); 257 (void) strncpy(pname, phyp->path, strlen(phyp->path)); 258 phynum = phyp->phynum; 259 wwn = pmcs_barray2wwn(phyp->sas_address); 260 (void) scsi_wwn_to_wwnstr(wwn, ua_form, sas_addr); 261 if (strcmp(etype, SAS_PHY_ONLINE) == 0) { 262 lrate = phyp->link_rate; 263 } 264 } 265 if (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0) { 266 (void) ddi_pathname(pwp->dip, pname); 267 } 268 269 if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 0) != 0) { 270 pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL, 271 "%s: Failed to post sysevent", __func__); 272 kmem_free(pname, MAXPATHLEN); 273 return; 274 } 275 276 if (nvlist_add_int32(attr_list, SAS_DRV_INST, 277 ddi_get_instance(pwp->dip)) != 0) 278 goto fail; 279 280 if (nvlist_add_string(attr_list, SAS_PORT_ADDR, sas_addr) != 0) 281 goto fail; 282 283 if (nvlist_add_string(attr_list, SAS_DEVFS_PATH, pname) != 0) 284 goto fail; 285 286 if (nvlist_add_uint8(attr_list, SAS_PHY_ID, phynum) != 0) 287 goto fail; 288 289 if (strcmp(etype, SAS_PHY_ONLINE) == 0) { 290 if (nvlist_add_uint8(attr_list, SAS_LINK_RATE, lrate) != 0) 291 goto fail; 292 } 293 294 if (nvlist_add_string(attr_list, SAS_EVENT_TYPE, etype) != 0) 295 goto fail; 296 297 (void) ddi_log_sysevent(pwp->dip, DDI_VENDOR_SUNW, EC_HBA, subclass, 298 attr_list, NULL, DDI_NOSLEEP); 299 300 fail: 301 kmem_free(pname, MAXPATHLEN); 302 nvlist_free(attr_list); 303 } 304