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