xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_smhba.c (revision 3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5)
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		*addr;
129 	int		ua_form = 1;
130 	uint64_t	wwn;
131 	pmcs_phy_t	*pphy;
132 
133 	pphy = pptr->parent;
134 
135 	if (pphy != NULL) {
136 		addr = kmem_zalloc(PMCS_MAX_UA_SIZE, KM_SLEEP);
137 		wwn = pmcs_barray2wwn(pphy->sas_address);
138 		(void) scsi_wwn_to_wwnstr(wwn, ua_form, addr);
139 
140 		if (pphy->dtype == SATA) {
141 			(void) scsi_device_prop_update_string(sd,
142 			    SCSI_DEVICE_PROP_PATH,
143 			    SCSI_ADDR_PROP_BRIDGE_PORT, addr);
144 		}
145 		if (pphy->dtype == EXPANDER) {
146 			(void) scsi_device_prop_update_string(sd,
147 			    SCSI_DEVICE_PROP_PATH,
148 			    SCSI_ADDR_PROP_ATTACHED_PORT, addr);
149 		}
150 		kmem_free(addr, PMCS_MAX_UA_SIZE);
151 	}
152 
153 	if (pptr->dtype != EXPANDER) {
154 		(void) scsi_device_prop_update_int(sd,
155 		    SCSI_DEVICE_PROP_PATH, SCSI_ADDR_PROP_TARGET_PORT_DEPTH,
156 		    pptr->level);
157 	}
158 }
159 
160 void
161 pmcs_smhba_set_phy_props(pmcs_iport_t *iport)
162 {
163 	int		i;
164 	size_t		packed_size;
165 	char		*packed_data;
166 	pmcs_hw_t	*pwp = iport->pwp;
167 	pmcs_phy_t	*phy_ptr;
168 	nvlist_t	**phy_props;
169 	nvlist_t	*nvl;
170 
171 	ASSERT(mutex_owned(&iport->lock));
172 	if (iport->nphy == 0) {
173 		return;
174 	}
175 
176 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
177 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
178 		    "%s: nvlist_alloc() failed", __func__);
179 	}
180 
181 	phy_props = kmem_zalloc(sizeof (nvlist_t *) * iport->nphy, KM_SLEEP);
182 
183 	for (phy_ptr = list_head(&iport->phys), i = 0;
184 	    phy_ptr != NULL;
185 	    phy_ptr = list_next(&iport->phys, phy_ptr), i++) {
186 		pmcs_lock_phy(phy_ptr);
187 
188 		(void) nvlist_alloc(&phy_props[i], NV_UNIQUE_NAME, 0);
189 
190 		(void) nvlist_add_uint8(phy_props[i], SAS_PHY_ID,
191 		    phy_ptr->phynum);
192 		(void) nvlist_add_int8(phy_props[i], SAS_NEG_LINK_RATE,
193 		    phy_ptr->link_rate);
194 		(void) nvlist_add_int8(phy_props[i], SAS_PROG_MIN_LINK_RATE,
195 		    phy_ptr->state.prog_min_rate);
196 		(void) nvlist_add_int8(phy_props[i], SAS_HW_MIN_LINK_RATE,
197 		    phy_ptr->state.hw_min_rate);
198 		(void) nvlist_add_int8(phy_props[i], SAS_PROG_MAX_LINK_RATE,
199 		    phy_ptr->state.prog_max_rate);
200 		(void) nvlist_add_int8(phy_props[i], SAS_HW_MAX_LINK_RATE,
201 		    phy_ptr->state.hw_max_rate);
202 
203 		pmcs_unlock_phy(phy_ptr);
204 	}
205 
206 	(void) nvlist_add_nvlist_array(nvl, SAS_PHY_INFO_NVL, phy_props,
207 	    iport->nphy);
208 
209 	(void) nvlist_size(nvl, &packed_size, NV_ENCODE_NATIVE);
210 	packed_data = kmem_zalloc(packed_size, KM_SLEEP);
211 	(void) nvlist_pack(nvl, &packed_data, &packed_size,
212 	    NV_ENCODE_NATIVE, 0);
213 
214 	(void) ddi_prop_update_byte_array(DDI_DEV_T_NONE, iport->dip,
215 	    SAS_PHY_INFO, (uchar_t *)packed_data, packed_size);
216 
217 	for (i = 0; i < iport->nphy && phy_props[i] != NULL; i++) {
218 		nvlist_free(phy_props[i]);
219 	}
220 	nvlist_free(nvl);
221 	kmem_free(phy_props, sizeof (nvlist_t *) * iport->nphy);
222 	kmem_free(packed_data, packed_size);
223 }
224 
225 /*
226  * Called with PHY lock held on phyp
227  */
228 void
229 pmcs_smhba_log_sysevent(pmcs_hw_t *pwp, char *subclass, char *etype,
230     pmcs_phy_t *phyp)
231 {
232 	nvlist_t	*attr_list;
233 	char		*pname;
234 	char		sas_addr[PMCS_MAX_UA_SIZE];
235 	uint8_t		phynum = 0;
236 	uint8_t		lrate = 0;
237 	uint64_t	wwn;
238 	int		ua_form = 0;
239 
240 	if (pwp->dip == NULL)
241 		return;
242 	if (phyp == NULL)
243 		return;
244 
245 	pname = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP);
246 	if (pname == NULL)
247 		return;
248 
249 	if ((strcmp(subclass, ESC_SAS_PHY_EVENT) == 0) ||
250 	    (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0)) {
251 		ASSERT(phyp != NULL);
252 		(void) strncpy(pname, phyp->path, strlen(phyp->path));
253 		phynum = phyp->phynum;
254 		wwn = pmcs_barray2wwn(phyp->sas_address);
255 		(void) scsi_wwn_to_wwnstr(wwn, ua_form, sas_addr);
256 		if (strcmp(etype, SAS_PHY_ONLINE) == 0) {
257 			lrate = phyp->link_rate;
258 		}
259 	}
260 	if (strcmp(subclass, ESC_SAS_HBA_PORT_BROADCAST) == 0) {
261 		(void) ddi_pathname(pwp->dip, pname);
262 	}
263 
264 	if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, 0) != 0) {
265 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
266 		    "%s: Failed to post sysevent", __func__);
267 		kmem_free(pname, MAXPATHLEN);
268 		return;
269 	}
270 
271 	if (nvlist_add_int32(attr_list, SAS_DRV_INST,
272 	    ddi_get_instance(pwp->dip)) != 0)
273 		goto fail;
274 
275 	if (nvlist_add_string(attr_list, SAS_PORT_ADDR, sas_addr) != 0)
276 		goto fail;
277 
278 	if (nvlist_add_string(attr_list, SAS_DEVFS_PATH, pname) != 0)
279 		goto fail;
280 
281 	if (nvlist_add_uint8(attr_list, SAS_PHY_ID, phynum) != 0)
282 		goto fail;
283 
284 	if (strcmp(etype, SAS_PHY_ONLINE) == 0) {
285 		if (nvlist_add_uint8(attr_list, SAS_LINK_RATE, lrate) != 0)
286 			goto fail;
287 	}
288 
289 	if (nvlist_add_string(attr_list, SAS_EVENT_TYPE, etype) != 0)
290 		goto fail;
291 
292 	(void) ddi_log_sysevent(pwp->dip, DDI_VENDOR_SUNW, EC_HBA, subclass,
293 	    attr_list, NULL, DDI_NOSLEEP);
294 
295 fail:
296 	kmem_free(pname, MAXPATHLEN);
297 	nvlist_free(attr_list);
298 }
299