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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*LINTLIBRARY*/
28
29 /*
30 * I18N message number ranges
31 * This file: 12000 - 12499
32 * Shared common messages: 1 - 1999
33 */
34
35 /*
36 * This module is part of the Fibre Channel Interface library.
37 */
38
39 /* #define _POSIX_SOURCE 1 */
40
41
42 /* Includes */
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <sys/file.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/mkdev.h>
49 #include <sys/param.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <sys/scsi/scsi.h>
54 #include <dirent.h> /* for DIR */
55 #include <sys/vtoc.h>
56 #include <nl_types.h>
57 #include <strings.h>
58 #include <errno.h>
59 #include <sys/ddi.h> /* for max */
60 #include <fnmatch.h>
61 #include <l_common.h>
62 #include <stgcom.h>
63 #include <l_error.h>
64 #include <g_state.h>
65 #include <g_scsi.h>
66 #include <sys/fibre-channel/ulp/fcp_util.h>
67 #include <sys/fibre-channel/impl/fc_error.h>
68 #include <sys/fibre-channel/impl/fcph.h>
69 #include <sys/socalio.h>
70 #include <libdevinfo.h>
71 #include <ctype.h>
72 #include <devid.h>
73
74 /* Some forward declarations of static functions */
75 /*
76 * becomes extern interface for Tapestry.
77 * static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *);
78 * static int g_get_dev_list(char *, fc_port_dev_t **, int *, int);
79 */
80 static int g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
81 static int g_set_port_state(char *, int);
82 static int g_dev_log_in_out(char *, la_wwn_t, uint16_t);
83 static int g_get_dev_port_state(char *, la_wwn_t, uint32_t *);
84 static void g_free_rls(AL_rls *);
85 static int g_scsi_inquiry_cmd80(int, uchar_t *, int);
86 static int get_fca_inq_dtype(char *, la_wwn_t, uchar_t *);
87 static int g_find_supported_inq_page(int, int);
88 static int wwn_list_name_compare(const void *, const void *);
89 static int devid_get_all(ddi_devid_t, di_node_t, char *,
90 struct mplist_struct **);
91 static int get_multipath(char *, struct dlist **,
92 struct wwn_list_struct *);
93 static int get_multipath_disk(char *, struct dlist **,
94 struct wwn_list_struct *);
95 static void mplist_free(struct mplist_struct *);
96 static int get_wwn_data(di_node_t, uchar_t **, uchar_t **);
97 static int get_dev_path(struct wwn_list_struct **, char *, char *);
98 static int insert_missing_pwwn(char *, struct wwn_list_struct **);
99 static int get_scsi_vhci_port_wwn(char *, uchar_t *);
100 static int search_wwn_entry(struct wwn_list_found_struct *, uchar_t *,
101 uchar_t *);
102 static int add_wwn_entry(struct wwn_list_found_struct **, uchar_t *,
103 uchar_t *);
104 static int string_to_wwn(uchar_t *, uchar_t *);
105 static int get_wwns(char *, uchar_t *, uchar_t *, int *,
106 struct wwn_list_found_struct **);
107
108 /* type for g_dev_map_init related routines */
109
110 #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
111
112 typedef struct impl_map_dev_prop {
113 char prop_name[MAXNAMELEN];
114 int prop_type;
115 int prop_size;
116 void *prop_data;
117 int prop_error;
118 struct impl_map_dev_prop *next;
119 } impl_map_dev_prop_t;
120
121 typedef struct impl_map_dev {
122 int flag;
123 uint_t topo;
124 impl_map_dev_prop_t *prop_list;
125 struct impl_map_dev *parent;
126 struct impl_map_dev *child;
127 struct impl_map_dev *next;
128 } impl_map_dev_t;
129
130 /* Defines */
131 #define VERBPRINT if (verbose) (void) printf
132
133 #define DIR_MATCH_ST "*[0-9+]n"
134 #define DIR_MATCH_SSD "*s2"
135
136 #define PROP_NOEXIST 0
137 #define PROP_EXIST 1
138
139 /* Prototypes */
140 static int create_map(char *, gfc_map_t *, int, int);
141 static char ctoi(char);
142 static int lilp_map_cmp(const void*, const void*);
143 static int devices_get_all(di_node_t, char *, char *,
144 struct wwn_list_struct **);
145 static char *my_devfs_path(di_node_t);
146 static void my_devfs_path_free(char *path);
147 static void copy_wwn_data_to_str(char *, const uchar_t *);
148 static void init_drv(char *, char *, char *);
149
150 /* static for g_dev_map_init related routines */
151
152 static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t,
153 uchar_t *, uchar_t *, int, int);
154 static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int);
155 static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **);
156 static void free_prop_list(impl_map_dev_prop_t **);
157 static void free_child_list(impl_map_dev_t **);
158 static u_longlong_t wwnConversion(uchar_t *wwn);
159
160 uchar_t g_switch_to_alpa[] = {
161 0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
162 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
163 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
164 0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
165 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
166 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
167 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
168 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
169 0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
170 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
171 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
172 0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
173 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
174 };
175
176 uchar_t g_sf_alpa_to_switch[] = {
177 0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
180 0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
181 0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
182 0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
183 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
184 0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
185 0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
186 0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
187 0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
188 0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
189 0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
190 0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
191 0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
193 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
194 0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
195 0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
196 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
197 0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
198 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
199 0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
200 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
201 };
202
203
204
205 /*
206 * Check if device is in the map.
207 *
208 * PARAMS:
209 * map - loop map returned from fc port
210 * tid - device ID for private map or 24-bit alpa for fabric map
211 *
212 * RETURNS:
213 * 1 if device present in the map.
214 * 0 otherwise.
215 *
216 */
217 int
g_device_in_map(gfc_map_t * map,int tid)218 g_device_in_map(gfc_map_t *map, int tid)
219 {
220 int i, j;
221 gfc_port_dev_info_t *dev_ptr;
222
223 dev_ptr = map->dev_addr;
224 if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) ||
225 (map->hba_addr.port_topology == FC_TOP_FABRIC)) {
226 for (i = 0; i < map->count; i++, dev_ptr++) {
227 if (dev_ptr->
228 gfc_port_dev.pub_port.dev_did.port_id == tid) {
229 /* Does not count if WWN == 0 */
230 for (j = 0; j < FC_WWN_SIZE; j++)
231 if (dev_ptr->gfc_port_dev.pub_port.
232 dev_pwwn.raw_wwn[j] != 0)
233 return (1);
234 }
235 }
236 } else {
237 for (i = 0; i < map->count; i++, dev_ptr++) {
238 if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa ==
239 (int)g_switch_to_alpa[tid]) {
240 /* Does not count if WWN == 0 */
241 for (j = 0; j < WWN_SIZE; j++)
242 if (dev_ptr->gfc_port_dev.priv_port.
243 sf_port_wwn[j] != 0)
244 return (1);
245 }
246 }
247 }
248 return (0);
249 }
250
251 /*
252 * Inserts any missing port wwns for mpxio device paths
253 * which are in ONLINE or STANDBY state.
254 */
255 static int
insert_missing_pwwn(char * phys_path,struct wwn_list_struct ** wwn_list_ptr)256 insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr)
257 {
258 mp_pathlist_t pathlist;
259 int i, pathcnt, match;
260 struct wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found;
261 char pwwn1[WWN_S_LEN];
262
263 /*
264 * Now check each scsi_vhci device path to find any missed
265 * port wwns and insert a new wwn list entry for the missed
266 * port wwn
267 */
268 if (g_get_pathlist(phys_path, &pathlist)) {
269 /* Free memory for pathlist before return */
270 S_FREE(pathlist.path_info);
271 return (L_INVALID_PATH);
272 }
273
274 pathcnt = pathlist.path_count;
275 for (i = 0; i < pathcnt; i++) {
276 /*
277 * Just search for ONLINE and STANDBY paths as
278 * those should be the only missing wwn entries.
279 * There is a very small window for an offline
280 * to have occurred between the time we retrieved
281 * the device list and a call to this function.
282 * If that happens, we just won't add it to
283 * the list which is probably a good thing.
284 */
285 if (pathlist.path_info[i].path_state ==
286 MDI_PATHINFO_STATE_ONLINE ||
287 pathlist.path_info[i].path_state ==
288 MDI_PATHINFO_STATE_STANDBY) {
289 (void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
290 WWN_S_LEN - 1);
291 pwwn1[WWN_S_LEN - 1] = '\0';
292 /*
293 * Now search through wwn list for matching
294 * device path AND pwwn
295 * If it's found, continue to next path.
296 * If it's not found, add it the wwn list.
297 */
298 match = 0;
299
300 for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL;
301 wwn_list_s = wwn_list_s->wwn_next) {
302 if (strncmp(phys_path,
303 wwn_list_s->physical_path,
304 strlen(phys_path)) == 0) {
305 wwn_list_found = wwn_list_s;
306 if (strncmp(pwwn1,
307 wwn_list_s->port_wwn_s,
308 WWN_S_LEN) == 0) {
309 match++;
310 break;
311 }
312 }
313 }
314 if (match) {
315 continue;
316 } else {
317 /*
318 * didn't find a match but the mpxio
319 * device is in the list. Retrieve
320 * the info from the wwn_list_found
321 * and add it to the list.
322 */
323 if ((new_wwn = (struct wwn_list_struct *)
324 calloc(1,
325 sizeof (struct wwn_list_struct)))
326 == NULL) {
327 S_FREE(pathlist.path_info);
328 return (L_MALLOC_FAILED);
329 }
330 if ((new_wwn->physical_path = (char *)
331 calloc(1,
332 strlen(wwn_list_found->physical_path)
333 + 1)) == NULL) {
334 S_FREE(pathlist.path_info);
335 return (L_MALLOC_FAILED);
336 }
337 if ((new_wwn->logical_path = (char *)
338 calloc(1,
339 strlen(wwn_list_found->logical_path)
340 + 1)) == NULL) {
341 S_FREE(pathlist.path_info);
342 return (L_MALLOC_FAILED);
343 }
344
345 /*
346 * Insert new_wwn at the beginning of the list.
347 */
348 new_wwn->wwn_next = *wwn_list_ptr;
349 (*wwn_list_ptr)->wwn_prev = new_wwn;
350
351 /* set new starting ptr */
352 *wwn_list_ptr = new_wwn;
353
354 memcpy(new_wwn->physical_path,
355 wwn_list_found->physical_path,
356 strlen(wwn_list_found->physical_path));
357 memcpy(new_wwn->logical_path,
358 wwn_list_found->logical_path,
359 strlen(wwn_list_found->logical_path));
360 /*
361 * Copy found node wwn data to this new entry
362 * Node wwn is required for the wwn_list
363 * however for mpxio devices it is not
364 * relevant as it may apply to multiple
365 * target controllers, so just use what
366 * we already have in wwn_list_found.
367 */
368 memcpy(new_wwn->node_wwn_s,
369 wwn_list_found->node_wwn_s, WWN_S_LEN);
370 memcpy(new_wwn->w_node_wwn,
371 wwn_list_found->w_node_wwn, WWN_SIZE);
372 new_wwn->device_type =
373 wwn_list_found->device_type;
374 memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN);
375 }
376 }
377 }
378 S_FREE(pathlist.path_info);
379 return (0);
380 }
381
382 /*
383 * gets the port wwn for a scsi_vhci device using ONLINE path priority
384 */
385 static int
get_scsi_vhci_port_wwn(char * phys_path,uchar_t * port_wwn)386 get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn)
387 {
388 mp_pathlist_t pathlist;
389 int i, pathcnt, found;
390 char pwwn1[WWN_S_LEN];
391
392 if (g_get_pathlist(phys_path, &pathlist)) {
393 return (L_INVALID_PATH);
394 }
395
396 found = 0;
397 pathcnt = pathlist.path_count;
398 /*
399 * Look for an ONLINE path first.
400 * If that fails, get the STANDBY path port WWN
401 * If that fails, give up
402 */
403 for (i = 0; found == 0 && i < pathcnt; i++) {
404 if (pathlist.path_info[i].path_state ==
405 MDI_PATHINFO_STATE_ONLINE) {
406 (void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
407 WWN_S_LEN - 1);
408 pwwn1[WWN_S_LEN - 1] = '\0';
409 found++;
410 }
411 }
412
413 for (i = 0; found == 0 && i < pathcnt; i++) {
414 if (pathlist.path_info[i].path_state ==
415 MDI_PATHINFO_STATE_STANDBY) {
416 (void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
417 WWN_S_LEN - 1);
418 pwwn1[WWN_S_LEN - 1] = '\0';
419 found++;
420 }
421 }
422
423 S_FREE(pathlist.path_info);
424 if (found) {
425 return (string_to_wwn((uchar_t *)pwwn1, port_wwn));
426 } else {
427 return (-1);
428 }
429 }
430
431 /*
432 * searches wwn_list_found for the pwwn passed in
433 * and sets the corresponding nwwn on return.
434 * If no match is found, -1 is returned and nwwn is not set.
435 */
436 static int
search_wwn_entry(struct wwn_list_found_struct * wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)437 search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn,
438 uchar_t *nwwn)
439 {
440 struct wwn_list_found_struct *wwn_list_s;
441
442 for (wwn_list_s = wwn_list_found; wwn_list_s != NULL;
443 wwn_list_s = wwn_list_s->wwn_next) {
444 if (memcmp(pwwn, wwn_list_s->port_wwn, WWN_SIZE) == 0) {
445 memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE);
446 return (0);
447 }
448 }
449 return (-1);
450 }
451
452 /*
453 * adds a nwwn, pwwn entry to the next entry in wwn_list_found list
454 */
455 static int
add_wwn_entry(struct wwn_list_found_struct ** wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)456 add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn,
457 uchar_t *nwwn)
458 {
459 struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL;
460
461 /* Got wwns, load data in list */
462 if ((new_wwn = (struct wwn_list_found_struct *)
463 calloc(1, sizeof (struct wwn_list_found_struct))) == NULL) {
464 return (L_MALLOC_FAILED);
465 }
466
467 memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE);
468 memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE);
469
470 /*
471 * Insert new_wwn in the list
472 */
473 if (*wwn_list_found != NULL) {
474 temp_wwn_list_found = (*wwn_list_found)->wwn_next;
475 (*wwn_list_found)->wwn_next = new_wwn;
476 } else {
477 *wwn_list_found = new_wwn;
478 }
479 new_wwn->wwn_next = temp_wwn_list_found;
480
481 return (0);
482 }
483
484
485 /*
486 * Create a linked list of all the WWN's for all FC_AL disks and
487 * tapes that are attached to this host.
488 *
489 * RETURN VALUES: 0 O.K.
490 *
491 * wwn_list pointer:
492 * NULL: No devices found.
493 * !NULL: Devices found
494 * wwn_list points to a linked list of wwn's.
495 */
496 int
g_get_wwn_list(struct wwn_list_struct ** wwn_list_ptr,int verbose)497 g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose)
498 {
499 struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL;
500 struct wwn_list_found_struct *wwn_list_found = NULL;
501 int err;
502 int al_pa;
503 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
504 hrtime_t start_time, end_time;
505 char *env = NULL;
506
507 /* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */
508 if (wwn_list_ptr == NULL) {
509 return (L_NULL_WWN_LIST);
510 }
511
512 if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
513 start_time = gethrtime();
514 }
515
516 if ((err = g_devices_get_all(wwn_list_ptr)) != 0) {
517 return (err);
518 }
519
520 /*
521 * retain backward compatibility with g_get_wwn_list
522 * and retrieve the WWN for scsi_vhci devices in the
523 * same fashion
524 * Note that for scsi_vhci devices, the wwn fields are
525 * not relevant but in the previous versions
526 * we loaded the wwns so...
527 */
528 wwn_list_p = *wwn_list_ptr;
529 while (wwn_list_p != NULL) {
530 if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
531 /* get port wwn of first ONLINE, STANDBY */
532 if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path,
533 port_wwn)) == 0) {
534 if ((search_wwn_entry(wwn_list_found, port_wwn,
535 node_wwn)) != 0) {
536 if ((err =
537 get_wwns(wwn_list_p->physical_path,
538 port_wwn,
539 node_wwn, &al_pa,
540 &wwn_list_found)) != 0) {
541 g_free_wwn_list_found(
542 &wwn_list_found);
543 return (err);
544 }
545 }
546 } else {
547 /* Use g_get_wwn as a last resort */
548 if ((err = g_get_wwn(wwn_list_p->physical_path,
549 port_wwn, node_wwn, &al_pa, 0)) != 0) {
550 /*
551 * this is a bad WWN.
552 * remove it from the wwn_list.
553 *
554 * After removing the bad WWN,
555 * wwn_list_p should point to the next
556 * node in the list.
557 */
558 if ((wwn_list_p->wwn_prev == NULL) &&
559 (wwn_list_p->wwn_next == NULL)) {
560 *wwn_list_ptr = NULL;
561 free(wwn_list_p);
562 g_free_wwn_list_found(
563 &wwn_list_found);
564 return (L_NO_DEVICES_FOUND);
565 } else if (
566 wwn_list_p->wwn_prev == NULL) {
567 *wwn_list_ptr =
568 wwn_list_p->wwn_next;
569 free(wwn_list_p);
570 wwn_list_p = *wwn_list_ptr;
571 wwn_list_p->wwn_prev = NULL;
572 } else if (
573 wwn_list_p->wwn_next == NULL) {
574 wwn_list_p->wwn_prev->wwn_next =
575 NULL;
576 free(wwn_list_p);
577 wwn_list_p = NULL;
578 } else {
579 wwn_list_tmp_p =
580 wwn_list_p->wwn_next;
581 wwn_list_p->wwn_prev->wwn_next =
582 wwn_list_p->wwn_next;
583 wwn_list_p->wwn_next->wwn_prev =
584 wwn_list_p->wwn_prev;
585 free(wwn_list_p);
586 wwn_list_p = wwn_list_tmp_p;
587 }
588 continue;
589 }
590 }
591 copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn);
592 copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn);
593 memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE);
594 }
595 wwn_list_p = wwn_list_p->wwn_next;
596 }
597 g_free_wwn_list_found(&wwn_list_found);
598
599 /*
600 * Now go through the list one more time to add entries for
601 * any missing port wwns.
602 * This allows a search on port wwn for any paths which are
603 * ONLINE or STANDBY. We don't care about OFFLINE as those won't
604 * and should not show up in the list
605 */
606 for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL;
607 wwn_list_p = wwn_list_p->wwn_next) {
608 if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
609 if ((err = insert_missing_pwwn(
610 wwn_list_p->physical_path, wwn_list_ptr)) != 0)
611 return (err);
612 }
613 }
614
615 if (env != NULL) {
616 end_time = gethrtime();
617 fprintf(stdout, " g_get_wwn_list: "
618 "\t\tTime = %lld millisec\n",
619 (end_time - start_time)/1000000);
620 }
621 return (0);
622
623 }
624
625 int
g_devices_get_all(struct wwn_list_struct ** wwn_list_ptr)626 g_devices_get_all(struct wwn_list_struct **wwn_list_ptr)
627 {
628 struct wwn_list_struct *tape_ptr = NULL;
629 struct wwn_list_struct *tmp;
630 int err;
631 di_node_t root;
632 hrtime_t start_time, end_time;
633 char *env = NULL;
634
635 if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
636 start_time = gethrtime();
637 }
638
639 /*
640 * Try to prime di_drv_first_node()
641 * If there are no nodes bound, di_drv_first_node()
642 * will return nothing.
643 */
644 init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST);
645 init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD);
646
647 if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
648 return (L_DEV_SNAPSHOT_FAILED);
649 }
650
651 if (env != NULL) {
652 end_time = gethrtime();
653 fprintf(stdout, " di_init - /: "
654 "\t\tTime = %lld millisec\n",
655 (end_time - start_time)/1000000);
656 }
657
658 if (env != NULL) {
659 start_time = gethrtime();
660 }
661
662 if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME,
663 wwn_list_ptr)) != 0) {
664 if (err != L_NO_DEVICES_FOUND) {
665 di_fini(root);
666 g_free_wwn_list(&tape_ptr);
667 g_free_wwn_list(wwn_list_ptr);
668 return (err);
669 }
670 }
671
672 if (env != NULL) {
673 end_time = gethrtime();
674 fprintf(stdout, " devices_get_all - ssd: "
675 "\t\tTime = %lld millisec\n",
676 (end_time - start_time)/1000000);
677 }
678
679 if (env != NULL) {
680 start_time = gethrtime();
681 }
682
683 if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME,
684 &tape_ptr)) != 0) {
685 di_fini(root);
686 if (err != L_NO_DEVICES_FOUND) {
687 g_free_wwn_list(&tape_ptr);
688 g_free_wwn_list(wwn_list_ptr);
689 return (err);
690 } else {
691 /*
692 * if *wwn_list_ptr == NULL
693 * we have disks but no tapes
694 * Just return
695 */
696 if (*wwn_list_ptr != NULL) {
697 return (0);
698 } else {
699 /*
700 * No disks or tapes
701 */
702 g_free_wwn_list(&tape_ptr);
703 g_free_wwn_list(wwn_list_ptr);
704 return (err);
705 }
706 }
707 }
708
709 if (env != NULL) {
710 end_time = gethrtime();
711 fprintf(stdout, " devices_get_all - st: "
712 "\t\tTime = %lld millisec\n",
713 (end_time - start_time)/1000000);
714 }
715
716 /* Now link the two together */
717 if (*wwn_list_ptr != NULL) { /* We have both disks and tapes */
718 /* Walk to the end of it */
719 for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL;
720 tmp = tmp->wwn_next)
721 ;
722 tmp->wwn_next = tape_ptr;
723 tape_ptr->wwn_prev = tmp;
724 di_fini(root);
725 return (0);
726 }
727
728 /* else we have no disks */
729 *wwn_list_ptr = tape_ptr;
730 di_fini(root);
731 return (0);
732 }
733
734 void
g_free_wwn_list_found(struct wwn_list_found_struct ** wwn_list_found)735 g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found) {
736 WWN_list_found *next = NULL;
737
738 /* return if wwn_list_found is NULL */
739 if (wwn_list_found == NULL) {
740 return;
741 }
742 for (; *wwn_list_found != NULL; *wwn_list_found = next) {
743 next = (*wwn_list_found)->wwn_next;
744 g_destroy_data(*wwn_list_found);
745 *wwn_list_found = NULL;
746 }
747 }
748
749 void
g_free_wwn_list(struct wwn_list_struct ** wwn_list)750 g_free_wwn_list(struct wwn_list_struct **wwn_list)
751 {
752 WWN_list *next = NULL;
753
754 /* return if wwn_list is NULL */
755 if (wwn_list == NULL) {
756 return;
757 }
758
759 for (; *wwn_list != NULL; *wwn_list = next) {
760 next = (*wwn_list)->wwn_next;
761 if ((*wwn_list)->physical_path != NULL)
762 (void) g_destroy_data((*wwn_list)->physical_path);
763 if ((*wwn_list)->logical_path != NULL)
764 (void) g_destroy_data((*wwn_list)->logical_path);
765 (void) g_destroy_data(*wwn_list);
766 }
767 wwn_list = NULL;
768 }
769
770
771
772
773 void
g_sort_wwn_list(struct wwn_list_struct ** wwn_list)774 g_sort_wwn_list(struct wwn_list_struct **wwn_list)
775 {
776 int i, n;
777 struct wwn_list_struct **wwn_list_array;
778 struct wwn_list_struct *wwn_list_ptr;
779 struct wwn_list_struct **wwn_list_array_ptr1;
780 struct wwn_list_struct **wwn_list_array_ptr2;
781
782 /*
783 * Count the number of wwn_list in the list
784 */
785 for (n = 0, wwn_list_ptr = *wwn_list;
786 wwn_list_ptr != NULL;
787 wwn_list_ptr = wwn_list_ptr->wwn_next) {
788 n++;
789 }
790 if (n <= 1) {
791 return;
792 }
793
794 /*
795 * Allocate a simple wwn_list array and fill it in
796 */
797 wwn_list_array = (struct wwn_list_struct **)
798 g_zalloc((n+1) * sizeof (struct wwn_list_struct *));
799
800 wwn_list_array_ptr1 = wwn_list_array;
801 for (wwn_list_ptr = *wwn_list;
802 wwn_list_ptr != NULL;
803 wwn_list_ptr = wwn_list_ptr->wwn_next) {
804 *wwn_list_array_ptr1++ = wwn_list_ptr;
805 }
806 *wwn_list_array_ptr1 = NULL;
807
808 /*
809 * Sort the wwn_list array
810 */
811 qsort((void *) wwn_list_array, n,
812 sizeof (struct wwn_list_struct *), wwn_list_name_compare);
813
814 /*
815 * Rebuild the linked list wwn_list structure
816 */
817 wwn_list_array_ptr1 = wwn_list_array;
818 *wwn_list = *wwn_list_array_ptr1;
819 wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1;
820 (*wwn_list_array_ptr1)->wwn_prev = NULL;
821 for (i = 0; i < n - 1; i++) {
822 (*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1;
823 (*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++;
824 }
825 (*wwn_list_array_ptr1)->wwn_next = NULL;
826
827 /*
828 * Clean up
829 */
830 (void) g_destroy_data((void *)wwn_list_array);
831 }
832
833 int
wwn_list_name_compare(const void * arg1,const void * arg2)834 wwn_list_name_compare(const void *arg1, const void *arg2)
835 {
836 char *s1, *s2;
837 int n1, n2;
838 char *p1, *p2;
839
840 s1 = (*((struct wwn_list_struct **)arg1))->logical_path;
841 s2 = (*((struct wwn_list_struct **)arg2))->logical_path;
842 for (;;) {
843 if (*s1 == 0 || *s2 == 0)
844 break;
845 if ((isdigit(*s1) && isdigit(*s2))) {
846 n1 = strtol(s1, &p1, 10);
847 n2 = strtol(s2, &p2, 10);
848 if (n1 != n2) {
849 return (n1 - n2);
850 }
851 s1 = p1;
852 s2 = p2;
853 } else if (*s1 != *s2) {
854 break;
855 } else {
856 s1++;
857 s2++;
858 }
859 }
860 return (*s1 - *s2);
861 }
862
863 /*
864 * Get the limited map for FC4 devices.
865 * This function is specific to FC4
866 * devices and doesn't work for FC (leadville) devices.
867 *
868 * RETURN VALUES:
869 * 0 O.K.
870 * non-zero otherwise
871 *
872 * lilpmap *map_ptr:
873 * NULL: No devices found
874 * !NULL: if devices found
875 */
876 int
g_get_limited_map(char * path,struct lilpmap * map_ptr,int verbose)877 g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose)
878 {
879 int fd, i;
880 char drvr_path[MAXPATHLEN];
881 struct stat stbuf;
882
883
884 /* initialize map */
885 (void) memset(map_ptr, 0, sizeof (struct lilpmap));
886
887 (void) strcpy(drvr_path, path);
888 /*
889 * Get the path to the :devctl driver
890 *
891 * This assumes the path looks something like this:
892 * /devices/sbus@1f,0/SUNW,socal@1,0:1
893 * or
894 * /devices/sbus@1f,0/SUNW,socal@1,0
895 * or
896 * a 1 level PCI type driver
897 */
898 if (stat(drvr_path, &stbuf) < 0) {
899 return (L_LSTAT_ERROR);
900 }
901 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
902 /* append a port. Just try 0 since they did not give us one */
903 (void) strcat(drvr_path, ":0");
904 }
905
906 P_DPRINTF(" g_get_limited_map: Geting drive map from:"
907 " %s\n", drvr_path);
908
909 /* open controller */
910 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
911 return (L_OPEN_PATH_FAIL);
912
913 if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) {
914 I_DPRINTF(" FCIO_GETMAP ioctl failed\n");
915 (void) close(fd);
916 return (L_FCIO_GETMAP_IOCTL_FAIL);
917 }
918 (void) close(fd);
919
920 /*
921 * Check for reasonableness.
922 */
923 if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) {
924 return (L_INVALID_LOOP_MAP);
925 }
926 for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) {
927 if (map_ptr->lilp_list[i] > 0xef) {
928 return (L_INVALID_LOOP_MAP);
929 }
930 }
931
932 return (0);
933 }
934
935
936 /*
937 * For leadville specific HBA's ONLY.
938 * Get the host specific parameters,
939 * al_pa, hard address, node/port WWN etc.
940 *
941 * OUTPUT:
942 * fc_port_dev_t structure.
943 *
944 * RETURNS:
945 * 0 if OK
946 * non-zero in case of error.
947 */
948 int
g_get_host_params(char * host_path,fc_port_dev_t * host_val,int verbose)949 g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose)
950 {
951 int err;
952 int fd;
953 int dev_type;
954 fcio_t fcio;
955
956 /* return invalid path if host_path is NULL */
957 if (host_path == NULL) {
958 return (L_INVALID_PATH);
959 }
960 /* return invalid arg if host_val is NULL */
961 if (host_val == NULL) {
962 return (L_INVALID_ARG);
963 }
964
965 dev_type = g_get_path_type(host_path);
966 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
967 return (L_INVALID_PATH_TYPE);
968 }
969 if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) {
970 return (L_OPEN_PATH_FAIL);
971 }
972
973 /* initialize structure */
974 (void) memset(host_val, 0, sizeof (struct fc_port_dev));
975
976 fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
977 fcio.fcio_xfer = FCIO_XFER_READ;
978 fcio.fcio_obuf = (caddr_t)host_val;
979 fcio.fcio_olen = sizeof (fc_port_dev_t);
980
981 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
982 I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
983 (void) close(fd);
984 return (L_FCIO_GET_HOST_PARAMS_FAIL);
985 }
986 (void) close(fd);
987
988 /* get the inquiry information for the leadville HBA. */
989 if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn,
990 &host_val->dev_dtype)) != 0) {
991 return (err);
992 }
993 return (0);
994 }
995
996
997
998 /*
999 * Issue FCIO ioctls to the port(fp) driver.
1000 * FCIO ioctl needs to be retried when it
1001 * is returned with an EINVAL error, wait
1002 * time between retries should be atleast
1003 * WAIT_FCIO_IOCTL (too much of a time to wait!!)
1004 *
1005 * OUTPUT:
1006 * fcio_t structure
1007 *
1008 * RETURNS:
1009 * 0 if O.K.
1010 * non-zero otherwise.
1011 */
1012 int
g_issue_fcio_ioctl(int fd,fcio_t * fcio,int verbose)1013 g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose)
1014 {
1015 int ntries;
1016
1017 for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
1018 if (ioctl(fd, FCIO_CMD, fcio) != 0) {
1019 if ((errno == EAGAIN) &&
1020 (ntries+1 < RETRY_FCIO_IOCTL)) {
1021 /* wait WAIT_FCIO_IOCTL */
1022 (void) usleep(WAIT_FCIO_IOCTL);
1023 continue;
1024 }
1025 I_DPRINTF("FCIO ioctl failed.\n"
1026 "Error: %s. fc_error = %d (0x%x)\n",
1027 strerror(errno), fcio->fcio_errno,
1028 fcio->fcio_errno);
1029 if (errno == EINVAL) {
1030 if (fcio->fcio_errno == FC_TOOMANY) {
1031 return (L_INVALID_DEVICE_COUNT);
1032 } else {
1033 return (errno);
1034 }
1035 }
1036 /*
1037 * When port is offlined, qlc
1038 * returns the FC_OFFLINE error and errno
1039 * is set to EIO.
1040 * We do want to ignore this error,
1041 * especially when an enclosure is
1042 * removed from the loop.
1043 */
1044 if (fcio->fcio_errno == FC_OFFLINE)
1045 break;
1046 return (-1);
1047 }
1048 break;
1049 }
1050
1051 return (0);
1052 }
1053
1054 /*
1055 * This function issues the FCP_TGT_INQUIRY ioctl to
1056 * the fcp module
1057 *
1058 * OUTPUT:
1059 * fcp_ioctl structure in fcp_data is filled in by fcp
1060 *
1061 * RETURN VALUES :
1062 * 0 on Success
1063 * Non-zero otherwise
1064 */
1065 static int
g_issue_fcp_ioctl(int fd,struct fcp_ioctl * fcp_data,int verbose)1066 g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose)
1067 {
1068 int num_tries = 0;
1069 struct device_data *dev_data = NULL;
1070
1071 /*
1072 * Issue the ioctl to FCP
1073 * The retries are required because the driver may
1074 * need some time to respond at times.
1075 */
1076 while (num_tries++ < RETRY_FCP_IOCTL) {
1077 /* if ioctl fails it is an error from Solaris operation. */
1078 if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) {
1079 if (errno == EAGAIN) {
1080 (void) usleep(WAIT_FCP_IOCTL);
1081 continue;
1082 } else {
1083 break;
1084 }
1085 }
1086 dev_data = (struct device_data *)((void *)(fcp_data->list));
1087 if (dev_data->dev_status == 0) {
1088 return (0);
1089 }
1090
1091 if (dev_data->dev_status == EAGAIN) {
1092 (void) usleep(WAIT_FCP_IOCTL);
1093 continue;
1094 } else {
1095 dev_data->dev0_type = DTYPE_UNKNOWN;
1096 return (0);
1097 }
1098 }
1099
1100 return (L_FCP_TGT_INQUIRY_FAIL);
1101 }
1102
1103 /*
1104 * Get the number of devices and also
1105 * a list of devices accessible through
1106 * the device's port as specified by path.
1107 * The calling function * is responsible for freeing the dev_list.
1108 *
1109 * Acquires inq_dtype from g_get_inq_dtype() and
1110 * stores into dev_dtype field of fc_port_dev.
1111 *
1112 * For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login
1113 * and get inq dtype.
1114 *
1115 * dev_list:
1116 * NULL: No devices found, in case of an error
1117 * Non-NULL: Devices found.
1118 * ndevs:
1119 * set to the number of devices
1120 * accessible through the port.
1121 *
1122 * RETURNS:
1123 * 0 if O.K.
1124 * non-zero otherwise
1125 */
1126 int
g_get_dev_list(char * path,fc_port_dev_t ** dev_list,int * ndevs)1127 g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs)
1128 {
1129 int num_devices = 0;
1130 int i, err, ulp_failure = 0, new_count = 0;
1131 int dev_type;
1132 int fd;
1133 char fcapath[MAXPATHLEN];
1134 char *char_ptr;
1135 struct stat stbuf;
1136 fcio_t fcio;
1137 uint32_t port_top;
1138 fc_port_dev_t *dlist;
1139
1140 *dev_list = dlist = NULL;
1141 (void) strcpy(fcapath, path);
1142 /*
1143 * Get the path to the :devctl driver
1144 *
1145 * This assumes the path looks something like this:
1146 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1147 * or
1148 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1149 * or
1150 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1151 * or
1152 * a 1 level PCI type driver but still :devctl
1153 */
1154 if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) {
1155 if ((char_ptr = strrchr(fcapath, '/')) == NULL) {
1156 return (L_INVALID_PATH);
1157 }
1158 *char_ptr = '\0'; /* Terminate sting */
1159 /* append controller */
1160 (void) strcat(fcapath, FC_CTLR);
1161 } else {
1162 if (stat(fcapath, &stbuf) < 0) {
1163 return (L_LSTAT_ERROR);
1164 }
1165 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1166 /* append controller */
1167 (void) strcat(fcapath, FC_CTLR);
1168 }
1169 }
1170 dev_type = g_get_path_type(fcapath);
1171 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1172 return (L_INVALID_PATH_TYPE);
1173 }
1174 if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1175 return (L_OPEN_PATH_FAIL);
1176 }
1177
1178 /*
1179 * Get the device list from port driver
1180 */
1181 fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
1182 fcio.fcio_olen = sizeof (num_devices);
1183 fcio.fcio_xfer = FCIO_XFER_READ;
1184 fcio.fcio_obuf = (caddr_t)&num_devices;
1185 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
1186 I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
1187 (void) close(fd);
1188 return (L_FCIO_GET_NUM_DEVS_FAIL);
1189 }
1190 if (num_devices == 0) {
1191 *ndevs = 0;
1192 (void) close(fd);
1193 return (L_NO_DEVICES_FOUND);
1194 }
1195
1196 if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1197 sizeof (fc_port_dev_t))) == NULL) {
1198 (void) close(fd);
1199 return (L_MALLOC_FAILED);
1200 }
1201 bzero((caddr_t)&fcio, sizeof (fcio));
1202 /* Get the device list */
1203 fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1204 /* Information read operation */
1205 fcio.fcio_xfer = FCIO_XFER_READ;
1206 fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1207 fcio.fcio_obuf = (caddr_t)dlist;
1208 /* new device count */
1209 fcio.fcio_alen = sizeof (new_count);
1210 fcio.fcio_abuf = (caddr_t)&new_count;
1211 if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1212 if (err == L_INVALID_DEVICE_COUNT) {
1213 /*
1214 * original buffer was small so allocate buffer
1215 * with a new count and retry.
1216 */
1217 free(dlist);
1218 num_devices = new_count;
1219 new_count = 0;
1220 if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1221 sizeof (fc_port_dev_t))) == NULL) {
1222 (void) close(fd);
1223 return (L_MALLOC_FAILED);
1224 }
1225 fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1226 /* Information read operation */
1227 fcio.fcio_xfer = FCIO_XFER_READ;
1228 fcio.fcio_obuf = (caddr_t)dlist;
1229 fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1230 /* new device count */
1231 fcio.fcio_alen = sizeof (new_count);
1232 fcio.fcio_abuf = (caddr_t)&new_count;
1233 if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1234 if (err == L_INVALID_DEVICE_COUNT) {
1235 /*
1236 * No more retry. There may be severe
1237 * hardware problem so return error
1238 * here.
1239 */
1240 I_DPRINTF(" Device count was %d"
1241 " should have been %d\n",
1242 num_devices, new_count);
1243 } else {
1244 I_DPRINTF(
1245 " FCIO_GET_DEV_LIST ioctl failed.");
1246 err = L_FCIO_GET_DEV_LIST_FAIL;
1247 }
1248 free(dlist);
1249 (void) close(fd);
1250 return (err);
1251 }
1252 } else {
1253 I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
1254 free(dlist);
1255 (void) close(fd);
1256 return (L_FCIO_GET_DEV_LIST_FAIL);
1257 }
1258 }
1259
1260 /*
1261 * if new count is smaller than the original number from
1262 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
1263 * and continue.
1264 */
1265 if (new_count < num_devices) {
1266 if (new_count == 0) {
1267 *ndevs = 0;
1268 (void) close(fd);
1269 S_FREE(dlist);
1270 return (L_NO_DEVICES_FOUND);
1271 }
1272 num_devices = new_count;
1273 if ((dlist = (fc_port_dev_t *)realloc(dlist,
1274 (new_count * sizeof (fc_port_dev_t))))
1275 == NULL) {
1276 S_FREE(dlist);
1277 (void) close(fd);
1278 return (L_MALLOC_FAILED);
1279 }
1280 }
1281
1282 *dev_list = dlist;
1283 *ndevs = num_devices;
1284
1285 /* close here since fcapath will be passed to other routines. */
1286 (void) close(fd);
1287
1288 if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1289 free(*dev_list);
1290 *dev_list = NULL;
1291 return (err);
1292 }
1293
1294 /* Get the inq_dtype for each device on dev list. */
1295 for (i = 0; i < num_devices; i++, dlist++) {
1296 /* Get the inq_dtype for each device. */
1297 if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn,
1298 &dlist->dev_dtype)) != 0) {
1299 /*
1300 * if g_get_inq_dtype failed on g_dev_login
1301 * or g_issue_fcp_ioctl, continue to the next
1302 * dev on dlist.
1303 * L_GET_DEV_LIST_ULP_FAILURE is returned
1304 * after processing the whole dlist.
1305 */
1306 if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
1307 (err == L_FCP_TGT_INQUIRY_FAIL)) {
1308 ulp_failure = 1;
1309 dlist->dev_dtype = GFC_ERR_INQ_DTYPE;
1310 } else {
1311 (void) free(*dev_list);
1312 *dev_list = NULL;
1313 return (err);
1314 }
1315 }
1316 }
1317
1318 if (ulp_failure) {
1319 return (L_GET_DEV_LIST_ULP_FAILURE);
1320 } else {
1321 return (0);
1322 }
1323 }
1324
1325
1326 /* Constant used by g_get_inq_dtype() */
1327 #define FCP_PATH "/devices/pseudo/fcp@0:fcp"
1328
1329 /*
1330 * Gets the inq_dtype for devices on the fabric FC driver
1331 * through an ioctl to the FCP module.
1332 *
1333 * OUTPUT:
1334 * inq_dtype is set to the dtype on success
1335 *
1336 * RETURN VALUES:
1337 * 0 on Success
1338 * Non-zero on error
1339 */
1340 int
g_get_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)1341 g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1342 {
1343 int dev_type, fd;
1344 int err, fcp_fd;
1345 uint32_t state;
1346 uint32_t port_top = 0;
1347 struct fcp_ioctl fcp_data;
1348 struct device_data inq_data;
1349 struct stat sbuf;
1350
1351 dev_type = g_get_path_type(fcapath);
1352 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1353 return (L_INVALID_PATH_TYPE);
1354 }
1355
1356 if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1357 return (err);
1358 }
1359
1360 if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) {
1361 /*
1362 * if there is an error on getting port state we will
1363 * continue to login.
1364 * state can be either of
1365 * PORT_DEVICE_INVALID, PORT_DEVICE_VALID,
1366 * PORT_DEVICE_LOGGED_IN. Trying port login
1367 * unless already logged in.
1368 * It will be examined if there is an adverse
1369 * effect on invalid state device.
1370 */
1371 if (((err = g_get_dev_port_state(fcapath, pwwn, &state))
1372 != 0) || (state != PORT_DEVICE_LOGGED_IN)) {
1373 /* do port login to fabric device. */
1374 if ((err = g_dev_login(fcapath, pwwn)) != 0) {
1375 return (err);
1376 }
1377 }
1378 }
1379
1380 if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1)
1381 return (L_OPEN_PATH_FAIL);
1382
1383 if (fstat(fd, &sbuf) == -1) {
1384 (void) close(fd);
1385 return (L_FSTAT_ERROR);
1386 }
1387
1388 if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1389 (void) close(fd);
1390 return (L_OPEN_PATH_FAIL);
1391 }
1392
1393 /* Get the minor number for an fp instance */
1394 fcp_data.fp_minor = minor(sbuf.st_rdev);
1395
1396 fcp_data.listlen = 1;
1397 inq_data.dev_pwwn = pwwn; /* The port WWN as passed */
1398 fcp_data.list = (caddr_t)&inq_data;
1399
1400 if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1401 close(fd);
1402 close(fcp_fd);
1403 return (err);
1404 }
1405 *inq_dtype = inq_data.dev0_type;
1406
1407 close(fd);
1408 close(fcp_fd);
1409
1410 return (err);
1411 }
1412
1413 /*
1414 * Gets the inq_dtype for devices on the fabric FC driver
1415 * through an ioctl to the FCP module.
1416 *
1417 * This is exactly same as g_get_inq_dtype except that it does not do
1418 * g_dev_login(). That is for the case when the FCA tries to get its own
1419 * inq_dtype and in such a case, it cannot PLOGI into itself.
1420 *
1421 * OUTPUT:
1422 * inq_dtype is set to the dtype on success
1423 *
1424 * RETURN VALUES:
1425 * 0 on Success
1426 * Non-zero on error
1427 */
1428 static int
get_fca_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)1429 get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1430 {
1431 int dev_type, fd;
1432 int err, fcp_fd;
1433 struct fcp_ioctl fcp_data;
1434 struct device_data inq_data;
1435 struct stat sbuf;
1436
1437 dev_type = g_get_path_type(fcapath);
1438 if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1439 return (L_INVALID_PATH_TYPE);
1440 }
1441
1442 if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1443 return (L_OPEN_PATH_FAIL);
1444 }
1445
1446 if (fstat(fd, &sbuf) == -1) {
1447 (void) close(fd);
1448 return (L_FSTAT_ERROR);
1449 }
1450
1451 if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1452 (void) close(fd);
1453 return (L_OPEN_PATH_FAIL);
1454 }
1455
1456 /* Get the minor number for an fp instance */
1457 fcp_data.fp_minor = minor(sbuf.st_rdev);
1458
1459 fcp_data.listlen = 1;
1460 inq_data.dev_pwwn = pwwn; /* The port WWN as passed */
1461 fcp_data.list = (caddr_t)&inq_data;
1462
1463 if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1464 close(fd);
1465 close(fcp_fd);
1466 return (err);
1467 }
1468 *inq_dtype = inq_data.dev0_type;
1469
1470 close(fd);
1471 close(fcp_fd);
1472
1473 return (0);
1474 }
1475
1476 /*
1477 * This function returns the traditional g_get_dev_map. Device list
1478 * and local hba seperate.
1479 */
1480 int
g_get_dev_map(char * path,gfc_map_t * map_ptr,int verbose)1481 g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose)
1482 {
1483 return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD));
1484 }
1485
1486 /*
1487 * This function returns the device map with local hba in physical
1488 * order. Note: Physical order is only returned properly for
1489 * private loop. local hba is also included seperate
1490 */
1491 int
g_get_lilp_map(char * path,gfc_map_t * map_ptr,int verbose)1492 g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose)
1493 {
1494 return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP));
1495 }
1496
1497 /*
1498 * Gets device map from nexus driver
1499 *
1500 * PARAMS:
1501 * path - must be the physical path to a device
1502 * map - loop map returned from fc port.
1503 * verbose - options.
1504 *
1505 * LOGIC:
1506 * 1. check the validity of path via g_get_path_type.
1507 * 2. If FC path, get the topology of the path via
1508 * g_get_fca_port_topology.
1509 *
1510 * 3. If FC type(Leadville statck)
1511 * g_get_dev_list to get the device node list of fc_port_dev_t.
1512 * g_get_host_params to get the fca port node of fc_port_dev_t.
1513 *
1514 * Case of fabric or public loop topology
1515 * Check if the port id > 0xffff.
1516 * Move device node and fca port node to
1517 * gfc_map structure via gfc_port_dev_info_t
1518 * pub_port union.
1519 * Issue g_get_inq_dtype to get FCP inquiry data
1520 * and store it into gfc_port_dev_info_t.
1521 *
1522 * Case of private loop topology
1523 * Check if the port id < 0xff.
1524 * Move device node and fca port node to
1525 * gfc_map structure via gfc_port_dev_info_t
1526 * priv_port union.
1527 * Issue g_get_inq_dtype to get FCP inquiry data
1528 * and store it into gfc_port_dev_info_t.
1529 *
1530 * else FC4 type(socal/sf or ifp stack)
1531 * SFIOCGMAP ioctl to get the device and hba nodes of
1532 * sf_addr_pair_t.
1533 *
1534 *
1535 * RETURNS:
1536 * 0 : if OK
1537 * non-zero: otherwise
1538 */
1539 int
create_map(char * path,gfc_map_t * map_ptr,int verbose,int map_type)1540 create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type)
1541 {
1542 int fd, i, j, num_devices = 0, err, pathcnt = 1;
1543 char drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
1544 char *char_ptr;
1545 struct stat stbuf;
1546 fc_port_dev_t *dev_list, *dlistptr;
1547 uint32_t hba_port_top = 0;
1548 uint_t dev_type;
1549 sf_al_map_t sf_map;
1550 gfc_port_dev_info_t *dev_ptr;
1551 fc_port_dev_t fp_hba_port;
1552 mp_pathlist_t pathlist;
1553 int p_on = 0, p_st = 0;
1554
1555 /* return invalid path if path is NULL */
1556 if (path == NULL) {
1557 return (L_INVALID_PATH);
1558 }
1559 /* return invalid arg if map_ptr is NULL */
1560 if (map_ptr == NULL) {
1561 return (L_INVALID_ARG);
1562 }
1563
1564 map_ptr->dev_addr = NULL;
1565 map_ptr->count = 0;
1566 (void) strcpy(drvr_path, path);
1567 /*
1568 * Get the path to the :devctl driver
1569 *
1570 * This assumes the path looks something like this:
1571 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1572 * or
1573 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1574 * or
1575 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1576 * or
1577 * a 1 level PCI type driver but still :devctl
1578 */
1579 if (strstr(path, SCSI_VHCI)) {
1580 (void) strcpy(drvr_path0, path);
1581 if (g_get_pathlist(drvr_path0, &pathlist)) {
1582 return (L_INVALID_PATH);
1583 }
1584 pathcnt = pathlist.path_count;
1585 p_on = p_st = 0;
1586 for (i = 0; i < pathcnt; i++) {
1587 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
1588 if (pathlist.path_info[i].path_state ==
1589 MDI_PATHINFO_STATE_ONLINE) {
1590 p_on = i;
1591 break;
1592 } else if (pathlist.path_info[i].path_state ==
1593 MDI_PATHINFO_STATE_STANDBY) {
1594 p_st = i;
1595 }
1596 }
1597 }
1598 if (pathlist.path_info[p_on].path_state ==
1599 MDI_PATHINFO_STATE_ONLINE) {
1600 /* on_line path */
1601 (void) strcpy(drvr_path,
1602 pathlist.path_info[p_on].path_hba);
1603 } else {
1604 /* standby or path0 */
1605 (void) strcpy(drvr_path,
1606 pathlist.path_info[p_st].path_hba);
1607 }
1608 free(pathlist.path_info);
1609 (void) strcat(drvr_path, FC_CTLR);
1610 } else {
1611 (void) strcpy(drvr_path, path);
1612 if (strstr(drvr_path, DRV_NAME_SSD) ||
1613 strstr(drvr_path, SES_NAME) ||
1614 strstr(drvr_path, DRV_NAME_ST)) {
1615 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
1616 return (L_INVALID_PATH);
1617 }
1618 *char_ptr = '\0'; /* Terminate sting */
1619 /* append controller */
1620 (void) strcat(drvr_path, FC_CTLR);
1621 } else {
1622 if (stat(drvr_path, &stbuf) < 0) {
1623 return (L_LSTAT_ERROR);
1624 }
1625 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1626 /* append controller */
1627 (void) strcat(drvr_path, FC_CTLR);
1628 }
1629 }
1630 }
1631
1632 P_DPRINTF(" g_get_dev_map: Geting drive map from:"
1633 " %s\n", drvr_path);
1634
1635 dev_type = g_get_path_type(drvr_path);
1636 if ((dev_type == 0) || !(dev_type & XPORT_MASK)) {
1637 return (L_INVALID_PATH_TYPE);
1638 }
1639
1640 /* get fiber topology */
1641 if ((err = g_get_fca_port_topology(drvr_path,
1642 &hba_port_top, verbose)) != 0) {
1643 return (err);
1644 }
1645
1646 /* for FC devices. */
1647 if (dev_type & FC_FCA_MASK) {
1648 /*
1649 * if g_get_dev_list fails with L_NO_DEVICES_FOUND
1650 * we still want to call g_get_host_params to try to find the
1651 * HBA. If we do not see any HBAs on the loop, the
1652 * g_get_host_params will fail when it trys to issue the target
1653 * inquiry ioctl. In this case, we would still like to return
1654 * L_NO_DEVICES_FOUND.
1655 *
1656 * If g_get_dev_list fails with L_NO_DEVICES_FOUND and
1657 * g_get_host_params fails, the function returns
1658 * L_NO_DEVICES_FOUND
1659 */
1660 if ((err = g_get_dev_list(drvr_path, &dev_list,
1661 &num_devices)) != 0) {
1662 /*
1663 * g_get_dev_map doesn't allow ulp failure
1664 * to continue thus we need to free dev_list
1665 * here.
1666 */
1667 if (err == L_GET_DEV_LIST_ULP_FAILURE) {
1668 (void) free(dev_list);
1669 }
1670 if (err != L_NO_DEVICES_FOUND) {
1671 return (err);
1672 }
1673 }
1674
1675 /* Get local HBA information */
1676 if ((err = g_get_host_params(drvr_path, &fp_hba_port,
1677 verbose)) != 0) {
1678 (void) free(dev_list);
1679 if (num_devices == 0)
1680 return (L_NO_DEVICES_FOUND);
1681 else
1682 return (err);
1683 }
1684
1685 /* If devices, other than local HBA are found */
1686 /* allocate space for them in the gfc_map. */
1687 if (num_devices > 0) {
1688
1689 /* If map type is on MAP_FORMAT_LILP we need */
1690 /* to add space for the local HBA */
1691 if (map_type == MAP_FORMAT_LILP) {
1692 map_ptr->count = ++num_devices;
1693 } else {
1694 map_ptr->count = num_devices;
1695 }
1696
1697 if ((map_ptr->dev_addr = (gfc_port_dev_info_t *)
1698 calloc(map_ptr->count,
1699 sizeof (gfc_port_dev_info_t))) == NULL) {
1700 (void) free(dev_list);
1701 return (L_MALLOC_FAILED);
1702 }
1703 }
1704
1705 /* If we want the lilp map then we need to do a little */
1706 /* work here. The lilp map contains the local hba in */
1707 /* the dev_addr. Once this has been added qsort the */
1708 /* dev_addr array so it's in physical order. */
1709 /* The lilp map will contain the local hba in the */
1710 /* dev_addr array only when num_devices > 0 */
1711 if (map_type == MAP_FORMAT_LILP && num_devices > 0) {
1712
1713 /* First we need to allocate one additional */
1714 /* device to the dev_addr structure, for the */
1715 /* local hba */
1716 if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
1717 (num_devices * sizeof (fc_port_dev_t))))
1718 == NULL) {
1719 S_FREE(dev_list);
1720 (void) free(map_ptr->dev_addr);
1721 map_ptr->dev_addr = NULL;
1722 return (L_MALLOC_FAILED);
1723 }
1724
1725 /* Next, copy the local hba into this new loc. */
1726 if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
1727 sizeof (fc_port_dev_t)) == NULL) {
1728 (void) free(dev_list);
1729 (void) free(map_ptr->dev_addr);
1730 map_ptr->dev_addr = NULL;
1731 return (L_MEMCPY_FAILED);
1732 }
1733
1734 /* Now sort by physical location */
1735 qsort((void*)dev_list, num_devices,
1736 sizeof (fc_port_dev_t), lilp_map_cmp);
1737 }
1738
1739 dlistptr = dev_list;
1740 dev_ptr = map_ptr->dev_addr;
1741
1742 switch (hba_port_top) {
1743 case FC_TOP_FABRIC:
1744 case FC_TOP_PUBLIC_LOOP:
1745 if (fp_hba_port.dev_did.port_id <= 0xffff) {
1746 (void) free(dlistptr);
1747 (void) free(map_ptr->dev_addr);
1748 map_ptr->dev_addr = NULL;
1749 return (L_INVALID_FABRIC_ADDRESS);
1750 } else {
1751 map_ptr->hba_addr.port_topology = hba_port_top;
1752 map_ptr->hba_addr.gfc_port_dev.pub_port =
1753 fp_hba_port;
1754 }
1755 for (i = 0; i < num_devices; i++, dev_ptr++,
1756 dev_list++) {
1757 if (dev_list->dev_did.port_id <= 0xffff) {
1758 (void) free(dlistptr);
1759 (void) free(map_ptr->dev_addr);
1760 map_ptr->dev_addr = NULL;
1761 return (L_INVALID_FABRIC_ADDRESS);
1762 } else {
1763 dev_ptr->port_topology = hba_port_top;
1764 dev_ptr->gfc_port_dev.pub_port =
1765 *dev_list;
1766 }
1767 }
1768 break;
1769 case FC_TOP_PRIVATE_LOOP:
1770 /*
1771 * Map the (new->old) structures here.
1772 * Checking (i < SF_NUM_ENTRIES_IN_MAP) just to
1773 * make sure that we don't overrun the map structure
1774 * since it can hold data for upto 126 devices.
1775 */
1776 if (fp_hba_port.dev_did.port_id > 0xff) {
1777 (void) free(dlistptr);
1778 (void) free(map_ptr->dev_addr);
1779 map_ptr->dev_addr = NULL;
1780 return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1781 } else {
1782 map_ptr->hba_addr.port_topology = hba_port_top;
1783 map_ptr->hba_addr.gfc_port_dev.
1784 priv_port.sf_al_pa =
1785 (uchar_t)fp_hba_port.dev_did.port_id;
1786 map_ptr->hba_addr.gfc_port_dev.
1787 priv_port.sf_hard_address = (uchar_t)
1788 fp_hba_port.dev_hard_addr.hard_addr;
1789 for (j = 0; j < FC_WWN_SIZE; j++) {
1790 map_ptr->hba_addr.gfc_port_dev.
1791 priv_port.sf_node_wwn[j] =
1792 fp_hba_port.dev_nwwn.raw_wwn[j];
1793 map_ptr->hba_addr.gfc_port_dev.
1794 priv_port.sf_port_wwn[j] =
1795 fp_hba_port.dev_pwwn.raw_wwn[j];
1796 }
1797 map_ptr->hba_addr.gfc_port_dev.
1798 priv_port.sf_inq_dtype =
1799 fp_hba_port.dev_dtype;
1800 }
1801
1802 for (i = 0; (i < num_devices &&
1803 i < SF_NUM_ENTRIES_IN_MAP);
1804 i++, dev_ptr++, dev_list++) {
1805 /*
1806 * Out of 24 bits of port_id, copy only
1807 * 8 bits to al_pa. This works okay for
1808 * devices that're on a private loop.
1809 */
1810 if (dev_list->dev_did.port_id > 0xff) {
1811 (void) free(dlistptr);
1812 (void) free(map_ptr->dev_addr);
1813 map_ptr->dev_addr = NULL;
1814 return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1815 }
1816 dev_ptr->port_topology = hba_port_top;
1817 dev_ptr->gfc_port_dev.priv_port.sf_al_pa
1818 = (uchar_t)dev_list->dev_did.port_id;
1819
1820 /* Code refactorization is needed for C style */
1821 dev_ptr->gfc_port_dev.priv_port.sf_hard_address
1822 = (uchar_t)dev_list->dev_hard_addr.hard_addr;
1823
1824 for (j = 0; j < FC_WWN_SIZE; j++) {
1825
1826 dev_ptr->gfc_port_dev.priv_port.sf_node_wwn[j] =
1827 dev_list->dev_nwwn.raw_wwn[j];
1828 dev_ptr->gfc_port_dev.priv_port.sf_port_wwn[j] =
1829 dev_list->dev_pwwn.raw_wwn[j];
1830
1831 }
1832 dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype =
1833 dev_list->dev_dtype;
1834 }
1835 break;
1836 case FC_TOP_PT_PT:
1837 (void) free(dlistptr);
1838 (void) free(map_ptr->dev_addr);
1839 map_ptr->dev_addr = NULL;
1840 return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
1841 default:
1842 (void) free(dlistptr);
1843 (void) free(map_ptr->dev_addr);
1844 map_ptr->dev_addr = NULL;
1845 return (L_UNEXPECTED_FC_TOPOLOGY);
1846 } /* End of switch on port_topology */
1847 (void) free(dlistptr);
1848
1849 } else { /* sf and fc4/pci devices */
1850 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
1851 return (errno);
1852 /* initialize map */
1853 (void) memset(&sf_map, 0, sizeof (struct sf_al_map));
1854 if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
1855 I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
1856 (void) close(fd);
1857 return (L_SFIOCGMAP_IOCTL_FAIL);
1858 }
1859 /* Check for reasonableness. */
1860 if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
1861 (void) close(fd);
1862 return (L_INVALID_LOOP_MAP);
1863 }
1864 if (sf_map.sf_count == 0) {
1865 (void) close(fd);
1866 return (L_NO_DEVICES_FOUND);
1867 }
1868
1869 map_ptr->count = sf_map.sf_count;
1870 if ((map_ptr->dev_addr =
1871 (gfc_port_dev_info_t *)calloc(map_ptr->count,
1872 sizeof (gfc_port_dev_info_t))) == NULL) {
1873 (void) close(fd);
1874 return (L_MALLOC_FAILED);
1875 }
1876 dev_ptr = map_ptr->dev_addr;
1877 for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) {
1878 if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) {
1879 (void) free(map_ptr->dev_addr);
1880 map_ptr->dev_addr = NULL;
1881 (void) close(fd);
1882 return (L_INVALID_LOOP_MAP);
1883 }
1884 dev_ptr->port_topology = hba_port_top;
1885 dev_ptr->gfc_port_dev.priv_port =
1886 sf_map.sf_addr_pair[i];
1887 }
1888 map_ptr->hba_addr.port_topology = hba_port_top;
1889 map_ptr->hba_addr.gfc_port_dev.priv_port =
1890 sf_map.sf_hba_addr;
1891 (void) close(fd);
1892 }
1893
1894 return (0);
1895 }
1896
1897 /*
1898 * This function consturct FC proerty list using map_dev_fc_prop_list.
1899 *
1900 * port WWN, node WWN, port addr and hard addr properties is constructed.
1901 *
1902 * return 0 if OK.
1903 * otherwise returns error code.
1904 */
1905 static int
update_map_dev_fc_prop(impl_map_dev_prop_t ** prop_list,uint32_t map_topo,uchar_t * port_wwn,uchar_t * node_wwn,int port_addr,int hard_addr)1906 update_map_dev_fc_prop(impl_map_dev_prop_t **prop_list, uint32_t map_topo,
1907 uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr)
1908 {
1909 impl_map_dev_prop_t *prop_ptr, *pl_start = NULL, *pl_end = NULL;
1910 uchar_t *port_wwn_data, *node_wwn_data;
1911 int *port_addr_data, *hard_addr_data;
1912
1913 /* consrtruct port addr property. */
1914 if ((map_topo == FC_TOP_FABRIC) || (map_topo == FC_TOP_PUBLIC_LOOP)) {
1915 if (port_addr <= 0xffff) {
1916 return (L_INVALID_FABRIC_ADDRESS);
1917 }
1918 } else if (map_topo == FC_TOP_PRIVATE_LOOP) {
1919 if (port_addr > 0xff) {
1920 return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1921 }
1922 }
1923
1924 if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1925 1, sizeof (impl_map_dev_prop_t))) == NULL) {
1926 return (L_MALLOC_FAILED);
1927 }
1928 (void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP,
1929 strlen(PORT_ADDR_PROP));
1930 prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1931
1932 if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1933 free(prop_ptr);
1934 return (L_MALLOC_FAILED);
1935 }
1936 *port_addr_data = port_addr;
1937 prop_ptr->prop_data = port_addr_data;
1938
1939 pl_start = pl_end = prop_ptr;
1940
1941 /* consrtruct port WWN property. */
1942 if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1943 1, sizeof (impl_map_dev_prop_t))) == NULL) {
1944 free_prop_list(&pl_start);
1945 return (L_MALLOC_FAILED);
1946 }
1947 (void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP,
1948 strlen(PORT_WWN_PROP));
1949 prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1950
1951 if ((port_wwn_data = (uchar_t *)calloc(1, FC_WWN_SIZE)) == NULL) {
1952 free_prop_list(&pl_start);
1953 return (L_MALLOC_FAILED);
1954 }
1955 memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE);
1956 prop_ptr->prop_data = port_wwn_data;
1957 prop_ptr->prop_size = FC_WWN_SIZE;
1958 pl_end->next = prop_ptr;
1959 pl_end = prop_ptr;
1960
1961 /* consrtruct node WWN property. */
1962 if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1963 1, sizeof (impl_map_dev_prop_t))) == NULL) {
1964 free_prop_list(&pl_start);
1965 return (L_MALLOC_FAILED);
1966 }
1967 (void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP,
1968 strlen(NODE_WWN_PROP));
1969 prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1970
1971 if ((node_wwn_data = (uchar_t *)calloc(
1972 1, FC_WWN_SIZE)) == NULL) {
1973 free_prop_list(&pl_start);
1974 return (L_MALLOC_FAILED);
1975 }
1976 memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE);
1977 prop_ptr->prop_data = node_wwn_data;
1978 prop_ptr->prop_size = FC_WWN_SIZE;
1979 pl_end->next = prop_ptr;
1980 pl_end = prop_ptr;
1981
1982 /* consrtruct hard addr property. */
1983 if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1984 1, sizeof (impl_map_dev_prop_t))) == NULL) {
1985 free_prop_list(&pl_start);
1986 return (L_MALLOC_FAILED);
1987 }
1988 (void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP,
1989 strlen(HARD_ADDR_PROP));
1990 prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1991
1992 if ((hard_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1993 free_prop_list(&pl_start);
1994 return (L_MALLOC_FAILED);
1995 }
1996 *hard_addr_data = hard_addr;
1997 prop_ptr->prop_data = hard_addr_data;
1998 pl_end->next = prop_ptr;
1999 pl_end = prop_ptr;
2000
2001 if (*prop_list == NULL) {
2002 *prop_list = pl_start;
2003 } else {
2004 pl_end->next = (*prop_list)->next;
2005 *prop_list = pl_start;
2006 }
2007
2008 return (0);
2009 }
2010
2011 /*
2012 * This function consturct FCP inq dtype propery.
2013 * if inq_dtype is null the property is constrcted with err info.
2014 *
2015 * L_MALLOC_FAILED is the only possible error.
2016 */
2017 static int
update_map_dev_FCP_prop(impl_map_dev_prop_t ** prop_list,uchar_t * inq_dtype,int err,int exist)2018 update_map_dev_FCP_prop(impl_map_dev_prop_t **prop_list,
2019 uchar_t *inq_dtype, int err, int exist)
2020 {
2021 impl_map_dev_prop_t *prop_ptr, *old_prop_ptr;
2022 uchar_t *inq_dtype_data;
2023
2024 if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
2025 1, sizeof (impl_map_dev_prop_t))) == NULL) {
2026 return (L_MALLOC_FAILED);
2027 }
2028
2029 (void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP,
2030 strlen(INQ_DTYPE_PROP));
2031
2032 if (inq_dtype == NULL) {
2033 prop_ptr->prop_data = NULL;
2034 prop_ptr->prop_error = err;
2035 } else {
2036 if ((inq_dtype_data = (uchar_t *)calloc(
2037 1, sizeof (uchar_t))) == NULL) {
2038 free(prop_ptr);
2039 return (L_MALLOC_FAILED);
2040 }
2041 memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t));
2042 prop_ptr->prop_data = inq_dtype_data;
2043 prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
2044 prop_ptr->prop_size = sizeof (uchar_t);
2045 }
2046
2047 if (*prop_list == NULL) {
2048 *prop_list = prop_ptr;
2049 } else {
2050 if (exist == PROP_EXIST) {
2051 prop_ptr->next = (*prop_list)->next;
2052 old_prop_ptr = *prop_list;
2053 *prop_list = prop_ptr;
2054 free((uchar_t *)(old_prop_ptr->prop_data));
2055 old_prop_ptr->prop_data = NULL;
2056 S_FREE(old_prop_ptr);
2057 } else {
2058 prop_ptr->next = *prop_list;
2059 *prop_list = prop_ptr;
2060 }
2061 }
2062
2063 return (0);
2064 }
2065
2066 /*
2067 * This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl()
2068 * to get the inq_dtype of input device and calls update_map_dev_FCP_prop().
2069 * inq_dtype is set to NULL and pass error code if inq_dtype data is not
2070 * requried.
2071 *
2072 * return error from update_map_dev_FCP_prop().
2073 */
2074 static int
handle_map_dev_FCP_prop(minor_t fp_xport_minor,la_wwn_t port_wwn,impl_map_dev_prop_t ** prop_list)2075 handle_map_dev_FCP_prop(minor_t fp_xport_minor, la_wwn_t port_wwn,
2076 impl_map_dev_prop_t **prop_list)
2077 {
2078 struct device_data inq_data;
2079 int fcp_fd, err;
2080 struct fcp_ioctl fcp_data;
2081 uchar_t inq_dtype;
2082
2083 if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
2084 update_map_dev_FCP_prop(prop_list, NULL,
2085 L_OPEN_PATH_FAIL, PROP_NOEXIST);
2086 }
2087
2088 /* Get the minor number for an fp instance */
2089 fcp_data.fp_minor = fp_xport_minor;
2090
2091 /* Get FCP prop for the hba first. */
2092 fcp_data.listlen = 1;
2093 inq_data.dev_pwwn = port_wwn;
2094 fcp_data.list = (caddr_t)&inq_data;
2095
2096 if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
2097 /* if ioctl error then set the prop_error. */
2098 if ((err = update_map_dev_FCP_prop(
2099 prop_list, NULL, err, PROP_NOEXIST)) != 0) {
2100 return (err);
2101 }
2102 } else {
2103 inq_dtype = inq_data.dev0_type;
2104 if ((err = update_map_dev_FCP_prop(
2105 prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) {
2106 return (err);
2107 }
2108 }
2109
2110 return (0);
2111 }
2112
2113 /*
2114 * Construct device map tree from nexus driver
2115 *
2116 * PARAMS:
2117 * path - must be the physical path to a device
2118 * l_err - ptr to an error code. Set when NULL is returned.
2119 * flag - device map fomat and property type.
2120 *
2121 * LOGIC:
2122 * 1. check the validity of path via g_get_path_type.
2123 * 2. If FC path, get the topology of the path via
2124 * g_get_fca_port_topology.
2125 *
2126 * 3. If FC type(Leadville statck)
2127 * FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t.
2128 * FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t.
2129 *
2130 * root of tree is set with host_params info
2131 * FC propery is set.
2132 * FCP property is set if reqyested through flag.
2133 * Issue g_issue_fcp_ioctl to get FCP inquiry data
2134 * consruruct list of children via dev_list.
2135 * FC property is set.
2136 * FCP property is set if reqyested through flag.
2137 * Issue FCIO_DEV_LOGIN if it is fabric device.
2138 * Issue g_issue_fcp_ioctl to get FCP inquiry data.
2139 *
2140 * else FC4 type(socal/sf or ifp stack)
2141 * SFIOCGMAP ioctl to get the device and hba nodes of
2142 * sf_addr_pair_t.
2143 * FCIO_GETMAP ioctl to get hba port info.
2144 * consturct map and child tree list and
2145 * set the properties as private loop devices.
2146 *
2147 * RETURNS:
2148 * ptr to map is returned if OK.
2149 * NULL and l_err is set otherwise.
2150 */
2151 gfc_dev_t
g_dev_map_init(char * path,int * l_err,int flag)2152 g_dev_map_init(char *path, int *l_err, int flag)
2153 {
2154 int fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0;
2155 char drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
2156 char *char_ptr, *nexus_path;
2157 struct stat stbuf;
2158 fc_port_dev_t *dev_list = NULL, *dlist;
2159 uint32_t hba_port_top, state;
2160 uint_t path_type;
2161 sf_al_map_t sf_map;
2162 fc_port_dev_t fp_hba_port;
2163 mp_pathlist_t pathlist;
2164 int p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd;
2165 fcio_t fcio;
2166 struct lilpmap limited_map;
2167 impl_map_dev_t *impl_map, *impl_dev;
2168 impl_map_dev_t *mdl_start = NULL, *mdl_end = NULL;
2169 struct stat sbuf;
2170
2171 if (l_err == NULL) {
2172 return (NULL);
2173 }
2174
2175 if (path == NULL) {
2176 *l_err = L_INVALID_PATH;
2177 return (NULL);
2178 }
2179
2180 *l_err = 0;
2181
2182 (void) strcpy(drvr_path, path);
2183 /*
2184 * Get the path to the :devctl driver
2185 *
2186 * This assumes the path looks something like this:
2187 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
2188 * or
2189 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
2190 * or
2191 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
2192 * or
2193 * a 1 level PCI type driver but still :devctl
2194 */
2195 if (strstr(path, SCSI_VHCI)) {
2196 (void) strcpy(drvr_path0, path);
2197 if (g_get_pathlist(drvr_path0, &pathlist)) {
2198 *l_err = L_INVALID_PATH;
2199 return (NULL);
2200 }
2201 pathcnt = pathlist.path_count;
2202 p_on = p_st = 0;
2203 for (i = 0; i < pathcnt; i++) {
2204 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
2205 if (pathlist.path_info[i].path_state ==
2206 MDI_PATHINFO_STATE_ONLINE) {
2207 p_on = i;
2208 break;
2209 } else if (pathlist.path_info[i].path_state ==
2210 MDI_PATHINFO_STATE_STANDBY) {
2211 p_st = i;
2212 }
2213 }
2214 }
2215 if (pathlist.path_info[p_on].path_state ==
2216 MDI_PATHINFO_STATE_ONLINE) {
2217 /* on_line path */
2218 (void) strcpy(drvr_path,
2219 pathlist.path_info[p_on].path_hba);
2220 } else {
2221 /* standby or path0 */
2222 (void) strcpy(drvr_path,
2223 pathlist.path_info[p_st].path_hba);
2224 }
2225 free(pathlist.path_info);
2226 (void) strcat(drvr_path, FC_CTLR);
2227 } else {
2228 (void) strcpy(drvr_path, path);
2229 if (strstr(drvr_path, DRV_NAME_SSD) ||
2230 strstr(drvr_path, SES_NAME) ||
2231 strstr(drvr_path, DRV_NAME_ST)) {
2232 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
2233 *l_err = L_INVALID_PATH;
2234 return (NULL);
2235 }
2236 *char_ptr = '\0'; /* Terminate sting */
2237 /* append controller */
2238 (void) strcat(drvr_path, FC_CTLR);
2239 } else {
2240 if (stat(drvr_path, &stbuf) < 0) {
2241 *l_err = L_LSTAT_ERROR;
2242 return (NULL);
2243 }
2244 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
2245 /* append controller */
2246 (void) strcat(drvr_path, FC_CTLR);
2247 }
2248 }
2249 }
2250
2251 P_DPRINTF(" g_dev_map_init: Geting drive map from:"
2252 " %s\n", drvr_path);
2253
2254 path_type = g_get_path_type(drvr_path);
2255 if ((path_type == 0) || !(path_type & XPORT_MASK)) {
2256 *l_err = L_INVALID_PATH_TYPE;
2257 return (NULL);
2258 }
2259
2260 /* get fiber topology */
2261 if ((err = g_get_fca_port_topology(drvr_path,
2262 &hba_port_top, 0)) != 0) {
2263 *l_err = err;
2264 return (NULL);
2265 }
2266
2267 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) {
2268 *l_err = errno;
2269 return (NULL);
2270 }
2271
2272 /* for FC devices. */
2273 if (path_type & FC_FCA_MASK) {
2274 /* get the number of device first. */
2275 fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
2276 fcio.fcio_olen = sizeof (num_devices);
2277 fcio.fcio_xfer = FCIO_XFER_READ;
2278 fcio.fcio_obuf = (caddr_t)&num_devices;
2279 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2280 I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
2281 (void) close(fd);
2282 *l_err = L_FCIO_GET_NUM_DEVS_FAIL;
2283 return (NULL);
2284 }
2285 if (num_devices != 0) {
2286 if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
2287 sizeof (fc_port_dev_t))) == NULL) {
2288 (void) close(fd);
2289 *l_err = L_MALLOC_FAILED;
2290 return (NULL);
2291 }
2292
2293 bzero((caddr_t)&fcio, sizeof (fcio));
2294 /* Get the device list */
2295 fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2296 /* Information read operation */
2297 fcio.fcio_xfer = FCIO_XFER_READ;
2298 fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
2299 fcio.fcio_obuf = (caddr_t)dev_list;
2300 /* new device count */
2301 fcio.fcio_alen = sizeof (new_count);
2302 fcio.fcio_abuf = (caddr_t)&new_count;
2303 if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
2304 if (err == L_INVALID_DEVICE_COUNT) {
2305 /*
2306 * original buffer was small so allocate
2307 * buffer with a new count and retry.
2308 */
2309 free(dev_list);
2310 num_devices = new_count;
2311 new_count = 0;
2312 if ((dev_list = (fc_port_dev_t *)
2313 calloc(num_devices,
2314 sizeof (fc_port_dev_t))) == NULL) {
2315 (void) close(fd);
2316 *l_err = L_MALLOC_FAILED;
2317 return (NULL);
2318 }
2319 fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2320 /* Information read operation */
2321 fcio.fcio_xfer = FCIO_XFER_READ;
2322 fcio.fcio_obuf = (caddr_t)dev_list;
2323 fcio.fcio_olen = num_devices *
2324 sizeof (fc_port_dev_t);
2325 /* new device count */
2326 fcio.fcio_alen = sizeof (new_count);
2327 fcio.fcio_abuf = (caddr_t)&new_count;
2328 if ((err = g_issue_fcio_ioctl(fd, &fcio,
2329 0)) != 0) {
2330 if (err ==
2331 L_INVALID_DEVICE_COUNT) {
2332 /*
2333 * No more retry. There
2334 * may be severe
2335 * hardware problem so
2336 * return error here.
2337 */
2338 I_DPRINTF(" Device"
2339 " count was %d"
2340 " should have been"
2341 " %d\n",
2342 num_devices,
2343 new_count);
2344 free(dev_list);
2345 (void) close(fd);
2346
2347 *l_err = L_INVALID_DEVICE_COUNT;
2348
2349 return (NULL);
2350 } else {
2351
2352 /* Code refactorization is needed for C style */
2353 I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
2354
2355 free(dev_list);
2356 (void) close(fd);
2357
2358 *l_err = L_FCIO_GET_DEV_LIST_FAIL;
2359
2360 return (NULL);
2361 }
2362 }
2363 }
2364 }
2365 }
2366
2367 /*
2368 * if new count is smaller than the original number from
2369 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
2370 * and continue.
2371 */
2372 if (new_count < num_devices) {
2373 num_devices = new_count;
2374 if (new_count > 0) {
2375 if ((dev_list = (fc_port_dev_t *)
2376 realloc(dev_list,
2377 (new_count * sizeof (fc_port_dev_t))))
2378 == NULL) {
2379 S_FREE(dev_list);
2380 (void) close(fd);
2381 *l_err = L_MALLOC_FAILED;
2382 return (NULL);
2383 }
2384 }
2385 }
2386
2387 /* get the host param info */
2388 (void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev));
2389 fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
2390 fcio.fcio_xfer = FCIO_XFER_READ;
2391 fcio.fcio_obuf = (caddr_t)&fp_hba_port;
2392 fcio.fcio_olen = sizeof (fc_port_dev_t);
2393
2394 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2395 I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
2396 (void) close(fd);
2397 if (num_devices == 0) {
2398 *l_err = L_NO_DEVICES_FOUND;
2399 } else {
2400 free(dev_list);
2401 *l_err = L_FCIO_GET_HOST_PARAMS_FAIL;
2402 }
2403 (void) close(fd);
2404 return (NULL);
2405 }
2406
2407 /* If we want the lilp map then we need to do a little */
2408 /* work here. The lilp map contains the local hba in */
2409 /* the dev_addr. Once this has been added qsort the */
2410 /* dev_addr array so it's in physical order. */
2411 if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) {
2412 /* First we need to allocate one additional */
2413 /* device to the dev_addr structure, for the */
2414 /* local hba */
2415 if (num_devices > 0) {
2416 if ((dev_list = (fc_port_dev_t *)
2417 realloc(dev_list,
2418 (++num_devices *
2419 sizeof (fc_port_dev_t)))) == NULL) {
2420 (void) close(fd);
2421 /*
2422 * In case dev_list is not null free
2423 * it.
2424 */
2425 S_FREE(dev_list);
2426 *l_err = L_MALLOC_FAILED;
2427 return (NULL);
2428 }
2429
2430 /*
2431 * Next, copy the local hba into this new
2432 * loc.
2433 */
2434 if (memcpy(dev_list+(num_devices-1),
2435 &fp_hba_port,
2436 sizeof (fc_port_dev_t)) == NULL) {
2437 (void) free(dev_list);
2438 (void) close(fd);
2439 *l_err = L_MEMCPY_FAILED;
2440 return (NULL);
2441 }
2442
2443 /* Now sort by physical location */
2444 qsort((void*)dev_list, num_devices,
2445 sizeof (fc_port_dev_t), lilp_map_cmp);
2446 }
2447 }
2448
2449
2450 /* We have dev list info and host param info. */
2451 /* Now constructs map tree with these info. */
2452 /* First consturct the root of the map tree */
2453 /* with host param. */
2454 if ((impl_map = (impl_map_dev_t *)calloc(
2455 1, sizeof (impl_map_dev_t))) == NULL) {
2456 (void) free(dev_list);
2457 (void) close(fd);
2458 *l_err = L_MALLOC_FAILED;
2459 return (NULL);
2460 }
2461 impl_map->flag = flag;
2462 impl_map->topo = hba_port_top;
2463
2464 /* consturct hba property list. */
2465 if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2466 hba_port_top, fp_hba_port.dev_pwwn.raw_wwn,
2467 fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id,
2468 fp_hba_port.dev_hard_addr.hard_addr)) != 0) {
2469 (void) free(dev_list);
2470 (void) close(fd);
2471 g_dev_map_fini(impl_map);
2472 *l_err = err;
2473 return (NULL);
2474 }
2475
2476 if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2477 if (fstat(fd, &sbuf) == -1) {
2478 (void) free(dev_list);
2479 (void) close(fd);
2480 g_dev_map_fini(impl_map);
2481 *l_err = L_FSTAT_ERROR;
2482 return (NULL);
2483 }
2484 if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
2485 fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) {
2486 (void) free(dev_list);
2487 (void) close(fd);
2488 g_dev_map_fini(impl_map);
2489 *l_err = err;
2490 return (NULL);
2491 }
2492 }
2493
2494 /* consturct child for each device and */
2495 /* set device property list. */
2496 dlist = dev_list;
2497 for (i = 0; i < num_devices; i++, dlist++) {
2498 if ((impl_dev = (impl_map_dev_t *)calloc(
2499 1, sizeof (impl_map_dev_t))) == NULL) {
2500 (void) free(dev_list);
2501 (void) close(fd);
2502 g_dev_map_fini(impl_map);
2503 *l_err = L_MALLOC_FAILED;
2504 return (NULL);
2505 }
2506 /* set the map as parent */
2507 impl_dev->parent = impl_map;
2508 if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2509 hba_port_top, dlist->dev_pwwn.raw_wwn,
2510 dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id,
2511 dlist->dev_hard_addr.hard_addr)) != 0) {
2512 (void) free(dev_list);
2513 (void) close(fd);
2514 g_dev_map_fini(impl_map);
2515 *l_err = err;
2516 return (NULL);
2517 }
2518 if (i == 0) {
2519 mdl_start = mdl_end = impl_dev;
2520 } else {
2521 mdl_end->next = impl_dev;
2522 mdl_end = impl_dev;
2523 }
2524 if ((flag & MAP_XPORT_PROP_ONLY) !=
2525 MAP_XPORT_PROP_ONLY) {
2526 if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
2527 (hba_port_top == FC_TOP_FABRIC)) &&
2528 (memcmp(fp_hba_port.dev_pwwn.raw_wwn,
2529 dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) {
2530 (void) memset(&fcio, 0, sizeof (fcio_t));
2531 fcio.fcio_cmd = FCIO_GET_STATE;
2532 fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
2533 fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
2534 fcio.fcio_xfer = FCIO_XFER_READ |
2535 FCIO_XFER_WRITE;
2536 fcio.fcio_olen = sizeof (uint32_t);
2537 fcio.fcio_obuf = (caddr_t)&state;
2538 fcio.fcio_alen = 0;
2539 fcio.fcio_abuf = NULL;
2540 if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2541 I_DPRINTF(
2542 " FCIO_GET_STATE ioctl failed.\n");
2543 if ((err = update_map_dev_FCP_prop(
2544 &impl_dev->prop_list, NULL,
2545 L_FCIO_GET_STATE_FAIL,
2546 PROP_NOEXIST)) != 0) {
2547 (void) free(dev_list);
2548 (void) close(fd);
2549 g_dev_map_fini(impl_map);
2550 *l_err = err;
2551 return (NULL);
2552 }
2553 }
2554 if (state != PORT_DEVICE_LOGGED_IN) {
2555 (void) close(fd);
2556 if ((fd = g_object_open(drvr_path,
2557 O_NDELAY | O_RDONLY | O_EXCL)) ==
2558 -1) {
2559 (void) free(dev_list);
2560 g_dev_map_fini(impl_map);
2561 *l_err = L_OPEN_PATH_FAIL;
2562 return (NULL);
2563 }
2564 (void) memset(&fcio, 0,
2565 sizeof (fcio_t));
2566 fcio.fcio_cmd = FCIO_DEV_LOGIN;
2567 fcio.fcio_ilen =
2568 sizeof (dlist->dev_pwwn);
2569 fcio.fcio_ibuf =
2570 (caddr_t)&dlist->dev_pwwn;
2571 fcio.fcio_xfer = FCIO_XFER_WRITE;
2572 fcio.fcio_olen = fcio.fcio_alen = 0;
2573 fcio.fcio_obuf = fcio.fcio_abuf = NULL;
2574 if (g_issue_fcio_ioctl(fd, &fcio, 0) !=
2575 0) {
2576
2577 /* Code refactorization is needed for C style */
2578 I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
2579
2580 if ((err = update_map_dev_FCP_prop(
2581 &impl_dev->prop_list, NULL,
2582 L_FCIO_DEV_LOGIN_FAIL,
2583 PROP_NOEXIST)) != 0) {
2584 (void) free(dev_list);
2585 (void) close(fd);
2586 g_dev_map_fini(impl_map);
2587 *l_err = err;
2588 return (NULL);
2589 }
2590
2591 /*
2592 * plogi failed continue
2593 * to next dev
2594 */
2595 continue;
2596 }
2597 }
2598 }
2599 /* sbuf should be set from hba_port handling. */
2600 if ((err = handle_map_dev_FCP_prop(
2601 minor(sbuf.st_rdev),
2602 dlist->dev_pwwn, &impl_dev->prop_list)) !=
2603 0) {
2604 (void) free(dev_list);
2605 (void) close(fd);
2606 g_dev_map_fini(impl_map);
2607 *l_err = err;
2608 return (NULL);
2609 }
2610 }
2611 }
2612 /* connect the children to to map. */
2613 impl_map->child = mdl_start;
2614 S_FREE(dev_list);
2615
2616 } else { /* sf and fc4/pci devices */
2617 /* initialize map */
2618 (void) memset(&sf_map, 0, sizeof (struct sf_al_map));
2619 if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
2620 I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
2621 (void) close(fd);
2622 *l_err = L_SFIOCGMAP_IOCTL_FAIL;
2623 return (NULL);
2624 }
2625 /* Check for reasonableness. */
2626 if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
2627 (void) close(fd);
2628 *l_err = L_INVALID_LOOP_MAP;
2629 return (NULL);
2630 }
2631
2632 if (sf_map.sf_count == 0) {
2633 (void) close(fd);
2634 *l_err = L_NO_DEVICES_FOUND;
2635 return (NULL);
2636 }
2637
2638 if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) {
2639 (void) close(fd);
2640 *l_err = err;
2641 return (NULL);
2642 }
2643
2644 if ((nexus_fd =
2645 g_object_open(nexus_path, O_NDELAY | O_RDONLY)) == -1) {
2646 (void) close(fd);
2647 S_FREE(nexus_path);
2648 *l_err = errno;
2649 return (NULL);
2650 }
2651
2652 /* get limited map to get hba param info */
2653 if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) {
2654 I_DPRINTF(" FCIO_GETMAP ioctl failed\n");
2655 (void) close(fd);
2656 (void) close(nexus_fd);
2657 S_FREE(nexus_path);
2658 *l_err = L_FCIO_GETMAP_IOCTL_FAIL;
2659 return (NULL);
2660 }
2661 (void) close(nexus_fd);
2662 S_FREE(nexus_path);
2663
2664 for (i = 0; i < sf_map.sf_count; i++) {
2665 if (sf_map.sf_addr_pair[i].sf_al_pa ==
2666 limited_map.lilp_myalpa) {
2667 sf_map.sf_hba_addr = sf_map.sf_addr_pair[i];
2668 hba_alpa_found = 1;
2669 }
2670 }
2671
2672 if (!(hba_alpa_found)) {
2673 (void) close(fd);
2674 *l_err = L_INVALID_LOOP_MAP;
2675 return (NULL);
2676 }
2677
2678 /* We have dev list info and host param info. */
2679 /* Now constructs map tree with these info. */
2680 /* First consturct the root of the map tree */
2681 /* with host param. */
2682 if ((impl_map = (impl_map_dev_t *)calloc(
2683 1, sizeof (impl_map_dev_t))) == NULL) {
2684 (void) close(fd);
2685 *l_err = L_MALLOC_FAILED;
2686 return (NULL);
2687 }
2688 impl_map->flag = flag;
2689 impl_map->topo = hba_port_top;
2690
2691 /* consturct hba property list. */
2692 if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2693 hba_port_top, sf_map.sf_hba_addr.sf_port_wwn,
2694 sf_map.sf_hba_addr.sf_node_wwn,
2695 (int)sf_map.sf_hba_addr.sf_al_pa,
2696 (int)sf_map.sf_hba_addr.sf_hard_address)) != 0) {
2697 (void) close(fd);
2698 g_dev_map_fini(impl_map);
2699 *l_err = err;
2700 return (NULL);
2701 }
2702
2703 if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2704 if ((err = update_map_dev_FCP_prop(&impl_map->prop_list,
2705 &sf_map.sf_hba_addr.sf_inq_dtype, 0,
2706 PROP_NOEXIST)) != 0) {
2707 (void) close(fd);
2708 g_dev_map_fini(impl_map);
2709 *l_err = err;
2710 return (NULL);
2711 }
2712 }
2713
2714 for (i = 0; i < sf_map.sf_count; i++) {
2715 if ((impl_dev = (impl_map_dev_t *)calloc(
2716 1, sizeof (impl_map_dev_t))) == NULL) {
2717 (void) close(fd);
2718 g_dev_map_fini(impl_map);
2719 *l_err = L_MALLOC_FAILED;
2720 return (NULL);
2721 }
2722 /* set the map as parent */
2723 impl_dev->parent = impl_map;
2724 if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2725 hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn,
2726 sf_map.sf_addr_pair[i].sf_node_wwn,
2727 (int)(sf_map.sf_addr_pair[i].sf_al_pa),
2728 (int)(sf_map.sf_addr_pair[i].sf_hard_address))) !=
2729 0) {
2730 (void) close(fd);
2731 g_dev_map_fini(impl_map);
2732 *l_err = err;
2733 return (NULL);
2734 }
2735 if (i == 0) {
2736 mdl_start = mdl_end = impl_dev;
2737 } else {
2738 mdl_end->next = impl_dev;
2739 mdl_end = impl_dev;
2740 }
2741 if ((flag & MAP_XPORT_PROP_ONLY) !=
2742 MAP_XPORT_PROP_ONLY) {
2743 if ((err = update_map_dev_FCP_prop(
2744 &impl_dev->prop_list,
2745 &sf_map.sf_addr_pair[i].sf_inq_dtype, 0,
2746 PROP_NOEXIST)) != 0) {
2747 (void) close(fd);
2748 g_dev_map_fini(impl_map);
2749 *l_err = err;
2750 return (NULL);
2751 }
2752 }
2753 } /* end of for loop */
2754
2755 impl_map->child = mdl_start;
2756 } /* end of else */
2757
2758 close(fd);
2759 return ((gfc_dev_t)(impl_map));
2760 }
2761
2762 /*
2763 * This function deallocates memory for propery list.
2764 */
2765 static void
free_prop_list(impl_map_dev_prop_t ** prop_list)2766 free_prop_list(impl_map_dev_prop_t **prop_list)
2767 {
2768 impl_map_dev_prop_t *lp, *olp;
2769
2770 lp = *prop_list;
2771 while (lp != NULL) {
2772 switch (lp->prop_type) {
2773 case GFC_PROP_TYPE_BYTES:
2774 free((uchar_t *)(lp->prop_data));
2775 break;
2776 case GFC_PROP_TYPE_INT:
2777 free((int *)(lp->prop_data));
2778 break;
2779 case GFC_PROP_TYPE_STRING:
2780 free((char *)(lp->prop_data));
2781 break;
2782 default:
2783 break;
2784 }
2785 lp->prop_data = NULL;
2786 olp = lp;
2787 lp = olp->next;
2788 S_FREE(olp);
2789 }
2790
2791 *prop_list = NULL;
2792 }
2793
2794 /*
2795 * This function deallocates memory for children list.
2796 */
2797 static void
free_child_list(impl_map_dev_t ** dev_list)2798 free_child_list(impl_map_dev_t **dev_list)
2799 {
2800 impl_map_dev_t *lp, *olp;
2801
2802 lp = *dev_list;
2803 while (lp != NULL) {
2804 free_prop_list(&lp->prop_list);
2805 olp = lp;
2806 lp = olp->next;
2807 S_FREE(olp);
2808 }
2809
2810 *dev_list = NULL;
2811 }
2812
2813 /*
2814 * This function deallocates memory for the whole map.
2815 */
2816 void
g_dev_map_fini(gfc_dev_t map)2817 g_dev_map_fini(gfc_dev_t map)
2818 {
2819 impl_map_dev_t *impl_map;
2820
2821 impl_map = (impl_map_dev_t *)map;
2822
2823 if (impl_map != NULL) {
2824 free_prop_list(&impl_map->prop_list);
2825 free_child_list(&impl_map->child);
2826 S_FREE(impl_map);
2827 }
2828 }
2829
2830 /*
2831 * This function passes back topology of the input map.
2832 * input should be a handle form g_dev_map_init().
2833 *
2834 * return 0 if OK.
2835 * return error code otherwise.
2836 */
2837 int
g_get_map_topology(gfc_dev_t map,uint_t * topology)2838 g_get_map_topology(gfc_dev_t map, uint_t *topology)
2839 {
2840 impl_map_dev_t *impl_map;
2841
2842 if (map == NULL) {
2843 return (L_INVALID_MAP_DEV_ADDR);
2844 }
2845
2846 if (topology == NULL) {
2847 return (L_INVALID_ARG);
2848 }
2849
2850 impl_map = (impl_map_dev_t *)map;
2851
2852 *topology = impl_map->topo;
2853
2854 return (0);
2855 }
2856
2857 /*
2858 * This function returns the first device handle of the input map.
2859 * map input should be a handle form g_dev_map_init().
2860 *
2861 * l_err set to 0 if OK.
2862 * l_err set to error code otherwise.
2863 */
2864 gfc_dev_t
g_get_first_dev(gfc_dev_t map,int * l_err)2865 g_get_first_dev(gfc_dev_t map, int *l_err)
2866 {
2867 impl_map_dev_t *impl_map;
2868
2869 if (l_err == NULL) {
2870 return (NULL);
2871 }
2872
2873 *l_err = 0;
2874
2875 if (map == NULL) {
2876 *l_err = L_INVALID_MAP_DEV_ADDR;
2877 return (NULL);
2878 }
2879
2880 impl_map = (impl_map_dev_t *)map;
2881
2882 if (impl_map->child == NULL) {
2883 *l_err = L_NO_SUCH_DEV_FOUND;
2884 }
2885
2886 return ((gfc_dev_t)(impl_map->child));
2887 }
2888
2889 /*
2890 * This function returns the next device handle of the input map.
2891 * map_dev input should be a handle for device.
2892 *
2893 * l_err set to 0 if OK.
2894 * l_err set to error code otherwise.
2895 */
2896 gfc_dev_t
g_get_next_dev(gfc_dev_t map_dev,int * l_err)2897 g_get_next_dev(gfc_dev_t map_dev, int *l_err)
2898 {
2899 impl_map_dev_t *impl_dev;
2900
2901 if (l_err == NULL) {
2902 return (NULL);
2903 }
2904
2905 *l_err = 0;
2906
2907 if (map_dev == NULL) {
2908 *l_err = L_INVALID_MAP_DEV_ADDR;
2909 return (NULL);
2910 }
2911
2912 impl_dev = (impl_map_dev_t *)map_dev;
2913
2914 if (impl_dev->next == NULL) {
2915 *l_err = L_NO_SUCH_DEV_FOUND;
2916 }
2917
2918 return ((gfc_dev_t)(impl_dev->next));
2919 }
2920
2921 /*
2922 * This function passes back uchar_t type property and its count.
2923 * map_dev input should be a handle for device.
2924 *
2925 * return 0 if OK.
2926 * return error code otherwise.
2927 */
2928 int
g_dev_prop_lookup_bytes(gfc_dev_t map_dev,const char * prop_name,int * prop_data_count,uchar_t ** prop_data)2929 g_dev_prop_lookup_bytes(gfc_dev_t map_dev, const char *prop_name,
2930 int *prop_data_count, uchar_t **prop_data)
2931 {
2932 impl_map_dev_t *impl_dev;
2933 impl_map_dev_prop_t *impl_prop;
2934 int err;
2935
2936 if (map_dev == NULL) {
2937 return (L_INVALID_MAP_DEV_ADDR);
2938 }
2939
2940 if ((prop_name == NULL) || (prop_data == NULL) ||
2941 (prop_data_count == NULL)) {
2942 return (L_INVALID_ARG);
2943 }
2944
2945 impl_dev = (impl_map_dev_t *)map_dev;
2946 impl_prop = impl_dev->prop_list;
2947
2948 err = L_INVALID_MAP_DEV_PROP_NAME;
2949
2950 while (impl_prop) {
2951 if (strncmp(impl_prop->prop_name, prop_name,
2952 strlen(prop_name)) == 0) {
2953 if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
2954 err = L_INVALID_MAP_DEV_PROP_TYPE;
2955 break;
2956 }
2957 if (impl_prop->prop_data) {
2958 *prop_data = (uchar_t *)(impl_prop->prop_data);
2959 *prop_data_count = impl_prop->prop_size;
2960 return (0);
2961 } else {
2962 err = impl_prop->prop_error;
2963 }
2964 break;
2965 }
2966 impl_prop = impl_prop->next;
2967 }
2968
2969 return (err);
2970 }
2971
2972 /*
2973 * This function passes back int type property.
2974 * map_dev input should be a handle for device.
2975 *
2976 * return 0 if OK.
2977 * return error code otherwise.
2978 */
2979 int
g_dev_prop_lookup_ints(gfc_dev_t map_dev,const char * prop_name,int ** prop_data)2980 g_dev_prop_lookup_ints(gfc_dev_t map_dev, const char *prop_name,
2981 int **prop_data)
2982 {
2983 impl_map_dev_t *impl_dev;
2984 impl_map_dev_prop_t *impl_prop;
2985 int err;
2986
2987 if (map_dev == NULL) {
2988 return (L_INVALID_MAP_DEV_ADDR);
2989 }
2990
2991 if ((prop_name == NULL) || (prop_data == NULL)) {
2992 return (L_INVALID_ARG);
2993 }
2994
2995 impl_dev = (impl_map_dev_t *)map_dev;
2996 impl_prop = impl_dev->prop_list;
2997
2998 err = L_INVALID_MAP_DEV_PROP_NAME;
2999
3000 while (impl_prop) {
3001 if (strncmp(impl_prop->prop_name, prop_name,
3002 strlen(prop_name)) == 0) {
3003 if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3004 err = L_INVALID_MAP_DEV_PROP_TYPE;
3005 break;
3006 }
3007 if (impl_prop->prop_data) {
3008 *prop_data = (int *)(impl_prop->prop_data);
3009 return (0);
3010 } else {
3011 err = impl_prop->prop_error;
3012 }
3013 break;
3014 }
3015 impl_prop = impl_prop->next;
3016 }
3017
3018 return (err);
3019 }
3020
3021 /*
3022 * This function passes back int type property.
3023 * map_dev input should be a handle for device.
3024 *
3025 * return 0 if OK.
3026 * return error code otherwise.
3027 */
3028 int
g_dev_prop_lookup_strings(gfc_dev_t map_dev,const char * prop_name,char ** prop_data)3029 g_dev_prop_lookup_strings(gfc_dev_t map_dev, const char *prop_name,
3030 char **prop_data)
3031 {
3032 impl_map_dev_t *impl_dev;
3033 impl_map_dev_prop_t *impl_prop;
3034 int err;
3035
3036 if (map_dev == NULL) {
3037 return (L_INVALID_MAP_DEV_ADDR);
3038 }
3039
3040 if ((prop_name == NULL) || (prop_data == NULL)) {
3041 return (L_INVALID_ARG);
3042 }
3043
3044 impl_dev = (impl_map_dev_t *)map_dev;
3045 impl_prop = impl_dev->prop_list;
3046
3047 err = L_INVALID_MAP_DEV_PROP_NAME;
3048
3049 while (impl_prop) {
3050 if (strncmp(impl_prop->prop_name, prop_name,
3051 strlen(prop_name)) == 0) {
3052 if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3053 err = L_INVALID_MAP_DEV_PROP_TYPE;
3054 break;
3055 }
3056 if (impl_prop->prop_data) {
3057 *prop_data = (char *)(impl_prop->prop_data);
3058 return (0);
3059 } else {
3060 err = impl_prop->prop_error;
3061 }
3062 break;
3063 }
3064 impl_prop = impl_prop->next;
3065 }
3066
3067 return (err);
3068 }
3069
3070 /*
3071 * This function returns the handle for the first property of the input device.
3072 * map_dev input should be a handle form a device.
3073 *
3074 * l_err set to 0 if OK.
3075 * l_err set to error code otherwise.
3076 */
3077 gfc_prop_t
g_get_first_dev_prop(gfc_dev_t map_dev,int * l_err)3078 g_get_first_dev_prop(gfc_dev_t map_dev, int *l_err)
3079 {
3080 impl_map_dev_t *impl_dev;
3081
3082 if (l_err == NULL) {
3083 return (NULL);
3084 }
3085
3086 *l_err = 0;
3087
3088 if (map_dev == NULL) {
3089 *l_err = L_INVALID_MAP_DEV_ADDR;
3090 return (NULL);
3091 }
3092
3093 impl_dev = (impl_map_dev_t *)map_dev;
3094
3095 if (impl_dev->prop_list == NULL) {
3096 *l_err = L_NO_SUCH_PROP_FOUND;
3097 }
3098
3099 return ((gfc_prop_t)(impl_dev->prop_list));
3100 }
3101
3102 /*
3103 * This function returns the handle for next property handle of the input prop.
3104 * map_prop input should be a handle for property.
3105 *
3106 * l_err set to 0 if OK.
3107 * l_err set to error code otherwise.
3108 */
3109 gfc_prop_t
g_get_next_dev_prop(gfc_prop_t map_prop,int * l_err)3110 g_get_next_dev_prop(gfc_prop_t map_prop, int *l_err)
3111 {
3112 impl_map_dev_prop_t *impl_prop;
3113
3114 if (l_err == NULL) {
3115 return (NULL);
3116 }
3117
3118 *l_err = 0;
3119
3120 if (map_prop == NULL) {
3121 *l_err = L_INVALID_MAP_DEV_PROP;
3122 return (NULL);
3123 }
3124
3125 impl_prop = (impl_map_dev_prop_t *)map_prop;
3126
3127 if (impl_prop->next == NULL) {
3128 *l_err = L_NO_SUCH_PROP_FOUND;
3129 }
3130
3131 return ((gfc_prop_t)(impl_prop->next));
3132 }
3133
3134 /*
3135 * This function returns the name of the property of the input prop.
3136 * map_prop input should be a handle for property.
3137 *
3138 * return name string if OK.
3139 * returns NULL and l_err set to error code otherwise.
3140 */
3141 char *
g_get_dev_prop_name(gfc_prop_t map_prop,int * l_err)3142 g_get_dev_prop_name(gfc_prop_t map_prop, int *l_err)
3143 {
3144 impl_map_dev_prop_t *impl_prop;
3145
3146 if (l_err == NULL) {
3147 return (NULL);
3148 }
3149
3150 *l_err = 0;
3151
3152 if (map_prop == NULL) {
3153 *l_err = L_INVALID_MAP_DEV_PROP;
3154 return (NULL);
3155 }
3156
3157 impl_prop = (impl_map_dev_prop_t *)map_prop;
3158
3159 return (impl_prop->prop_name);
3160 }
3161
3162 /*
3163 * This function returns the type of the property of the input prop.
3164 * map_prop input should be a handle for property.
3165 *
3166 * return type if OK.
3167 * returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise.
3168 */
3169 int
g_get_dev_prop_type(gfc_prop_t map_prop,int * l_err)3170 g_get_dev_prop_type(gfc_prop_t map_prop, int *l_err)
3171 {
3172 impl_map_dev_prop_t *impl_prop;
3173
3174 if (l_err != NULL) {
3175 *l_err = 0;
3176 } else {
3177 return (L_INVALID_ARG);
3178 }
3179
3180 if (map_prop == NULL) {
3181 *l_err = L_INVALID_MAP_DEV_PROP;
3182 return (GFC_PROP_TYPE_UNKNOWN);
3183 }
3184
3185 impl_prop = (impl_map_dev_prop_t *)map_prop;
3186
3187 return (impl_prop->prop_type);
3188 }
3189
3190 /*
3191 * This function passes back uchar_t type property and its count.
3192 * map_prop input should be a handle for property.
3193 *
3194 * return 0 if OK.
3195 * return error code otherwise.
3196 */
3197 int
g_get_dev_prop_bytes(gfc_prop_t map_prop,int * prop_data_count,uchar_t ** prop_data)3198 g_get_dev_prop_bytes(gfc_prop_t map_prop, int *prop_data_count,
3199 uchar_t **prop_data)
3200 {
3201 impl_map_dev_prop_t *impl_prop;
3202
3203 if (map_prop == NULL) {
3204 return (L_INVALID_MAP_DEV_ADDR);
3205 }
3206
3207 if ((prop_data == NULL) || (prop_data_count == NULL)) {
3208 return (L_INVALID_ARG);
3209 }
3210
3211 impl_prop = (impl_map_dev_prop_t *)map_prop;
3212
3213 if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
3214 return (L_INVALID_MAP_DEV_PROP_TYPE);
3215 }
3216 if (impl_prop->prop_data) {
3217 *prop_data = (uchar_t *)(impl_prop->prop_data);
3218 *prop_data_count = impl_prop->prop_size;
3219 } else {
3220 return (impl_prop->prop_error);
3221 }
3222
3223 return (0);
3224 }
3225
3226 /*
3227 * This function passes back int type property.
3228 * map_prop input should be a handle for property.
3229 *
3230 * return 0 if OK.
3231 * return error code otherwise.
3232 */
3233 int
g_get_dev_prop_ints(gfc_prop_t map_prop,int ** prop_data)3234 g_get_dev_prop_ints(gfc_prop_t map_prop, int **prop_data)
3235 {
3236 impl_map_dev_prop_t *impl_prop;
3237
3238 if (map_prop == NULL) {
3239 return (L_INVALID_MAP_DEV_ADDR);
3240 }
3241
3242 if (prop_data == NULL) {
3243 return (L_INVALID_ARG);
3244 }
3245
3246 impl_prop = (impl_map_dev_prop_t *)map_prop;
3247
3248 if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3249 return (L_INVALID_MAP_DEV_PROP_TYPE);
3250 }
3251 if (impl_prop->prop_data) {
3252 *prop_data = (int *)(impl_prop->prop_data);
3253 } else {
3254 return (impl_prop->prop_error);
3255 }
3256
3257 return (0);
3258 }
3259
3260 /*
3261 * This function passes back string type property.
3262 * map_prop input should be a handle for property.
3263 *
3264 * return 0 if OK.
3265 * return error code otherwise.
3266 */
3267 int
g_get_dev_prop_strings(gfc_prop_t map_prop,char ** prop_data)3268 g_get_dev_prop_strings(gfc_prop_t map_prop, char **prop_data)
3269 {
3270 impl_map_dev_prop_t *impl_prop;
3271
3272 if (map_prop == NULL) {
3273 return (L_INVALID_MAP_DEV_ADDR);
3274 }
3275
3276 if (prop_data == NULL) {
3277 return (L_INVALID_ARG);
3278 }
3279
3280 impl_prop = (impl_map_dev_prop_t *)map_prop;
3281
3282 if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3283 return (L_INVALID_MAP_DEV_PROP_TYPE);
3284 }
3285 if (impl_prop->prop_data) {
3286 *prop_data = (char *)(impl_prop->prop_data);
3287 } else {
3288 return (impl_prop->prop_error);
3289 }
3290
3291 return (0);
3292 }
3293
3294 /*
3295 * Free the linked list allocated by g_rdls()
3296 */
3297 static void
g_free_rls(AL_rls * rlsptr)3298 g_free_rls(AL_rls *rlsptr)
3299 {
3300 AL_rls *trlsptr;
3301
3302 while (rlsptr != NULL) {
3303 trlsptr = rlsptr->next;
3304 free(rlsptr);
3305 rlsptr = trlsptr;
3306 }
3307 }
3308
3309 /*
3310 * Read the extended link error status block
3311 * from the specified device and Host Adapter.
3312 *
3313 * PARAMS:
3314 * path_phys - physical path to an FC device
3315 * rls_ptr - pointer to read link state structure
3316 *
3317 * RETURNS:
3318 * 0 : if OK
3319 * non-zero: otherwise
3320 */
3321 int
g_rdls(char * path_phys,struct al_rls ** rls_ptr,int verbose)3322 g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose)
3323 {
3324 char nexus_path[MAXPATHLEN], *nexus_path_ptr;
3325 int fd, fp_fd, err, length, exp_map_flag = 0, *port_addr;
3326 struct lilpmap map;
3327 AL_rls *rls, *c1 = NULL, *c2 = NULL;
3328 uchar_t i, *port_wwn_byte;
3329 la_wwn_t port_wwn;
3330 sf_al_map_t exp_map;
3331 char *charPtr, fp_path[MAXPATHLEN];
3332 uint_t dev_type;
3333 struct stat stbuf;
3334 fcio_t fcio;
3335 fc_portid_t rls_req;
3336 fc_rls_acc_t rls_payload;
3337 gfc_dev_t map_root, map_dev;
3338 uint32_t hba_port_top, state;
3339 int pathcnt = 1, count;
3340 mp_pathlist_t pathlist;
3341 int p_on = 0, p_st = 0;
3342
3343 /* return invalid path if path_phys is NULL */
3344 if (path_phys == NULL) {
3345 return (L_INVALID_PATH);
3346 }
3347 /* return invalid arg if rls_ptr is NULL */
3348 if (rls_ptr == NULL) {
3349 return (L_INVALID_ARG);
3350 }
3351
3352 *rls_ptr = rls = NULL;
3353
3354 if (strstr(path_phys, SCSI_VHCI) != NULL) {
3355 (void) strcpy(fp_path, path_phys);
3356 if (g_get_pathlist(fp_path, &pathlist)) {
3357 return (L_INVALID_PATH);
3358 }
3359 pathcnt = pathlist.path_count;
3360 p_on = p_st = 0;
3361 for (i = 0; i < pathcnt; i++) {
3362 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3363 if (pathlist.path_info[i].path_state ==
3364 MDI_PATHINFO_STATE_ONLINE) {
3365 p_on = i;
3366 break;
3367 } else if (pathlist.path_info[i].path_state ==
3368 MDI_PATHINFO_STATE_STANDBY) {
3369 p_st = i;
3370 }
3371 }
3372 }
3373 if (pathlist.path_info[p_on].path_state ==
3374 MDI_PATHINFO_STATE_ONLINE) {
3375 /* on_line path */
3376 (void) strcpy(fp_path,
3377 pathlist.path_info[p_on].path_hba);
3378 } else {
3379 /* standby or path0 */
3380 (void) strcpy(fp_path,
3381 pathlist.path_info[p_st].path_hba);
3382 }
3383 free(pathlist.path_info);
3384 } else {
3385 (void) strcpy(fp_path, path_phys);
3386 }
3387
3388 /* Get map of devices on this loop. */
3389 if ((dev_type = g_get_path_type(fp_path)) == 0) {
3390 return (L_INVALID_PATH);
3391 }
3392 if (dev_type & FC_FCA_MASK) {
3393 if (strstr(path_phys, SCSI_VHCI) != NULL) {
3394 (void) strcat(fp_path, FC_CTLR);
3395 } else if (strstr(fp_path, DRV_NAME_SSD) ||
3396 strstr(fp_path, DRV_NAME_ST) ||
3397 strstr(fp_path, SES_NAME)) {
3398 if ((charPtr = strrchr(fp_path, '/')) == NULL) {
3399 return (L_INVALID_PATH);
3400 }
3401 *charPtr = '\0';
3402 /* append devctl to the path */
3403 (void) strcat(fp_path, FC_CTLR);
3404 } else {
3405 if (stat(fp_path, &stbuf) < 0) {
3406 return (L_LSTAT_ERROR);
3407 }
3408 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
3409 /* append devctl to the path */
3410 (void) strcat(fp_path, FC_CTLR);
3411 }
3412 }
3413
3414 if ((map_root = g_dev_map_init(fp_path, &err,
3415 MAP_XPORT_PROP_ONLY)) == NULL) {
3416 return (err);
3417 }
3418
3419 } else { /* FC4_FCA_MASK type path */
3420 (void) memset(&map, 0, sizeof (struct lilpmap));
3421
3422 if ((err = g_get_nexus_path(path_phys,
3423 &nexus_path_ptr)) != 0) {
3424 return (err);
3425 }
3426 (void) strcpy(nexus_path, nexus_path_ptr);
3427 g_destroy_data(nexus_path_ptr);
3428
3429 /* open driver */
3430 if ((fd = g_object_open(nexus_path,
3431 O_NDELAY | O_RDONLY)) == -1)
3432 return (errno);
3433
3434 /*
3435 * First try using the socal version of the map.
3436 * If that fails get the expanded vesion.
3437 */
3438 if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
3439 I_DPRINTF(" FCIO_GETMAP ioctl failed.\n");
3440 if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) {
3441 I_DPRINTF(" SFIOCGMAP ioctl failed.\n");
3442 (void) close(fd);
3443 return (L_SFIOCGMAP_IOCTL_FAIL);
3444 }
3445 /* Check for reasonableness. */
3446 if ((exp_map.sf_count > 126) ||
3447 (exp_map.sf_count < 0)) {
3448 (void) close(fd);
3449 return (L_INVALID_LOOP_MAP);
3450 }
3451 for (i = 0; i < exp_map.sf_count; i++) {
3452 if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) {
3453 (void) close(fd);
3454 return (L_INVALID_LOOP_MAP);
3455 }
3456 }
3457 length = exp_map.sf_count;
3458 exp_map_flag++;
3459 } else {
3460 I_DPRINTF(" g_rdls:"
3461 " FCIO_GETMAP ioctl returned %d entries.\n",
3462 map.lilp_length);
3463 /* Check for reasonableness. */
3464 if (map.lilp_length > sizeof (map.lilp_list)) {
3465 (void) close(fd);
3466 return (L_FCIOGETMAP_INVLD_LEN);
3467 }
3468 length = map.lilp_length;
3469 }
3470 for (i = 0; i < length; i++) {
3471 if ((c2 = (struct al_rls *)
3472 g_zalloc(sizeof (struct al_rls))) == NULL) {
3473 close(fd);
3474 return (L_MALLOC_FAILED);
3475 }
3476 if (rls == NULL) {
3477 c1 = rls = c2;
3478 } else {
3479 for (c1 = rls; c1->next; c1 = c1->next) {};
3480 c1 = c1->next = c2;
3481 }
3482 (void) strcpy(c1->driver_path, nexus_path);
3483 if (exp_map_flag) {
3484 c1->payload.rls_portno = c1->al_ha =
3485 exp_map.sf_addr_pair[i].sf_al_pa;
3486 } else {
3487 c1->payload.rls_portno = c1->al_ha =
3488 map.lilp_list[i];
3489 }
3490 c1->payload.rls_linkfail =
3491 (uint_t)0xff000000; /* get LESB for this port */
3492 I_DPRINTF(" g_rdls:"
3493 " al_pa 0x%x\n", c1->payload.rls_portno);
3494
3495 if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) {
3496 /*
3497 * The ifp driver will return ENXIO when rls
3498 * is issued for same initiator on loop when
3499 * there is more than one on the loop.
3500 * Rather than completely fail, continue on.
3501 * Set values in the payload struct to -1 as
3502 * this is what socal is currently doing for
3503 * the case of same initiator rls.
3504 */
3505 if ((dev_type & FC4_PCI_FCA) &&
3506 (errno == ENXIO)) {
3507 c1->payload.rls_linkfail =
3508 c1->payload.rls_syncfail =
3509 c1->payload.rls_sigfail =
3510 c1->payload.rls_primitiverr =
3511 c1->payload.rls_invalidword =
3512 c1->payload.rls_invalidcrc =
3513 (uint_t)0xffffffff;
3514 } else {
3515 I_DPRINTF(" FCIO_LINKSTATUS ioctl"
3516 " failed with errno %d.\n", errno);
3517 g_free_rls(rls);
3518 (void) close(fd);
3519 return (L_FCIO_LINKSTATUS_FAILED);
3520 }
3521 }
3522 I_DPRINTF(" g_rdls: al_pa returned by ioctl 0x%x\n",
3523 c1->payload.rls_portno);
3524 }
3525 *rls_ptr = rls; /* Pass back pointer */
3526
3527 (void) close(fd);
3528 return (0);
3529 }
3530
3531 /* Now we need to take care of FC_FCA_MASK case. */
3532 /* we have map created already via g_dev_map_init. */
3533 if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3534 g_dev_map_fini(map_root);
3535 return (err);
3536 }
3537
3538 if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
3539 g_dev_map_fini(map_root);
3540 if (err != L_NO_SUCH_DEV_FOUND) {
3541 return (err);
3542 } else {
3543 return (L_NO_DEVICES_FOUND);
3544 }
3545 }
3546
3547 while (map_dev) {
3548 if ((err = g_dev_prop_lookup_ints(
3549 map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3550 g_dev_map_fini(map_root);
3551 g_free_rls(rls);
3552 return (err);
3553 }
3554
3555 if ((c2 = (struct al_rls *)
3556 g_zalloc(sizeof (struct al_rls))) == NULL) {
3557 g_dev_map_fini(map_root);
3558 g_free_rls(rls);
3559 close(fd);
3560 return (L_MALLOC_FAILED);
3561 }
3562 if (rls == NULL) {
3563 c1 = rls = c2;
3564 } else {
3565 for (c1 = rls; c1->next; c1 = c1->next) {};
3566 c1 = c1->next = c2;
3567 }
3568 /* Set the al_ha here */
3569 c1->al_ha = rls_req.port_id = *port_addr;
3570
3571 /*
3572 * fp uses different input/output structures for
3573 * rls. Load the values returned for the fp ioctl
3574 * into the structure passed back to the caller
3575 * Note: There is no reason for the path
3576 * to be loaded into AL_rls as is done for socal/ifp
3577 * above.
3578 */
3579 if ((hba_port_top == FC_TOP_FABRIC) ||
3580 (hba_port_top == FC_TOP_PUBLIC_LOOP)) {
3581 if ((err = g_dev_prop_lookup_bytes(
3582 map_dev, PORT_WWN_PROP, &count,
3583 &port_wwn_byte)) != 0) {
3584 g_dev_map_fini(map_root);
3585 g_free_rls(rls);
3586 return (err);
3587 }
3588 memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE);
3589 if ((err = g_get_dev_port_state(
3590 fp_path, port_wwn, &state)) == 0) {
3591 if (state != PORT_DEVICE_LOGGED_IN) {
3592 if ((err = g_dev_login(fp_path,
3593 port_wwn)) != 0) {
3594
3595 c1->payload.rls_linkfail =
3596 c1->payload.rls_syncfail =
3597 c1->payload.rls_sigfail =
3598 c1->payload.rls_primitiverr =
3599 c1->payload.rls_invalidword =
3600 c1->payload.rls_invalidcrc =
3601 (uint_t)0xffffffff;
3602 if (((map_dev =
3603 g_get_next_dev(map_dev,
3604 &err))
3605 == NULL) &&
3606 (err !=
3607 L_NO_SUCH_DEV_FOUND)) {
3608 g_dev_map_fini(
3609 map_root);
3610 g_free_rls(rls);
3611 return (err);
3612 }
3613 continue;
3614 }
3615 }
3616 } /* if g_get_dev_port_state fails proceed. */
3617 }
3618
3619 fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3620 if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3621 g_dev_map_fini(map_root);
3622 g_free_rls(rls);
3623 return (L_OPEN_PATH_FAIL);
3624 }
3625 fcio.fcio_cmd = FCIO_LINK_STATUS;
3626 fcio.fcio_ibuf = (caddr_t)&rls_req;
3627 fcio.fcio_ilen = sizeof (rls_req);
3628 fcio.fcio_xfer = FCIO_XFER_RW;
3629 fcio.fcio_flags = 0;
3630 fcio.fcio_obuf = (caddr_t)&rls_payload;
3631 fcio.fcio_olen = sizeof (rls_payload);
3632 if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3633 c1->payload.rls_linkfail =
3634 c1->payload.rls_syncfail =
3635 c1->payload.rls_sigfail =
3636 c1->payload.rls_primitiverr =
3637 c1->payload.rls_invalidword =
3638 c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3639 } else {
3640 /*
3641 * Load the values into the struct passed
3642 * back to the caller
3643 */
3644 c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3645 c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3646 c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3647 c1->payload.rls_primitiverr =
3648 rls_payload.rls_prim_seq_err;
3649 c1->payload.rls_invalidword =
3650 rls_payload.rls_invalid_word;
3651 c1->payload.rls_invalidcrc =
3652 rls_payload.rls_invalid_crc;
3653 }
3654 (void) close(fp_fd);
3655
3656 if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3657 (err != L_NO_SUCH_DEV_FOUND)) {
3658 g_dev_map_fini(map_root);
3659 g_free_rls(rls);
3660 return (err);
3661 }
3662 }
3663
3664 /* for Leadville issue a final call for the initiator */
3665
3666 if ((err = g_dev_prop_lookup_ints(
3667 map_root, PORT_ADDR_PROP, &port_addr)) != 0) {
3668 g_dev_map_fini(map_root);
3669 g_free_rls(rls);
3670 return (err);
3671 }
3672
3673 if ((c2 = (struct al_rls *)
3674 g_zalloc(sizeof (struct al_rls))) == NULL) {
3675 g_dev_map_fini(map_root);
3676 g_free_rls(rls);
3677 return (L_MALLOC_FAILED);
3678 }
3679 if (rls == NULL) {
3680 c1 = rls = c2;
3681 } else {
3682 for (c1 = rls; c1->next; c1 = c1->next) {};
3683 c1 = c1->next = c2;
3684 }
3685
3686 c1->al_ha = rls_req.port_id = *port_addr;
3687
3688 if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3689 g_dev_map_fini(map_root);
3690 g_free_rls(rls);
3691 return (L_OPEN_PATH_FAIL);
3692 }
3693
3694 fcio.fcio_cmd = FCIO_LINK_STATUS;
3695 fcio.fcio_ibuf = (caddr_t)&rls_req;
3696 fcio.fcio_ilen = sizeof (rls_req);
3697 fcio.fcio_xfer = FCIO_XFER_RW;
3698 fcio.fcio_flags = 0;
3699 fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3700 fcio.fcio_obuf = (caddr_t)&rls_payload;
3701 fcio.fcio_olen = sizeof (rls_payload);
3702
3703 if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3704 c1->payload.rls_linkfail =
3705 c1->payload.rls_syncfail =
3706 c1->payload.rls_sigfail =
3707 c1->payload.rls_primitiverr =
3708 c1->payload.rls_invalidword =
3709 c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3710 } else {
3711 /*
3712 * Load the values into the struct passed
3713 * back to the caller
3714 */
3715 c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3716 c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3717 c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3718 c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err;
3719 c1->payload.rls_invalidword = rls_payload.rls_invalid_word;
3720 c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc;
3721 (void) close(fp_fd);
3722 }
3723 (void) close(fp_fd);
3724
3725 *rls_ptr = rls; /* Pass back pointer */
3726
3727 g_dev_map_fini(map_root);
3728 return (0);
3729 }
3730
wwnConversion(uchar_t * wwn)3731 static u_longlong_t wwnConversion(uchar_t *wwn)
3732 {
3733 u_longlong_t tmp;
3734 memcpy(&tmp, wwn, sizeof (u_longlong_t));
3735 return (tmp);
3736 }
3737
3738 /*
3739 * Get device World Wide Name (port and node) for device at path
3740 * and add all WWNs to the wwn_list_found list.
3741 *
3742 * RETURN: 0 O.K.
3743 *
3744 * INPUTS:
3745 * - path_phys must be of a device, either an IB or disk.
3746 */
3747 static int
get_wwns(char * path_phys,uchar_t port_wwn[],uchar_t node_wwn[],int * al_pa,struct wwn_list_found_struct ** wwn_list_found)3748 get_wwns(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], int *al_pa,
3749 struct wwn_list_found_struct **wwn_list_found)
3750 {
3751 uint32_t hba_port_top;
3752 int i, err, count;
3753 char *char_ptr, *ptr;
3754 int found = 0, pathcnt, *port_addr;
3755 unsigned long long pwwn;
3756 uchar_t *port_wwn_byte, *node_wwn_byte;
3757 char drvr_path[MAXPATHLEN];
3758 int p_on = 0, p_st = 0;
3759 mp_pathlist_t pathlist;
3760 char pwwn1[WWN_S_LEN];
3761 gfc_dev_t map_root, map_dev;
3762 hrtime_t start_time, end_time;
3763 char *env = NULL;
3764
3765 P_DPRINTF(" g_get_wwn: Getting device WWN"
3766 " and al_pa for device: %s\n",
3767 path_phys);
3768
3769 if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
3770 start_time = gethrtime();
3771 }
3772
3773 /*
3774 * Get the loop identifier (switch setting) from the path.
3775 *
3776 * This assumes the path looks something like this:
3777 * /devices/.../SUNW,socal@3,0/SUNW,sf@0,0/SUNW,ssd@x,0
3778 * or
3779 * /devices/.../SUNW,qlc@5/SUNW,fp@0,0/SUNW,ssd@x,0
3780 */
3781 if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
3782 return (L_INVLD_PATH_NO_ATSIGN_FND);
3783 }
3784 char_ptr++; /* point to the loop identifier or WWN */
3785
3786 (void) strcpy(drvr_path, path_phys);
3787 /* This function allocs mem for map.dev_addr on success */
3788 if (strstr(drvr_path, SCSI_VHCI)) {
3789 if (g_get_pathlist(drvr_path, &pathlist)) {
3790 return (L_INVALID_PATH);
3791 }
3792 pathcnt = pathlist.path_count;
3793 p_on = p_st = 0;
3794 for (i = 0; i < pathcnt; i++) {
3795 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3796 if (pathlist.path_info[i].path_state ==
3797 MDI_PATHINFO_STATE_ONLINE) {
3798 p_on = i;
3799 break;
3800 } else if (pathlist.path_info[i].path_state ==
3801 MDI_PATHINFO_STATE_STANDBY) {
3802 p_st = i;
3803 }
3804 }
3805 }
3806 if (p_on == i) {
3807 /* on_line path */
3808 (void) strcpy(drvr_path,
3809 pathlist.path_info[p_on].path_hba);
3810 (void) strncpy(pwwn1,
3811 pathlist.path_info[p_on].path_addr,
3812 WWN_S_LEN - 1);
3813 pwwn1[WWN_S_LEN - 1] = '\0';
3814 } else {
3815 /* standby or path0 */
3816 (void) strcpy(drvr_path,
3817 pathlist.path_info[p_st].path_hba);
3818 (void) strncpy(pwwn1,
3819 pathlist.path_info[p_st].path_addr,
3820 WWN_S_LEN - 1);
3821 pwwn1[WWN_S_LEN - 1] = '\0';
3822 }
3823 free(pathlist.path_info);
3824 (void) strcat(drvr_path, FC_CTLR);
3825 }
3826 if ((map_root = g_dev_map_init(drvr_path, &err,
3827 MAP_XPORT_PROP_ONLY)) == NULL) {
3828 return (err);
3829 }
3830
3831 if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3832 g_dev_map_fini(map_root);
3833 return (err);
3834 }
3835
3836 if (strstr(path_phys, SCSI_VHCI)) {
3837 char_ptr = pwwn1;
3838 } else {
3839 /*
3840 * Format of WWN is
3841 * ssd@w2200002037000f96,0:a,raw
3842 */
3843 if (*char_ptr != 'w') {
3844 g_dev_map_fini(map_root);
3845 return (L_INVLD_WWN_FORMAT);
3846 }
3847 char_ptr++;
3848 }
3849 pwwn = strtoull(char_ptr, &ptr, 16);
3850 if (ptr == char_ptr) {
3851 g_dev_map_fini(map_root);
3852 return (L_NO_WWN_FOUND_IN_PATH);
3853 }
3854 P_DPRINTF(" g_get_wwn: Looking for WWN "
3855 "0x%llx\n", pwwn);
3856
3857 if (((map_dev = g_get_first_dev(map_root, &err)) == NULL) &&
3858 (err != L_NO_SUCH_DEV_FOUND)) {
3859 g_dev_map_fini(map_root);
3860 return (err);
3861 }
3862
3863 while (map_dev) {
3864 if ((err = g_dev_prop_lookup_bytes(map_dev,
3865 PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) {
3866 g_dev_map_fini(map_root);
3867 return (err);
3868 }
3869 if ((err = g_dev_prop_lookup_bytes(map_dev,
3870 NODE_WWN_PROP, &count, &node_wwn_byte)) != 0) {
3871 g_dev_map_fini(map_root);
3872 return (err);
3873 }
3874
3875 if (pwwn == wwnConversion(port_wwn_byte) && found != 1) {
3876 found = 1;
3877 memcpy(port_wwn, port_wwn_byte, FC_WWN_SIZE);
3878 memcpy(node_wwn, node_wwn_byte, FC_WWN_SIZE);
3879 if ((err = g_dev_prop_lookup_ints(
3880 map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3881 g_dev_map_fini(map_root);
3882 return (err);
3883 }
3884 *al_pa = *port_addr;
3885 }
3886 add_wwn_entry(wwn_list_found, port_wwn_byte,
3887 node_wwn_byte);
3888
3889 if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3890 (err != L_NO_SUCH_DEV_FOUND)) {
3891 g_dev_map_fini(map_root);
3892 return (err);
3893 }
3894 }
3895 if (!found) {
3896 g_dev_map_fini(map_root);
3897 return (L_NO_LOOP_ADDRS_FOUND);
3898 }
3899
3900 g_dev_map_fini(map_root);
3901 if (env != NULL) {
3902 end_time = gethrtime();
3903 fprintf(stdout, " get_wwns: "
3904 "\t\tTime = %lld millisec\n",
3905 (end_time - start_time)/1000000);
3906 }
3907 return (0);
3908 }
3909
3910 /*
3911 * Get device World Wide Name and AL_PA for device at path
3912 *
3913 * RETURN: 0 O.K.
3914 *
3915 * INPUTS:
3916 * - path_phys must be of a device, either an IB or disk.
3917 */
3918 int
g_get_wwn(char * path_phys,uchar_t port_wwn[],uchar_t node_wwn[],int * al_pa,int verbose)3919 g_get_wwn(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[],
3920 int *al_pa, int verbose)
3921 {
3922 struct wwn_list_found_struct *wwn_list_found = NULL;
3923 int ret;
3924
3925 /* return invalid path if the argument is NULL */
3926 if (path_phys == NULL) {
3927 return (L_INVALID_PATH);
3928 }
3929 /* return invalid arg if the argument is NULL */
3930 if ((port_wwn == NULL) || (node_wwn == NULL) || (al_pa == NULL)) {
3931 return (L_INVALID_ARG);
3932 }
3933
3934 ret = get_wwns(path_phys, port_wwn, node_wwn, al_pa, &wwn_list_found);
3935 g_free_wwn_list_found(&wwn_list_found);
3936 return (ret);
3937 }
3938
3939 int
g_get_serial_number(char * path,uchar_t * serial_number,size_t * serial_number_len)3940 g_get_serial_number(char *path, uchar_t *serial_number,
3941 size_t *serial_number_len)
3942 {
3943 int fd, status = 0;
3944 L_inquiry80 inq80;
3945
3946 /* return invalid path if path is NULL */
3947 if (path == NULL) {
3948 return (L_INVALID_PATH);
3949 }
3950 /* return invalid arg if serial_number is NULL */
3951 if (serial_number == NULL) {
3952 return (L_INVALID_ARG);
3953 }
3954
3955 P_DPRINTF(" g_get_serial_number: path: %s\n", path);
3956 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) {
3957 return (L_OPEN_PATH_FAIL);
3958 }
3959 /*
3960 * Call the inquiry cmd on page 0x80 only if the vendor
3961 * supports page 0x80.
3962 */
3963 if ((g_find_supported_inq_page(fd, 0x80))) {
3964 /*
3965 * Let's retrieve the serial number from page 0x80
3966 * and store it in the inquiry structure
3967 */
3968 status = g_scsi_inquiry_cmd80(fd,
3969 (uchar_t *)&inq80,
3970 sizeof (struct l_inquiry80_struct));
3971 if (status == 0) {
3972 if (*serial_number_len > inq80.inq_page_len)
3973 *serial_number_len = inq80.inq_page_len;
3974 strncpy((char *)serial_number, (char *)inq80.inq_serial,
3975 *serial_number_len);
3976 } else {
3977 char unavail[] = "Unavailable";
3978 status = 0;
3979 if (*serial_number_len > strlen(unavail))
3980 *serial_number_len = strlen(unavail);
3981 strncpy((char *)serial_number, unavail,
3982 *serial_number_len);
3983 }
3984 } else {
3985 /*
3986 * page 0x80 is not supported, so print the
3987 * appropriate message.
3988 */
3989 char unsupp[] = "Unsupported";
3990 if (*serial_number_len > strlen(unsupp))
3991 *serial_number_len = strlen(unsupp);
3992 strncpy((char *)serial_number, unsupp,
3993 *serial_number_len);
3994 }
3995 (void) close(fd);
3996 return (status);
3997 }
3998
3999 int
g_get_inquiry(char * path,L_inquiry * l_inquiry)4000 g_get_inquiry(char *path, L_inquiry *l_inquiry)
4001 {
4002 int fd, status;
4003
4004 /* return invalid path if path is NULL */
4005 if (path == NULL) {
4006 return (L_INVALID_PATH);
4007 }
4008 /* return invalid arg if l_inquiry is NULL */
4009 if (l_inquiry == NULL) {
4010 return (L_INVALID_ARG);
4011 }
4012
4013 P_DPRINTF(" g_get_inquiry: path: %s\n", path);
4014 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4015 return (L_OPEN_PATH_FAIL);
4016 status = g_scsi_inquiry_cmd(fd,
4017 (uchar_t *)l_inquiry, sizeof (struct l_inquiry_struct));
4018
4019 (void) close(fd);
4020 return (status);
4021 }
4022
4023 /*
4024 * Function to retrieve inquiry page 0x80 from the device
4025 */
4026 static int
g_scsi_inquiry_cmd80(int fd,uchar_t * buf_ptr,int buf_len)4027 g_scsi_inquiry_cmd80(int fd, uchar_t *buf_ptr, int buf_len)
4028 {
4029 struct uscsi_cmd ucmd;
4030 my_cdb_g0 cdb = {SCMD_INQUIRY, 0x1, 0x80, 0, 0x10, 0};
4031 struct scsi_extended_sense sense;
4032
4033 (void) memset(buf_ptr, 0, buf_len);
4034 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
4035 cdb.count = (uchar_t)buf_len;
4036 ucmd.uscsi_cdb = (caddr_t)&cdb;
4037 ucmd.uscsi_cdblen = CDB_GROUP0;
4038 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
4039 ucmd.uscsi_buflen = buf_len;
4040 ucmd.uscsi_rqbuf = (caddr_t)&sense;
4041 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
4042 ucmd.uscsi_timeout = 60;
4043 return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT));
4044 }
4045
4046 /*
4047 * Function to determine if the given page is supported by vendor.
4048 */
4049 static int
g_find_supported_inq_page(int fd,int page_num)4050 g_find_supported_inq_page(int fd, int page_num)
4051 {
4052 struct uscsi_cmd ucmd;
4053 my_cdb_g0 cdb = {SCMD_INQUIRY, 0x1, 0, 0, 0xff, 0};
4054 struct scsi_extended_sense sense;
4055 L_inquiry00 inq00;
4056 uchar_t *data;
4057 int status = 0;
4058 int index;
4059
4060 (void) memset((char *)&ucmd, 0, sizeof (ucmd));
4061 cdb.count = (uchar_t)(sizeof (L_inquiry00));
4062 ucmd.uscsi_cdb = (caddr_t)&cdb;
4063 ucmd.uscsi_cdblen = CDB_GROUP0;
4064 ucmd.uscsi_bufaddr = (caddr_t)&inq00;
4065 ucmd.uscsi_buflen = sizeof (inq00);
4066 ucmd.uscsi_rqbuf = (caddr_t)&sense;
4067 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
4068 ucmd.uscsi_timeout = 60;
4069 status = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT);
4070 if (status) {
4071 return (0);
4072 }
4073 data = (uchar_t *)&inq00;
4074 for (index = 4; (index <= inq00.len+3)&&
4075 (data[index] <= page_num); index ++) {
4076 if (data[index] == page_num) {
4077 return (1);
4078 }
4079 }
4080 return (0);
4081 }
4082
4083 int
g_get_perf_statistics(char * path,uchar_t * perf_ptr)4084 g_get_perf_statistics(char *path, uchar_t *perf_ptr)
4085 {
4086 int fd;
4087
4088 P_DPRINTF(" g_get_perf_statistics: Get Performance Statistics:"
4089 "\n Path:%s\n",
4090 path);
4091
4092 /* initialize tables */
4093 (void) memset(perf_ptr, 0, sizeof (int));
4094
4095 /* open controller */
4096 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4097 return (L_OPEN_PATH_FAIL);
4098
4099
4100 /* update parameters in the performance table */
4101
4102 /* get the period in seconds */
4103
4104
4105 (void) close(fd);
4106
4107 return (0);
4108 }
4109
4110
4111 int
g_start(char * path)4112 g_start(char *path)
4113 {
4114 int status;
4115 int fd;
4116
4117 P_DPRINTF(" g_start: Start: Path %s\n", path);
4118 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4119 return (L_OPEN_PATH_FAIL);
4120 status = g_scsi_start_cmd(fd);
4121 (void) close(fd);
4122 return (status);
4123 }
4124
4125 int
g_stop(char * path,int immediate_flag)4126 g_stop(char *path, int immediate_flag)
4127 {
4128 int status, fd;
4129
4130 P_DPRINTF(" g_stop: Stop: Path %s\n", path);
4131 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4132 return (errno);
4133 status = g_scsi_stop_cmd(fd, immediate_flag);
4134 (void) close(fd);
4135 return (status);
4136 }
4137
4138 int
g_reserve(char * path)4139 g_reserve(char *path)
4140 {
4141 int fd, status;
4142
4143 P_DPRINTF(" g_reserve: Reserve: Path %s\n", path);
4144 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4145 return (L_OPEN_PATH_FAIL);
4146 status = g_scsi_reserve_cmd(fd);
4147 (void) close(fd);
4148 return (status);
4149 }
4150
4151 int
g_release(char * path)4152 g_release(char *path)
4153 {
4154 int fd, status;
4155
4156 P_DPRINTF(" g_release: Release: Path %s\n", path);
4157 if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4158 return (L_OPEN_PATH_FAIL);
4159 status = g_scsi_release_cmd(fd);
4160 (void) close(fd);
4161 return (status);
4162 }
4163
4164 static char
ctoi(char c)4165 ctoi(char c)
4166 {
4167 if ((c >= '0') && (c <= '9'))
4168 c -= '0';
4169 else if ((c >= 'A') && (c <= 'F'))
4170 c = c - 'A' + 10;
4171 else if ((c >= 'a') && (c <= 'f'))
4172 c = c - 'a' + 10;
4173 else
4174 c = -1;
4175 return (c);
4176 }
4177
4178 int
g_string_to_wwn(uchar_t * wwn,uchar_t * wwnp)4179 g_string_to_wwn(uchar_t *wwn, uchar_t *wwnp)
4180 {
4181 int i;
4182 char c, c1;
4183
4184 *wwnp++ = 0;
4185 *wwnp++ = 0;
4186 for (i = 0; i < WWN_SIZE - 2; i++, wwnp++) {
4187 c = ctoi(*wwn++);
4188 c1 = ctoi(*wwn++);
4189 if (c == -1 || c1 == -1)
4190 return (-1);
4191 *wwnp = ((c << 4) + c1);
4192 }
4193
4194 return (0);
4195
4196 }
4197
4198 /*
4199 * Converts a string of WWN ASCII characters to a
4200 * binary representation.
4201 *
4202 * Input: string - pointer to uchar_t array
4203 * WWN in ASCII
4204 * length: 16 bytes
4205 * Output: wwn - pointer to uchar_t array
4206 * containing WWN result
4207 * length: 8 bytes
4208 * Returns:
4209 * non-zero on error
4210 * zero on success
4211 */
4212 int
string_to_wwn(uchar_t * string,uchar_t * wwn)4213 string_to_wwn(uchar_t *string, uchar_t *wwn)
4214 {
4215 int i;
4216 char c, c1;
4217 uchar_t *wwnp;
4218
4219 wwnp = wwn;
4220
4221 for (i = 0; i < WWN_SIZE; i++, wwnp++) {
4222
4223 c = ctoi(*string++);
4224 c1 = ctoi(*string++);
4225 if (c == -1 || c1 == -1)
4226 return (-1);
4227 *wwnp = ((c << 4) + c1);
4228 }
4229
4230 return (0);
4231
4232 }
4233
4234
4235 /*
4236 * Get multiple paths to a given device port.
4237 * INPUTS:
4238 * port WWN string.
4239 */
4240 int
g_get_port_multipath(char * port_wwn_s,struct dlist ** dlh,int verbose)4241 g_get_port_multipath(char *port_wwn_s, struct dlist **dlh, int verbose)
4242 {
4243 int err;
4244 WWN_list *wwn_list, *wwn_list_ptr;
4245 struct dlist *dlt, *dl;
4246
4247
4248 /* Initialize list structures. */
4249 dl = *dlh = dlt = (struct dlist *)NULL;
4250 wwn_list = wwn_list_ptr = NULL;
4251
4252 H_DPRINTF(" g_get_port_multipath: Looking for multiple paths for"
4253 " device with\n port WWW:"
4254 "%s\n", port_wwn_s);
4255
4256 if (err = g_get_wwn_list(&wwn_list, verbose)) {
4257 return (err);
4258 }
4259
4260 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4261 wwn_list_ptr = wwn_list_ptr->wwn_next) {
4262 if (strcmp(port_wwn_s, wwn_list_ptr->port_wwn_s) == 0) {
4263 if ((dl = (struct dlist *)
4264 g_zalloc(sizeof (struct dlist))) == NULL) {
4265 while (*dlh != NULL) {
4266 dl = (*dlh)->next;
4267 (void) g_destroy_data(*dlh);
4268 *dlh = dl;
4269 }
4270 (void) g_free_wwn_list(&wwn_list);
4271 return (L_MALLOC_FAILED);
4272 }
4273 H_DPRINTF(" g_get_port_multipath:"
4274 " Found multipath:\n %s\n",
4275 wwn_list_ptr->physical_path);
4276 dl->dev_path = strdup(wwn_list_ptr->physical_path);
4277 dl->logical_path = strdup(wwn_list_ptr->logical_path);
4278 if (*dlh == NULL) {
4279 *dlh = dlt = dl;
4280 } else {
4281 dlt->next = dl;
4282 dl->prev = dlt;
4283 dlt = dl;
4284 }
4285 }
4286 }
4287 (void) g_free_wwn_list(&wwn_list);
4288 return (0);
4289 }
4290
4291
4292
4293 /*
4294 * Get multiple paths to a given disk/tape device.
4295 * The arg: devpath should be the physical path to device.
4296 *
4297 * OUTPUT:
4298 * multipath_list points to a list of multiple paths to the device.
4299 * NOTE: The caller must free the allocated list (dlist).
4300 *
4301 * RETURNS:
4302 * 0 if O.K.
4303 * non-zero otherwise
4304 */
4305 int
g_get_multipath(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list,int verbose)4306 g_get_multipath(char *devpath, struct dlist **multipath_list,
4307 struct wwn_list_struct *wwn_list, int verbose)
4308 {
4309 int err;
4310
4311 H_DPRINTF(" g_get_multipath: Looking for multiple paths for"
4312 " device at path: %s\n", devpath);
4313
4314 /* return invalid path if devpath is NULL */
4315 if (devpath == NULL) {
4316 return (L_INVALID_PATH);
4317 }
4318 /* return invalid arg if argument is NULL */
4319 if ((multipath_list == NULL) || (wwn_list == NULL)) {
4320 return (L_INVALID_ARG);
4321 }
4322
4323 if (strstr(devpath, DRV_NAME_SSD) != NULL) {
4324 err = get_multipath_disk(devpath, multipath_list, wwn_list);
4325 } else {
4326 err = get_multipath(devpath, multipath_list, wwn_list);
4327 }
4328
4329 return (err);
4330 }
4331
4332
4333 /*
4334 * Returns multipath information for a ssd device.
4335 * Inputs:
4336 * devpath: device path to for requested multipath info
4337 * wwn_list: returned from g_get_wwn_list or devices_get_all
4338 * Output:
4339 * multipath_list: dlist list of paths
4340 * Returns:
4341 * 0 on success
4342 * non-zero on failure
4343 */
4344 int
get_multipath_disk(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list)4345 get_multipath_disk(char *devpath, struct dlist **multipath_list,
4346 struct wwn_list_struct *wwn_list)
4347 {
4348 WWN_list *wwn_list_ptr;
4349 struct dlist *dl = NULL, *dlt = NULL;
4350 ddi_devid_t devid = NULL;
4351 int err;
4352 di_node_t root;
4353 struct mplist_struct *mplistp = NULL, *mplisth = NULL;
4354
4355 if (wwn_list == NULL || multipath_list == NULL || devpath == NULL) {
4356 return (L_NULL_WWN_LIST);
4357 }
4358
4359 if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
4360 return (L_DEV_SNAPSHOT_FAILED);
4361 }
4362
4363 if ((err = g_devid_get(devpath, &devid, root, SSD_DRVR_NAME)) != 0) {
4364 di_fini(root);
4365 return (err);
4366 }
4367
4368 *multipath_list = (struct dlist *)NULL;
4369 if ((err = devid_get_all(devid, root, SSD_DRVR_NAME, &mplisth)) != 0) {
4370 di_fini(root);
4371 return (err);
4372 }
4373
4374 if (mplisth == NULL) {
4375 di_fini(root);
4376 return (L_NULL_WWN_LIST);
4377 }
4378
4379 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4380 wwn_list_ptr = wwn_list_ptr->wwn_next) {
4381 /*
4382 * When a path is found from the list, load the logical
4383 * and physical dev path
4384 */
4385 for (mplistp = mplisth; mplistp != NULL;
4386 mplistp = mplistp->next) {
4387 if (strncmp(mplistp->devpath,
4388 wwn_list_ptr->physical_path,
4389 strlen(mplistp->devpath)) == 0) {
4390
4391 /* Load multipath list */
4392 if ((dl = (struct dlist *)
4393 calloc(1, sizeof (struct dlist))) == NULL) {
4394 while (*multipath_list != NULL) {
4395 dl = dlt->next;
4396 g_destroy_data(dlt);
4397 dlt = dl;
4398 }
4399 di_fini(root);
4400 return (L_MALLOC_FAILED);
4401 }
4402 H_DPRINTF(
4403 " g_get_multipath: Found multipath=%s\n",
4404 wwn_list_ptr->physical_path);
4405 dl->logical_path =
4406 strdup(wwn_list_ptr->logical_path);
4407 dl->dev_path =
4408 strdup(wwn_list_ptr->physical_path);
4409 if (*multipath_list == NULL) {
4410 *multipath_list = dlt = dl;
4411 } else {
4412 dlt->next = dl;
4413 dl->prev = dlt;
4414 dlt = dl;
4415 }
4416 }
4417 }
4418 }
4419 di_fini(root);
4420 mplist_free(mplisth);
4421 return (0);
4422 }
4423
4424 int
get_multipath(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list)4425 get_multipath(char *devpath, struct dlist **multipath_list,
4426 struct wwn_list_struct *wwn_list)
4427 {
4428 WWN_list *wwn_list_ptr;
4429 struct dlist *dl, *dlt;
4430 char path[MAXPATHLEN], m_phys_path[MAXPATHLEN], *ptr;
4431 int len;
4432 int lun_a = -1;
4433 char node_wwn_s[WWN_S_LEN];
4434
4435 if (devpath == NULL) {
4436 return (L_INVALID_PATH);
4437 }
4438
4439 /* Strip partition information. */
4440 if ((ptr = strrchr(devpath, ':')) != NULL) {
4441 len = strlen(devpath) - strlen(ptr);
4442 (void) strncpy(path, devpath, len);
4443 path[len] = '\0';
4444 } else {
4445 (void) strcpy(path, devpath);
4446 }
4447
4448 *multipath_list = dl = dlt = (struct dlist *)NULL;
4449
4450
4451 if (wwn_list == NULL) {
4452 return (L_NULL_WWN_LIST);
4453 }
4454
4455 for (*node_wwn_s = NULL, wwn_list_ptr = wwn_list;
4456 wwn_list_ptr != NULL;
4457 wwn_list_ptr = wwn_list_ptr->wwn_next) {
4458
4459 if ((ptr = strrchr(wwn_list_ptr->physical_path, ':')) != NULL) {
4460 len = strlen(wwn_list_ptr->physical_path) - strlen(ptr);
4461 (void) strncpy(m_phys_path, wwn_list_ptr->physical_path,
4462 len);
4463 m_phys_path[len] = '\0';
4464 } else {
4465 (void) strcpy(m_phys_path, wwn_list_ptr->physical_path);
4466 }
4467
4468 if (strcasecmp(m_phys_path, path) == 0) {
4469 (void) strcpy(node_wwn_s, wwn_list_ptr->node_wwn_s);
4470 break;
4471 }
4472 }
4473
4474 if (*node_wwn_s == NULL) {
4475 H_DPRINTF("node_wwn_s is NULL!\n");
4476 return (L_NO_NODE_WWN_IN_WWNLIST);
4477 }
4478
4479 lun_a = g_get_lun_number(wwn_list_ptr->physical_path);
4480
4481 for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4482 wwn_list_ptr = wwn_list_ptr->wwn_next) {
4483 if ((strcmp(node_wwn_s, wwn_list_ptr->node_wwn_s) == 0) &&
4484 ((lun_a < 0) || (lun_a ==
4485 g_get_lun_number(wwn_list_ptr->physical_path)))) {
4486
4487 if ((dl = (struct dlist *)
4488 g_zalloc(sizeof (struct dlist))) == NULL) {
4489 while (*multipath_list != NULL) {
4490 dl = dlt->next;
4491 (void) g_destroy_data(dlt);
4492 dlt = dl;
4493 }
4494 return (L_MALLOC_FAILED);
4495 }
4496 H_DPRINTF(" g_get_multipath: Found multipath=%s\n",
4497 wwn_list_ptr->physical_path);
4498 dl->dev_path = strdup(wwn_list_ptr->physical_path);
4499 dl->logical_path = strdup(wwn_list_ptr->logical_path);
4500 if (*multipath_list == NULL) {
4501 *multipath_list = dlt = dl;
4502 } else {
4503 dlt->next = dl;
4504 dl->prev = dlt;
4505 dlt = dl;
4506 }
4507 }
4508 }
4509 return (0);
4510 }
4511
4512 /*
4513 * Free a multipath list
4514 *
4515 */
4516 void
g_free_multipath(struct dlist * dlh)4517 g_free_multipath(struct dlist *dlh)
4518 {
4519 struct dlist *dl;
4520
4521 while (dlh != NULL) {
4522 dl = dlh->next;
4523 if (dlh->dev_path != NULL)
4524 (void) g_destroy_data(dlh->dev_path);
4525 if (dlh->logical_path != NULL)
4526 (void) g_destroy_data(dlh->logical_path);
4527 (void) g_destroy_data(dlh);
4528 dlh = dl;
4529 }
4530 }
4531
4532
4533
4534 /*
4535 * Get the path to the nexus (HBA) driver.
4536 * This assumes the path looks something like this:
4537 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4538 * or maybe this
4539 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
4540 * or
4541 * /devices/sbus@1f,0/SUNW,socal@1,0
4542 * or
4543 * /devices/sbus@1f,0/SUNW,socal@1,0:1
4544 * or
4545 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4546 * (or "qlc" instead of "socal" and "fp" for "sf")
4547 *
4548 * Which should resolve to a path like this:
4549 * /devices/sbus@1f,0/SUNW,socal@1,0:1
4550 * or
4551 * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4552 *
4553 * or
4554 * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
4555 * which should resolve to
4556 * /devices/pci@4,2000/scsi@1:devctl
4557 */
4558 int
g_get_nexus_path(char * path_phys,char ** nexus_path)4559 g_get_nexus_path(char *path_phys, char **nexus_path)
4560 {
4561 uchar_t port = 0;
4562 int port_flag = 0, i = 0, pathcnt = 1;
4563 char *char_ptr;
4564 char drvr_path[MAXPATHLEN];
4565 char buf[MAXPATHLEN];
4566 char temp_buf[MAXPATHLEN];
4567 struct stat stbuf;
4568 uint_t path_type;
4569 mp_pathlist_t pathlist;
4570 int p_on = 0, p_st = 0;
4571
4572 /* return invalid path if the path_phys is NULL */
4573 if (path_phys == NULL) {
4574 return (L_INVALID_PATH);
4575 }
4576
4577 *nexus_path = NULL;
4578 (void) strcpy(drvr_path, path_phys);
4579
4580 if (strstr(path_phys, SCSI_VHCI)) {
4581 if (g_get_pathlist(drvr_path, &pathlist)) {
4582 return (L_INVALID_PATH);
4583 }
4584 pathcnt = pathlist.path_count;
4585 p_on = p_st = 0;
4586 for (i = 0; i < pathcnt; i++) {
4587 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
4588 if (pathlist.path_info[i].path_state ==
4589 MDI_PATHINFO_STATE_ONLINE) {
4590 p_on = i;
4591 break;
4592 } else if (pathlist.path_info[i].path_state ==
4593 MDI_PATHINFO_STATE_STANDBY) {
4594 p_st = i;
4595 }
4596 }
4597 }
4598 if (pathlist.path_info[p_on].path_state ==
4599 MDI_PATHINFO_STATE_ONLINE) {
4600 /* on_line path */
4601 (void) strcpy(drvr_path,
4602 pathlist.path_info[p_on].path_hba);
4603 } else {
4604 /* standby or path0 */
4605 (void) strcpy(drvr_path,
4606 pathlist.path_info[p_st].path_hba);
4607 }
4608 free(pathlist.path_info);
4609 (void) strcat(drvr_path, FC_CTLR);
4610 } else {
4611 if (strstr(drvr_path, DRV_NAME_SSD) || strstr(drvr_path,
4612 DRV_NAME_ST) || strstr(drvr_path, SES_NAME)) {
4613 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4614 return (L_INVALID_PATH);
4615 }
4616 *char_ptr = '\0'; /* Terminate string */
4617 }
4618
4619 path_type = g_get_path_type(drvr_path);
4620
4621 if (path_type & FC4_SF_XPORT) {
4622
4623 /* sf driver in path so capture the port # */
4624 if ((char_ptr = strstr(drvr_path, "sf@")) == NULL) {
4625 return (L_INVALID_PATH);
4626 }
4627 port = atoi(char_ptr + 3);
4628 if (port > 1) {
4629 return (L_INVLD_PORT_IN_PATH);
4630 }
4631
4632 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4633 return (L_INVALID_PATH);
4634 }
4635 *char_ptr = '\0'; /* Terminate string */
4636 port_flag++;
4637
4638 L_DPRINTF(" g_get_nexus_path:"
4639 " sf driver in path so use port #%d.\n",
4640 port);
4641 } else if (path_type & FC_GEN_XPORT) {
4642 /*
4643 * check to see if it 3rd party vendor FCA.
4644 * if it is return error for this operation since
4645 * we don't know how they creates FCA port related minor node.
4646 *
4647 * As of now there is no supported operation on FCA node so
4648 * this should be okay.
4649 */
4650 if ((path_type & FC_FCA_MASK) == FC_FCA_MASK) {
4651 return (L_INVALID_PATH_TYPE);
4652 }
4653 /*
4654 * For current Sun FCA driver, appending
4655 * port # doesn't work. Just remove transport layer from
4656 * input path.
4657 */
4658 if ((char_ptr = strstr(drvr_path, "/fp@")) == NULL) {
4659 return (L_INVALID_PATH);
4660 }
4661 *char_ptr = '\0'; /* Terminate string */
4662 }
4663
4664 if (stat(drvr_path, &stbuf) != 0) {
4665 return (L_LSTAT_ERROR);
4666 }
4667
4668 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
4669 /*
4670 * Found a directory.
4671 * Now append a port number or devctl to the path.
4672 */
4673 if (port_flag) {
4674 /* append port */
4675 (void) sprintf(buf, ":%d", port);
4676 } else {
4677 /* Try adding port 0 and see if node exists. */
4678 (void) sprintf(temp_buf, "%s:0", drvr_path);
4679 if (stat(temp_buf, &stbuf) != 0) {
4680 /*
4681 * Path we guessed at does not
4682 * exist so it may be a driver
4683 * that ends in :devctl.
4684 */
4685 (void) sprintf(buf, ":devctl");
4686 } else {
4687 /*
4688 * The path that was entered
4689 * did not include a port number
4690 * so the port was set to zero, and
4691 * then checked. The default path
4692 * did exist.
4693 */
4694 ER_DPRINTF("Since a complete path"
4695 " was not supplied "
4696 "a default path is being"
4697 " used:\n %s\n",
4698 temp_buf);
4699 (void) sprintf(buf, ":0");
4700 }
4701 }
4702
4703 (void) strcat(drvr_path, buf);
4704 }
4705
4706 }
4707 *nexus_path = g_alloc_string(drvr_path);
4708 L_DPRINTF(" g_get_nexus_path: Nexus path = %s\n", drvr_path);
4709 return (0);
4710 }
4711
4712
4713 /*
4714 * Get the FC topology for the input device or nexus(HBA) path.
4715 *
4716 * The routine calls g_get_path_type to determine the stack of
4717 * the input path.
4718 *
4719 * If it a socal path
4720 * it returns FC_TOP_PRIVATE_LOOP
4721 * else
4722 * calls fc_get_topology ioctl to
4723 * get the fp topolgy from the driver.
4724 *
4725 * INPUTS:
4726 * path - a string of device path, transport path.
4727 * NOTE: "path" SHOULD NOT BE OPEN BEFORE CALLING
4728 * THIS FUNCTION BECAUSE THIS FUNCTION DOES
4729 * AN "O_EXCL" OPEN.
4730 * port_top - a pointer to the toplogy type.
4731 *
4732 * RETURNS:
4733 * 0 if there is no error.
4734 * error code.
4735 *
4736 * The input path is expected to be something like below:
4737 * 1)
4738 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4739 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@..
4740 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
4741 * /devices/sbus@1f,0/SUNW,socal@1,0
4742 * /devices/sbus@1f,0/SUNW,socal@1,0:1
4743 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4744 * (or "qlc" instead of "socal" and "fp" for "sf")
4745 *
4746 * Which should resolve to a path like this:
4747 * /devices/sbus@1f,0/SUNW,socal@1,0:1
4748 * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4749 *
4750 * 2)
4751 * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
4752 * which should resolve to
4753 * /devices/pci@4,2000/scsi@1:devctl
4754 *
4755 * 3) The nexus(hba or nexus) path will get an error only for qlc
4756 * since the routine need to open fp :devctl node for fcio ioctl.
4757 * /devices/sbus@1f,0/SUNW,socal@1,0
4758 * /devices/sbus@1f,0/SUNW,socal@1,0:1
4759 * /devices/pci@6,2000/pci@2/SUNW,qlc@5 => error
4760 */
4761 int
g_get_fca_port_topology(char * path,uint32_t * port_top,int verbose)4762 g_get_fca_port_topology(char *path, uint32_t *port_top, int verbose)
4763 {
4764 fcio_t fcio;
4765 int fd, i = 0, pathcnt = 1;
4766 char drvr_path[MAXPATHLEN];
4767 char *char_ptr;
4768 struct stat stbuf;
4769 uint_t dev_type;
4770 mp_pathlist_t pathlist;
4771 int p_on = 0, p_st = 0;
4772
4773 /* return invalid path if the path is NULL */
4774 if (path == NULL) {
4775 return (L_INVALID_PATH);
4776 }
4777 /* return invalid arg if the argument is NULL */
4778 if (port_top == NULL) {
4779 return (L_INVALID_ARG);
4780 }
4781
4782 (void) strcpy(drvr_path, path);
4783 if (strstr(path, SCSI_VHCI)) {
4784 if (g_get_pathlist(drvr_path, &pathlist)) {
4785 return (L_INVALID_PATH);
4786 }
4787 pathcnt = pathlist.path_count;
4788 p_on = p_st = 0;
4789 for (i = 0; i < pathcnt; i++) {
4790 if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
4791 if (pathlist.path_info[i].path_state ==
4792 MDI_PATHINFO_STATE_ONLINE) {
4793 p_on = i;
4794 break;
4795 } else if (pathlist.path_info[i].path_state ==
4796 MDI_PATHINFO_STATE_STANDBY) {
4797 p_st = i;
4798 }
4799 }
4800 }
4801 if (pathlist.path_info[p_on].path_state ==
4802 MDI_PATHINFO_STATE_ONLINE) {
4803 /* on_line path */
4804 (void) strcpy(drvr_path,
4805 pathlist.path_info[p_on].path_hba);
4806 } else {
4807 /* standby or path0 */
4808 (void) strcpy(drvr_path,
4809 pathlist.path_info[p_st].path_hba);
4810 }
4811 free(pathlist.path_info);
4812 (void) strcat(drvr_path, FC_CTLR);
4813 } else {
4814 /*
4815 * Get the path to the :devctl driver
4816 *
4817 * This assumes the path looks something like this:
4818 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4819 * or
4820 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
4821 * or
4822 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4823 * or
4824 * a 1 level PCI type driver but still :devctl
4825 * (or "qlc" in the place of "socal" and "fp" for "sf")
4826 *
4827 * The dir below doesn't have corresponding :devctl node.
4828 * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4829 * /devices/sbus@2,0/SUNW,socal@1,0
4830 *
4831 */
4832 if ((strstr(drvr_path, DRV_NAME_SSD) ||
4833 strstr(drvr_path, SES_NAME)) ||
4834 strstr(drvr_path, DRV_NAME_ST)) {
4835 if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4836 return (L_INVALID_PATH);
4837 }
4838 *char_ptr = '\0'; /* Terminate sting */
4839 /* append controller */
4840 (void) strcat(drvr_path, FC_CTLR);
4841 } else {
4842 if (stat(drvr_path, &stbuf) < 0) {
4843 return (L_LSTAT_ERROR);
4844 }
4845 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
4846 /* append controller */
4847 (void) strcat(drvr_path, FC_CTLR);
4848 }
4849 }
4850 }
4851
4852 if ((dev_type = g_get_path_type(drvr_path)) == 0) {
4853 return (L_INVALID_PATH);
4854 }
4855
4856 if ((dev_type & FC4_XPORT_MASK) || (dev_type & FC4_FCA_MASK)) {
4857 *port_top = FC_TOP_PRIVATE_LOOP;
4858 return (0);
4859 }
4860
4861 /* To contiue the path type should be fp :devctl node */
4862 if (!(dev_type & FC_XPORT_MASK)) {
4863 return (L_INVALID_PATH);
4864 }
4865
4866 if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
4867 return (errno);
4868
4869 P_DPRINTF(" g_get_fca_port_topology: Geting topology from:"
4870 " %s\n", drvr_path);
4871
4872 fcio.fcio_cmd = FCIO_GET_TOPOLOGY;
4873 fcio.fcio_olen = sizeof (uint32_t);
4874 fcio.fcio_xfer = FCIO_XFER_READ;
4875 fcio.fcio_obuf = (caddr_t)port_top;
4876 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
4877 I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n");
4878 close(fd);
4879 return (L_FCIO_GET_TOPOLOGY_FAIL);
4880 }
4881 close(fd);
4882 return (0);
4883 }
4884
4885
4886 /*
4887 * This functions enables or disables a FCA port depending on the
4888 * argument, cmd, passed to it. If cmd is PORT_OFFLINE, the function
4889 * tries to disable the port specified by the argument 'phys_path'. If
4890 * cmd is PORT_ONLINE, the function tries to enable the port specified
4891 * by the argument 'phys_path'.
4892 * INPUTS :
4893 * nexus_port_ptr - Pointer to the nexus path of the FCA port to
4894 * operate on
4895 * cmd - PORT_OFFLINE or PORT_ONLINE
4896 * RETURNS :
4897 * 0 on success and non-zero otherwise
4898 */
4899 static int
g_set_port_state(char * nexus_port_ptr,int cmd)4900 g_set_port_state(char *nexus_port_ptr, int cmd)
4901 {
4902 int path_type, fd;
4903
4904 if ((path_type = g_get_path_type(nexus_port_ptr)) == 0) {
4905 return (L_INVALID_PATH);
4906 }
4907
4908 if ((fd = g_object_open(nexus_port_ptr, O_NDELAY|O_RDONLY)) == -1) {
4909 return (L_OPEN_PATH_FAIL);
4910 }
4911
4912 switch (cmd) {
4913 case PORT_OFFLINE:
4914 if (path_type & FC4_SOCAL_FCA) {
4915 /*
4916 * Socal/sf drivers -
4917 * The socal driver currently returns EFAULT
4918 * even if the ioctl has completed successfully.
4919 */
4920 if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
4921 NULL) == -1) {
4922 close(fd);
4923 return (L_PORT_OFFLINE_FAIL);
4924 }
4925 } else {
4926 /*
4927 * QLogic card -
4928 * Can't do much here since the driver currently
4929 * doesn't support this feature. We'll just fail
4930 * for now. Support can be added when the driver
4931 * is enabled with the feature at a later date.
4932 */
4933 close(fd);
4934 return (L_PORT_OFFLINE_UNSUPPORTED);
4935 }
4936 break;
4937 case PORT_ONLINE:
4938 if (path_type & FC4_SOCAL_FCA) {
4939 /*
4940 * Socal/sf drivers
4941 * The socal driver currently returns EFAULT
4942 * even if the ioctl has completed successfully.
4943 */
4944 if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
4945 close(fd);
4946 return (L_PORT_ONLINE_FAIL);
4947 }
4948 } else {
4949 /*
4950 * QLogic card -
4951 * Can't do much here since the driver currently
4952 * doesn't support this feature. We'll just fail
4953 * for now. Support can be added when the driver
4954 * is enabled with the feature at a later date.
4955 */
4956 close(fd);
4957 return (L_PORT_ONLINE_UNSUPPORTED);
4958 }
4959 break;
4960 default:
4961 close(fd);
4962 return (-1);
4963 }
4964 close(fd);
4965 return (0);
4966 }
4967
4968 /*
4969 * The interfaces defined below (g_port_offline() and g_port_online())
4970 * are what will be exposed to applications. We will hide g_set_port_state().
4971 * They have to be functions (as against macros) because making them
4972 * macros will mean exposing g_set_port_state() and we dont want to do that
4973 */
4974
4975 int
g_port_offline(char * path)4976 g_port_offline(char *path)
4977 {
4978 return (g_set_port_state(path, PORT_OFFLINE));
4979 }
4980
4981 int
g_port_online(char * path)4982 g_port_online(char *path)
4983 {
4984 return (g_set_port_state(path, PORT_ONLINE));
4985 }
4986
4987 /*
4988 * This function sets the loopback mode for a port on a HBA
4989 * INPUTS :
4990 * portpath - Pointer to the path of the FCA port on which to
4991 * set the loopback mode
4992 * cmd - EXT_LPBACK
4993 * INT_LPBACK
4994 * NO_LPBACK
4995 * RETURNS :
4996 * 0 on success and non-zero otherwise
4997 */
4998 int
g_loopback_mode(char * portpath,int cmd)4999 g_loopback_mode(char *portpath, int cmd)
5000 {
5001 int path_type, fd;
5002
5003 if ((path_type = g_get_path_type(portpath)) == 0) {
5004 return (L_INVALID_PATH);
5005 }
5006
5007 if ((fd = g_object_open(portpath, O_NDELAY|O_RDONLY|O_EXCL)) == -1) {
5008 return (L_OPEN_PATH_FAIL);
5009 }
5010
5011 /*
5012 * The loopback calls are currently not fully supported
5013 * via fp.
5014 *
5015 * A fp based general solution is required to support Leadville FCAs
5016 * including Qlgc and 3rd party FCA. As of now qlgc provides
5017 * some diag functions like echo through qlc private ioctl
5018 * which is not supproted by luxadm and libraries.
5019 */
5020 switch (cmd) {
5021 case EXT_LPBACK:
5022 if (path_type & FC4_SOCAL_FCA) {
5023 if (ioctl(fd, FCIO_LOOPBACK_MANUAL,
5024 NULL) == -1) {
5025 /* Check for previous mode set */
5026 if (errno != EALREADY) {
5027 close(fd);
5028 return (L_LOOPBACK_FAILED);
5029 }
5030 }
5031 } else {
5032 /*
5033 * Well, it wasn't one of the above cards so..
5034 */
5035 close(fd);
5036 return (L_LOOPBACK_UNSUPPORTED);
5037 }
5038 break;
5039 case NO_LPBACK:
5040 if (path_type & FC4_SOCAL_FCA) {
5041 if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
5042 close(fd);
5043 return (L_LOOPBACK_FAILED);
5044 }
5045 } else {
5046 /*
5047 * Well, it wasn't one of the above cards so..
5048 */
5049 close(fd);
5050 return (L_LOOPBACK_UNSUPPORTED);
5051 }
5052 break;
5053 case INT_LPBACK:
5054 if (path_type & FC4_SOCAL_FCA) {
5055 if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
5056 NULL) == -1) {
5057 /* Check for previous mode set */
5058 if (errno != EALREADY) {
5059 close(fd);
5060 return (L_LOOPBACK_FAILED);
5061 }
5062 }
5063 } else {
5064 /*
5065 * Well, it wasn't one of the above cards so..
5066 */
5067 close(fd);
5068 return (L_LOOPBACK_UNSUPPORTED);
5069 }
5070 break;
5071 default:
5072 close(fd);
5073 return (L_LOOPBACK_UNSUPPORTED);
5074 }
5075 close(fd);
5076 return (0);
5077 }
5078
5079 /*
5080 * g_get_port_state(char *portpath, int port_state)
5081 * Purpose: Get port state for a path
5082 * Input: portpath
5083 * set to path of port
5084 * Output: port_state
5085 * Set to one of the following:
5086 * PORT_CONNECTED
5087 * PORT_NOTCONNECTED
5088 * Returns: 0 on success
5089 * non-zero on failure
5090 */
5091 int
g_get_port_state(char * portpath,int * portstate,int verbose)5092 g_get_port_state(char *portpath, int *portstate, int verbose)
5093 {
5094 int fd, err, num_devices = 0;
5095 struct lilpmap map;
5096 uint_t dev_type;
5097 gfc_dev_t map_root;
5098
5099
5100 (void) memset(&map, 0, sizeof (struct lilpmap));
5101
5102 /* return invalid path if portpath is NULL */
5103 if (portpath == NULL) {
5104 return (L_INVALID_PATH);
5105 }
5106 /* return invalid arg if argument is NULL */
5107 if ((portpath == NULL) || (portstate == NULL)) {
5108 return (L_INVALID_ARG);
5109 }
5110
5111 if ((dev_type = g_get_path_type(portpath)) == 0) {
5112 return (L_INVALID_PATH);
5113 }
5114
5115 /*
5116 * FCIO_GETMAP returns error when there are * no devices attached.
5117 * ENOMEM is returned when no devices are attached.
5118 * g_get_first_dev returns NULL without error when there is no
5119 * devices are attached.
5120 */
5121 if (dev_type & FC_FCA_MASK) {
5122 if ((map_root = g_dev_map_init(portpath, &err,
5123 MAP_XPORT_PROP_ONLY)) == NULL) {
5124 return (err);
5125 }
5126
5127 if (g_get_first_dev(map_root, &err) == NULL) {
5128 /* no device is found if err == 0 */
5129 if (err == L_NO_SUCH_DEV_FOUND) {
5130 *portstate = PORT_NOTCONNECTED;
5131 }
5132 g_dev_map_fini(map_root);
5133 return (0);
5134 } else {
5135 /* Device found okay */
5136 *portstate = PORT_CONNECTED;
5137 g_dev_map_fini(map_root);
5138 }
5139
5140 } else {
5141 /* open controller */
5142 if ((fd = g_object_open(portpath, O_NDELAY | O_RDONLY)) == -1) {
5143 return (errno);
5144 }
5145
5146 /*
5147 * Note: There is only one error returned by this ioctl. ENOMEM.
5148 * Hence the lack of return on error.
5149 */
5150 if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
5151 map.lilp_length = 0;
5152 }
5153 num_devices = map.lilp_length;
5154
5155 /* Non-Leadville stacks report the FCA in the count */
5156 *portstate = (num_devices > 1) ? PORT_CONNECTED :
5157 PORT_NOTCONNECTED;
5158 (void) close(fd);
5159 }
5160 return (0);
5161 }
5162
5163 /*
5164 * g_dev_login(char *port_path, la_wwn_t port_wwn)
5165 * Purpose: port login via g_dev_log_in_out()
5166 * Input: port_path
5167 * fc transport port with fabric/public loop topology
5168 * port_wwn
5169 * port wwn of device node to login
5170 *
5171 * Returns: return code from g_dev_log_in_out()
5172 */
5173 int
g_dev_login(char * port_path,la_wwn_t port_wwn)5174 g_dev_login(char *port_path, la_wwn_t port_wwn)
5175 {
5176 return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGIN));
5177 }
5178
5179
5180 /*
5181 * g_dev_logout(char *port_path, la_wwn_t port_wwn)
5182 * Purpose: port login via g_dev_log_in_out()
5183 * Input: port_path
5184 * fc transport port with fabric/public loop topology
5185 * port_wwn
5186 * port wwn of device node to logout
5187 *
5188 * Returns: return code from g_dev_log_in_out()
5189 */
5190 int
g_dev_logout(char * port_path,la_wwn_t port_wwn)5191 g_dev_logout(char *port_path, la_wwn_t port_wwn)
5192 {
5193 return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGOUT));
5194 }
5195
5196
5197 /*
5198 * g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
5199 * Purpose: port login via FCIO_DEV_LOGOUT and port logout via FCIO_DEV_LOGOUT
5200 * IOCTL requires EXCLUSIVE open.
5201 * Input: port_path
5202 * fc transport port with fabric/public loop topology
5203 * port_wwn
5204 * port wwn of device node to logout
5205 * cmd
5206 * FCIO_DEV_LOGON or FCIO_DEV_LOGOUT
5207 *
5208 * Returns: 0 on success
5209 * non-zero on failure
5210 */
5211 static int
g_dev_log_in_out(char * port_path,la_wwn_t port_wwn,uint16_t cmd)5212 g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
5213 {
5214 int fd, err;
5215 uint32_t hba_port_top;
5216 fcio_t fcio;
5217 int verbose = 0;
5218
5219 if ((err = g_get_fca_port_topology(port_path,
5220 &hba_port_top, verbose)) != 0) {
5221 return (err);
5222 }
5223
5224 if (!((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
5225 (hba_port_top == FC_TOP_FABRIC))) {
5226 return (L_OPNOSUPP_ON_TOPOLOGY);
5227 }
5228
5229 /* open controller */
5230 if ((fd = g_object_open(port_path, O_NDELAY | O_RDONLY | O_EXCL)) == -1)
5231 return (L_OPEN_PATH_FAIL);
5232
5233 /*
5234 * stores port_wwn to la_wwn_t raw_wwn field
5235 * and construct fcio structures for FCIO_DEV_LOGIN.
5236 */
5237 fcio.fcio_cmd = cmd;
5238 fcio.fcio_ilen = sizeof (port_wwn);
5239 fcio.fcio_ibuf = (caddr_t)&port_wwn;
5240 fcio.fcio_xfer = FCIO_XFER_WRITE;
5241 fcio.fcio_olen = fcio.fcio_alen = 0;
5242 fcio.fcio_obuf = fcio.fcio_abuf = NULL;
5243 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
5244 I_DPRINTF((cmd == FCIO_DEV_LOGIN) ?
5245 " FCIO_DEV_LOGIN ioctl failed.\n"
5246 : " FCIO_DEV_LOGOUT ioctl failed.\n");
5247 (void) close(fd);
5248 return ((cmd == FCIO_DEV_LOGIN) ?
5249 L_FCIO_DEV_LOGIN_FAIL
5250 : L_FCIO_DEV_LOGOUT_FAIL);
5251 } else {
5252 (void) close(fd);
5253 return (0);
5254 }
5255 }
5256
5257 /*
5258 * This function will verify if a FC device (represented by input WWN
5259 * is connected on a FCA port by searching the device list from
5260 * g_get_dev_list() for a WWN match.
5261 *
5262 * input:
5263 * fca_path: pointer to the physical path string, path to a fp node.
5264 * possible forms are
5265 * /devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl
5266 * dev_wwn: WWN string
5267 * flag: indicate that the input WWN is node or port
5268 *
5269 * returned values
5270 * 0: if a match is found.
5271 * L_WWN_NOT_FOUND_IN_DEV_LIST: if no match found
5272 * L_UNEXPECTED_FC_TOPOLOGY: existing error code for an error
5273 * from the topology checking of the input fca path.
5274 * L_MALLOC_FAILED: existing error code for allocation eror from the
5275 * g_get_dev_list().
5276 * L_FCIO_GETMAP_IOCTL_FAIL: existing error code for an error from the
5277 * FCIO ioctl called by the g_get_dev_list()
5278 * -1: other failure
5279 *
5280 */
5281 int
g_wwn_in_dev_list(char * fca_path,la_wwn_t dev_wwn,int flag)5282 g_wwn_in_dev_list(char *fca_path, la_wwn_t dev_wwn, int flag)
5283 {
5284 uint_t dev_type;
5285 int i, err;
5286 fc_port_dev_t *dev_list;
5287 fc_port_dev_t *dev_list_save;
5288 int num_devices = 0;
5289
5290 if ((dev_type = g_get_path_type(fca_path)) == 0) {
5291 return (L_INVALID_PATH);
5292 }
5293
5294 if (!(dev_type & FC_XPORT_MASK)) {
5295 return (L_INVALID_PATH_TYPE);
5296 }
5297
5298 if (((err = g_get_dev_list(fca_path, &dev_list, &num_devices))
5299 != 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) {
5300 return (err);
5301 }
5302
5303 dev_list_save = dev_list;
5304
5305 switch (flag) {
5306 case MATCH_NODE_WWN:
5307 for (i = 0; i < num_devices; i++, dev_list++) {
5308 if (memcmp(dev_list->dev_nwwn.raw_wwn,
5309 dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
5310 (void) free(dev_list_save);
5311 return (0);
5312 }
5313 }
5314 (void) free(dev_list_save);
5315 /* consider a new error code for not found. */
5316 return (L_WWN_NOT_FOUND_IN_DEV_LIST);
5317
5318 case MATCH_PORT_WWN:
5319 for (i = 0; i < num_devices; i++, dev_list++) {
5320 if (memcmp(dev_list->dev_pwwn.raw_wwn,
5321 dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
5322 (void) free(dev_list_save);
5323 return (0);
5324 }
5325 }
5326 (void) free(dev_list_save);
5327 /* consider a new error code for not found. */
5328 return (L_WWN_NOT_FOUND_IN_DEV_LIST);
5329 }
5330 (void) free(dev_list_save);
5331 return (-1);
5332 }
5333
5334
5335 /*
5336 * g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
5337 * Purpose: get the state of device port login via FCIO_GET_STATE ioctl.
5338 *
5339 * Input: fca_path
5340 * fc transport port with fabric/public loop topology
5341 * port_wwn
5342 * port wwn of device node to logout
5343 * state
5344 * port login or not
5345 *
5346 * Returns: 0 on success
5347 * non-zero on failure
5348 */
5349 static int
g_get_dev_port_state(char * fca_path,la_wwn_t port_wwn,uint32_t * state)5350 g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
5351 {
5352 int fd;
5353 int dev_type;
5354 fcio_t fcio;
5355 int verbose = 0;
5356
5357 if ((dev_type = g_get_path_type(fca_path)) == 0) {
5358 return (L_INVALID_PATH);
5359 }
5360
5361 if (!(dev_type & FC_XPORT_MASK)) {
5362 return (L_INVALID_PATH_TYPE);
5363 }
5364
5365 /* open controller */
5366 if ((fd = g_object_open(fca_path, O_NDELAY | O_RDONLY)) == -1)
5367 return (L_OPEN_PATH_FAIL);
5368
5369 /*
5370 * stores port_wwn to la_wwn_t raw_wwn field
5371 * and construct fcio structures for FCIO_DEV_LOGIN.
5372 */
5373 fcio.fcio_cmd = FCIO_GET_STATE;
5374 fcio.fcio_ilen = sizeof (port_wwn);
5375 fcio.fcio_ibuf = (caddr_t)&port_wwn;
5376 fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE;
5377 fcio.fcio_olen = sizeof (uint32_t);
5378 fcio.fcio_obuf = (caddr_t)state;
5379 fcio.fcio_alen = 0;
5380 fcio.fcio_abuf = NULL;
5381 if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
5382 I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
5383 (void) close(fd);
5384 return (L_FCIO_GET_STATE_FAIL);
5385 } else {
5386 (void) close(fd);
5387 return (0);
5388 }
5389 }
5390
5391 /*
5392 * Name: lilp_map_cmp
5393 *
5394 * Description: This function is used to compare the physical location
5395 * of to fc devices in a gfc_map_t.dev_addr arrary.
5396 *
5397 * Params:
5398 * First device to compare
5399 * Second device to compare
5400 *
5401 * Return:
5402 * 0 = Devices at equal phyiscal location, How did this happen?
5403 * >0 = First device have a higher physical location than second
5404 * <0 = Second device have a higher physical location than first
5405 */
lilp_map_cmp(const void * dev1,const void * dev2)5406 static int lilp_map_cmp(const void* dev1, const void* dev2) {
5407 int i_dev1 = ((fc_port_dev_t *)dev1)->dev_did.priv_lilp_posit;
5408 int i_dev2 = ((fc_port_dev_t *)dev2)->dev_did.priv_lilp_posit;
5409
5410 if (i_dev1 > i_dev2)
5411 return (1);
5412 if (i_dev1 < i_dev2)
5413 return (-1);
5414 return (0);
5415 }
5416
5417 /*
5418 * Description:
5419 * Retrieves multiple paths to a device based on devid
5420 * Caller must use mplist_free to free mplist structure
5421 * This currently only supports ssd devices.
5422 * The st driver does not register a device id.
5423 *
5424 * Input Values:
5425 *
5426 * devid: ptr to valid ddi_devid_t struct
5427 * root: root handle to device tree snapshot
5428 * drvr_name: driver name to start the node tree search
5429 *
5430 * Return Value:
5431 * 0 on success
5432 * non-zero on failure
5433 */
5434
5435 static int
devid_get_all(ddi_devid_t devid,di_node_t root,char * drvr_name,struct mplist_struct ** mplistp)5436 devid_get_all(ddi_devid_t devid, di_node_t root, char *drvr_name,
5437 struct mplist_struct **mplistp)
5438 {
5439 ddi_devid_t mydevid;
5440 di_node_t node;
5441 char *devfs_path = NULL;
5442 struct mplist_struct *mpl, *mpln;
5443
5444 if (devid == NULL || root == NULL || drvr_name == NULL ||
5445 mplistp == NULL ||
5446 (strncmp(drvr_name, SSD_DRVR_NAME, strlen(SSD_DRVR_NAME))
5447 != 0)) {
5448 return (EINVAL);
5449 }
5450
5451 *mplistp = mpl = mpln = (struct mplist_struct *)NULL;
5452
5453 /* point to first node which matches portdrvr */
5454 node = di_drv_first_node(drvr_name, root);
5455 if (node == DI_NODE_NIL) {
5456 return (L_NO_DRIVER_NODES_FOUND);
5457 }
5458
5459 while (node != DI_NODE_NIL) {
5460 if ((mydevid = di_devid(node)) != NULL) {
5461 if (((devid_compare(mydevid, devid)) == 0)) {
5462 /* Load multipath list */
5463 if ((mpl = (struct mplist_struct *)
5464 calloc(1, sizeof (struct mplist_struct)))
5465 == NULL) {
5466 mplist_free(*mplistp);
5467 return (L_MALLOC_FAILED);
5468 }
5469 if ((devfs_path = my_devfs_path(node)) ==
5470 NULL) {
5471 node = di_drv_next_node(node);
5472 S_FREE(mpl);
5473 continue;
5474 }
5475 mpl->devpath = (char *)calloc(1,
5476 strlen(devfs_path) +
5477 strlen(SSD_MINOR_NAME) + 1);
5478 if (mpl->devpath == NULL) {
5479 S_FREE(mpl);
5480 mplist_free(*mplistp);
5481 my_devfs_path_free(devfs_path);
5482 return (L_MALLOC_FAILED);
5483 }
5484 sprintf(mpl->devpath, "%s%s", devfs_path,
5485 SSD_MINOR_NAME);
5486 if (*mplistp == NULL) {
5487 *mplistp = mpln = mpl;
5488 } else {
5489 mpln->next = mpl;
5490 mpln = mpl;
5491 }
5492 my_devfs_path_free(devfs_path);
5493 }
5494 }
5495 node = di_drv_next_node(node);
5496 }
5497 return (0);
5498 }
5499
5500 /*
5501 * Frees a previously allocated mplist_struct
5502 */
5503 static void
mplist_free(struct mplist_struct * mplistp)5504 mplist_free(struct mplist_struct *mplistp)
5505 {
5506 struct mplist_struct *mplistn;
5507
5508 while (mplistp != NULL) {
5509 mplistn = mplistp->next;
5510 if (mplistp->devpath != NULL) {
5511 free(mplistp->devpath);
5512 mplistp->devpath = NULL;
5513 }
5514 free(mplistp);
5515 mplistp = mplistn;
5516 }
5517 }
5518
5519 /*
5520 * Description
5521 * Retrieves all device nodes based on drvr_name
5522 * Currently supports SSD_DRVR_NAME, ST_DRVR_NAME
5523 * There will be a device node in the libdevinfo
5524 * snapshot only if there is at least one node bound.
5525 *
5526 * Input values:
5527 * root valid snapshot handle from di_init(3DEVINFO)
5528 * drvr_name name of driver to start node search
5529 * wwn_list_ptr ptr to ptr to WWN_list struct
5530 *
5531 *
5532 */
5533 static int
devices_get_all(di_node_t root,char * drvr_name,char * minor_name,struct wwn_list_struct ** wwn_list_ptr)5534 devices_get_all(di_node_t root, char *drvr_name, char *minor_name,
5535 struct wwn_list_struct **wwn_list_ptr)
5536 {
5537 di_node_t node;
5538 char *devfs_path;
5539 char devicepath[MAXPATHLEN];
5540 uchar_t *nwwn = NULL, *pwwn = NULL;
5541 uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
5542 WWN_list *wwn_list, *l1, *l2;
5543 int scsi_vhci = 0;
5544 int err, devtype;
5545
5546 if (root == DI_NODE_NIL || drvr_name == NULL ||
5547 wwn_list_ptr == NULL) {
5548 return (EINVAL);
5549 }
5550
5551 wwn_list = *wwn_list_ptr = NULL;
5552
5553 memset(port_wwn, 0, sizeof (port_wwn));
5554 memset(node_wwn, 0, sizeof (node_wwn));
5555
5556 if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
5557 devtype = DTYPE_DIRECT;
5558 } else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
5559 devtype = DTYPE_SEQUENTIAL;
5560 } else {
5561 /*
5562 * An unsupported driver name was passed in
5563 */
5564 return (L_DRIVER_NOTSUPP);
5565 }
5566
5567 /* point to first node which matches portdrvr */
5568 node = di_drv_first_node(drvr_name, root);
5569 if (node == DI_NODE_NIL) {
5570 return (L_NO_DEVICES_FOUND);
5571 }
5572
5573 while (node != DI_NODE_NIL) {
5574
5575 if ((devfs_path = my_devfs_path(node)) != NULL) {
5576
5577 /*
5578 * Check for offline state
5579 */
5580 if ((di_state(node) &
5581 DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) {
5582 my_devfs_path_free(devfs_path);
5583 node = di_drv_next_node(node);
5584 continue;
5585 }
5586
5587 /*
5588 * Only support st, ssd nodes
5589 */
5590 if (!strstr(devfs_path, SLSH_DRV_NAME_SSD) &&
5591 !strstr(devfs_path, SLSH_DRV_NAME_ST)) {
5592 my_devfs_path_free(devfs_path);
5593 node = di_drv_next_node(node);
5594 continue;
5595 }
5596
5597 devicepath[0] = '\0';
5598
5599 /*
5600 * form device path
5601 */
5602 sprintf(devicepath, "%s%s", devfs_path, minor_name);
5603
5604 if ((strstr(devicepath, SCSI_VHCI) == NULL)) {
5605 if ((err = get_wwn_data(node, &nwwn, &pwwn)) !=
5606 0) {
5607 my_devfs_path_free(devfs_path);
5608 return (err);
5609 } else {
5610 memcpy(node_wwn, nwwn,
5611 sizeof (node_wwn));
5612 memcpy(port_wwn, pwwn,
5613 sizeof (port_wwn));
5614 }
5615 } else {
5616 /*
5617 * Clear values for SCSI VHCI devices.
5618 * node wwn, port wwn are irrevelant at
5619 * the SCSI VHCI level
5620 */
5621 scsi_vhci++;
5622 memset(port_wwn, 0, sizeof (port_wwn));
5623 memset(node_wwn, 0, sizeof (node_wwn));
5624 }
5625
5626 /* Got wwns, load data in list */
5627 if ((l2 = (struct wwn_list_struct *)
5628 calloc(1, sizeof (struct wwn_list_struct))) ==
5629 NULL) {
5630 my_devfs_path_free(devfs_path);
5631 return (L_MALLOC_FAILED);
5632 }
5633 if ((l2->physical_path = (char *)
5634 calloc(1, strlen(devicepath) +1)) == NULL) {
5635 my_devfs_path_free(devfs_path);
5636 return (L_MALLOC_FAILED);
5637 }
5638
5639 memcpy(l2->w_node_wwn, node_wwn, WWN_SIZE);
5640
5641 if (scsi_vhci) {
5642 strcpy(l2->node_wwn_s, MSGSTR(12000, "N/A"));
5643 } else {
5644 copy_wwn_data_to_str(l2->node_wwn_s, node_wwn);
5645 copy_wwn_data_to_str(l2->port_wwn_s, port_wwn);
5646 }
5647
5648 strcpy(l2->physical_path, devicepath);
5649
5650 l2->device_type = devtype;
5651 if (wwn_list == NULL) {
5652 l1 = wwn_list = l2;
5653 } else {
5654 l2->wwn_prev = l1;
5655 l1 = l1->wwn_next = l2;
5656 }
5657 my_devfs_path_free(devfs_path);
5658 scsi_vhci = 0;
5659 }
5660 node = di_drv_next_node(node);
5661 }
5662
5663 *wwn_list_ptr = wwn_list; /* pass back ptr to list */
5664
5665 if (*wwn_list_ptr == NULL) {
5666 return (L_NO_DEVICES_FOUND);
5667 } else {
5668 /*
5669 * Now load the /dev/ paths
5670 */
5671 if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
5672 if ((err = get_dev_path(wwn_list_ptr, DEV_RDIR,
5673 DIR_MATCH_SSD)) != 0) {
5674 g_free_wwn_list(wwn_list_ptr);
5675 return (err);
5676 }
5677 } else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
5678 if ((err = get_dev_path(wwn_list_ptr, DEV_TAPE_DIR,
5679 DIR_MATCH_ST)) != 0) {
5680 g_free_wwn_list(wwn_list_ptr);
5681 return (err);
5682 }
5683 }
5684 return (0);
5685 }
5686 }
5687
5688
5689 /*
5690 * Access the properties for the node to get the node-wwn, port-wwn property
5691 * On error, contents of nwwn, pwwn are unspecified.
5692 * On successful return nwwn and pwwn are WWN_SIZE bytes.
5693 */
5694 static int
get_wwn_data(di_node_t node,uchar_t ** nwwn,uchar_t ** pwwn)5695 get_wwn_data(di_node_t node, uchar_t **nwwn, uchar_t **pwwn)
5696 {
5697 if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
5698 nwwn) != WWN_SIZE) {
5699 /* If we didn't get back the right count, return error */
5700 return (L_NO_WWN_PROP_FOUND);
5701 }
5702 if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP,
5703 pwwn) != WWN_SIZE) {
5704 /* If we didn't get back the right count, return error */
5705 return (L_NO_WWN_PROP_FOUND);
5706 }
5707 return (0);
5708 }
5709
5710 /*
5711 * Description
5712 * retrieves the /dev logical path for a WWN_list of devices.
5713 * Input values
5714 * wwn_list_ptr ptr to list returned by devices_get_all
5715 * dir_name /dev/ directory to search
5716 *
5717 */
5718 static int
get_dev_path(struct wwn_list_struct ** wwn_list_ptr,char * dir_name,char * pattern_match)5719 get_dev_path(struct wwn_list_struct **wwn_list_ptr, char *dir_name,
5720 char *pattern_match)
5721 {
5722 DIR *dirp;
5723 struct dirent *entp;
5724 char namebuf[MAXPATHLEN];
5725 char *result = NULL;
5726 WWN_list *wwn_list, *wwn_list_save;
5727 char *env;
5728 hrtime_t start_time, end_time;
5729
5730 if (wwn_list_ptr == NULL || *wwn_list_ptr == NULL ||
5731 dir_name == NULL || pattern_match == NULL) {
5732 return (EINVAL);
5733 }
5734
5735 if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
5736 start_time = gethrtime();
5737 }
5738
5739 wwn_list = *wwn_list_ptr;
5740
5741 if ((dirp = opendir(dir_name)) == NULL) {
5742 P_DPRINTF(" get_dev_path: No devices found\n");
5743 return (L_NO_DEVICES_FOUND);
5744 }
5745
5746 while ((entp = readdir(dirp)) != NULL) {
5747 /*
5748 * Ignore current directory and parent directory
5749 * entries.
5750 */
5751 if ((strcmp(entp->d_name, ".") == 0) ||
5752 (strcmp(entp->d_name, "..") == 0) ||
5753 (fnmatch(pattern_match, entp->d_name, 0) != 0))
5754 continue;
5755
5756 memset(namebuf, 0, sizeof (namebuf));
5757 sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
5758
5759 if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
5760 ER_DPRINTF(" Warning: Get physical name from"
5761 " link failed. Link=%s\n", namebuf);
5762 continue;
5763 }
5764 for (wwn_list = *wwn_list_ptr; wwn_list != NULL;
5765 wwn_list = wwn_list->wwn_next) {
5766 if (strcmp(wwn_list->physical_path, result) == 0) {
5767 /*
5768 * Add information to the list.
5769 */
5770 if ((wwn_list->logical_path = (char *)
5771 calloc(1, strlen(namebuf) + 1)) == NULL) {
5772 free(result);
5773 return (L_MALLOC_FAILED);
5774 }
5775 strcpy(wwn_list->logical_path, namebuf);
5776 break;
5777 }
5778 }
5779 free(result);
5780 }
5781 closedir(dirp);
5782
5783 /*
5784 * Did we load all of the paths?
5785 * Note: if there is a missing entry in /dev then
5786 * the user probably did a cleanup of /dev.
5787 * Whatever the case, remove the entry as it
5788 * is invalid.
5789 */
5790 wwn_list = *wwn_list_ptr;
5791 while (wwn_list != NULL) {
5792 if (wwn_list->logical_path == NULL) {
5793 free(wwn_list->physical_path);
5794 wwn_list_save = wwn_list;
5795 if (wwn_list->wwn_prev != NULL) {
5796 wwn_list->wwn_prev->wwn_next =
5797 wwn_list->wwn_next;
5798 } else {
5799 /*
5800 * No previous entries
5801 */
5802 *wwn_list_ptr = wwn_list->wwn_next;
5803 }
5804 if (wwn_list->wwn_next != NULL) {
5805 wwn_list->wwn_next->wwn_prev =
5806 wwn_list->wwn_prev;
5807 }
5808 wwn_list = wwn_list->wwn_next;
5809 free(wwn_list_save);
5810 } else {
5811 wwn_list = wwn_list->wwn_next;
5812 }
5813 }
5814
5815 if (env != NULL) {
5816 end_time = gethrtime();
5817 fprintf(stdout,
5818 " get_dev_path %s: "
5819 "\t\tTime = %lld millisec\n",
5820 dir_name, (end_time - start_time)/1000000);
5821 }
5822
5823 if (*wwn_list_ptr == NULL) {
5824 return (L_NO_DEVICES_FOUND);
5825 } else {
5826 return (0);
5827 }
5828 }
5829
5830 /*
5831 * This functions calls di_devfs_path and gets the path associated with a
5832 * given devinfo node. If the path returned does not have a '@' in it, it
5833 * checks if the driver is detached and creates a path after looking at the
5834 * driver properties.
5835 *
5836 * di_devfs_path_free is called internally.
5837 *
5838 * The argument 'path' points to the final value upon return.
5839 * Caller must use my_devfs_path_free on returned char *
5840 * Note: Only support FC/SCSI_VHCI devices,
5841 * for FC check for initiator-interconnect-type prop
5842 *
5843 */
5844 static char *
my_devfs_path(di_node_t node)5845 my_devfs_path(di_node_t node)
5846 {
5847 uchar_t *pwwn = NULL;
5848 char *interconnect = NULL;
5849 char pwwns[WWN_SIZE*2+1];
5850 char *mypath;
5851 int scsi_vhci = 0;
5852 int rval;
5853 char *tptr = NULL, *lun_guid = NULL;
5854 int *lunnump = NULL;
5855 di_node_t parentnode;
5856
5857 /* sanity check */
5858 if (node == DI_NODE_NIL) {
5859 return (NULL);
5860 }
5861
5862 /* Now go get the path for this node */
5863 if ((tptr = di_devfs_path(node)) == NULL) {
5864 return (NULL);
5865 }
5866
5867 parentnode = di_parent_node(node);
5868
5869 if ((mypath = (char *)calloc(1, MAXPATHLEN + 1)) == NULL) {
5870 di_devfs_path_free(tptr);
5871 return (NULL);
5872 }
5873
5874 /* Prepend "/devices" to libdevinfo-returned paths */
5875 sprintf(mypath, "%s%s", DEVICES_DIR, tptr);
5876
5877 di_devfs_path_free(tptr);
5878
5879 /*
5880 * Is this a FC device?
5881 * Check initiator-interconnect-type property
5882 */
5883 if (strstr(mypath, SCSI_VHCI) == NULL) {
5884 rval = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
5885 "initiator-interconnect-type", &interconnect);
5886 /* Check for INTERCONNECT_FABRIC_STR & INTERCONNECT_FIBRE_STR */
5887 if ((rval <= 0) ||
5888 ((strcmp(interconnect, "FABRIC") != 0) &&
5889 (strcmp(interconnect, "FIBRE") != 0))) {
5890 /* Not a FC device. Free path and return */
5891 free(mypath);
5892 return (NULL);
5893 }
5894 } else {
5895 scsi_vhci++;
5896 }
5897
5898 if ((tptr = strrchr(mypath, '/')) == NULL) {
5899 free(mypath);
5900 return (NULL);
5901 }
5902
5903 if (strchr(tptr, '@') != NULL) {
5904 return (mypath);
5905 }
5906
5907 /*
5908 * No '@' in path. This can happen when driver is detached.
5909 * We'll check if the state is detached and if it is, we'll construct
5910 * the path by looking at the properties.
5911 */
5912
5913 if ((di_state(node) & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
5914 /*
5915 * Driver is not detached and no '@' in path.
5916 * Can't handle it.
5917 */
5918 free(mypath);
5919 return (NULL);
5920 }
5921
5922 if (!scsi_vhci) {
5923 copy_wwn_data_to_str(pwwns, pwwn);
5924 di_prop_lookup_ints(DDI_DEV_T_ANY, node, LUN_PROP, &lunnump);
5925 sprintf(&mypath[strlen(mypath)], "@w%s,%x", pwwn, *lunnump);
5926 } else {
5927 di_prop_lookup_strings(DDI_DEV_T_ANY, node,
5928 LUN_GUID_PROP, &lun_guid);
5929 sprintf(&mypath[strlen(mypath)], "@g%s", lun_guid);
5930 }
5931 return (mypath);
5932 }
5933
5934 static void
my_devfs_path_free(char * path)5935 my_devfs_path_free(char *path)
5936 {
5937 if (path != NULL) {
5938 free(path);
5939 }
5940 }
5941
5942 /*
5943 * from_ptr: ptr to uchar_t array of size WWN_SIZE
5944 * to_ptr: char ptr to string of size WWN_SIZE*2+1
5945 */
5946 static void
copy_wwn_data_to_str(char * to_ptr,const uchar_t * from_ptr)5947 copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
5948 {
5949 if ((to_ptr == NULL) || (from_ptr == NULL))
5950 return;
5951
5952 sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
5953 from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
5954 from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
5955 }
5956
5957 /*
5958 * Open the requested directory and get one valid open.
5959 * If a device is busy, return.
5960 * Only need to open one device since
5961 * that implies there will be a node returned from
5962 * di_drv_first_node()
5963 * dir_name: logical device name directory
5964 * (DEV_TAPE_DIR, DEV_RDIR)
5965 * pattern_match: used by fnmatch on directory entry
5966 * (DIR_MATCH_SSD, DIR_MATCH_ST)
5967 * drvr_path: path type to verify ("/ssd@", "/st@")
5968 * (SLSH_DRV_NAME_ST, SLSH_DRV_NAME_SSD)
5969 *
5970 * Returns: None
5971 */
5972 static void
init_drv(char * dir_name,char * pattern_match,char * drvr_path)5973 init_drv(char *dir_name, char *pattern_match, char *drvr_path)
5974 {
5975 DIR *dirp;
5976 struct dirent *entp;
5977 char namebuf[MAXPATHLEN];
5978 char *result = NULL;
5979 int fd;
5980
5981 if ((dirp = opendir(dir_name)) == NULL) {
5982 return;
5983 }
5984
5985 while ((entp = readdir(dirp)) != NULL) {
5986 /*
5987 * Ignore current directory and parent directory
5988 * entries.
5989 */
5990 if ((strcmp(entp->d_name, ".") == 0) ||
5991 (strcmp(entp->d_name, "..") == 0) ||
5992 (fnmatch(pattern_match, entp->d_name, 0) != 0)) {
5993 continue;
5994 }
5995
5996 memset(namebuf, 0, sizeof (namebuf));
5997 sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
5998
5999 if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
6000 ER_DPRINTF(" Warning: Get physical name from"
6001 " link failed. Link=%s\n", namebuf);
6002 continue;
6003 }
6004
6005 if (strstr(result, drvr_path) == NULL) {
6006 free(result);
6007 result = NULL;
6008 continue;
6009 }
6010
6011 if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) != -1) {
6012 close(fd);
6013 break;
6014 } else if (errno != EBUSY) {
6015 free(result);
6016 result = NULL;
6017 continue;
6018 } else {
6019 break;
6020 }
6021 }
6022 free(result);
6023 closedir(dirp);
6024 }
6025