xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_smhba.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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