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