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
pmcs_smhba_add_hba_prop(pmcs_hw_t * pwp,data_type_t dt,char * prop_name,void * prop_val)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
pmcs_smhba_add_iport_prop(pmcs_iport_t * iport,data_type_t dt,char * prop_name,void * prop_val)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
pmcs_smhba_add_tgt_prop(pmcs_xscsi_t * tgt,data_type_t dt,char * prop_name,void * prop_val)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
pmcs_smhba_set_scsi_device_props(pmcs_hw_t * pwp,pmcs_phy_t * pptr,struct scsi_device * sd)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
pmcs_smhba_set_phy_props(pmcs_iport_t * iport)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
pmcs_smhba_log_sysevent(pmcs_hw_t * pwp,char * subclass,char * etype,pmcs_phy_t * phyp)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