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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 #include "cfga_fp.h"
28 #include <sys/fibre-channel/impl/fc_error.h>
29
30 /* Structure for walking the tree */
31 typedef struct {
32 apid_t *apidp;
33 char *xport_logp;
34 ldata_list_t *listp;
35 fpcfga_cmd_t cmd;
36 cfga_stat_t chld_config;
37 cfga_type_t xport_type;
38 cfga_stat_t xport_rstate;
39 fpcfga_ret_t ret;
40 int l_errno;
41 } fpcfga_list_t;
42
43 typedef struct {
44 uint_t itype;
45 const char *ntype;
46 const char *name;
47 } fpcfga_devtype_t;
48
49 #define ERR_INQ_DTYPE 0xff
50
51 /* The TYPE field is parseable and should not contain spaces */
52 #define FP_FC_PORT_TYPE "fc"
53 #define FP_FC_PORT_ERROR "fc-error"
54 #define FP_FC_FABRIC_PORT_TYPE "fc-fabric"
55 #define FP_FC_PUBLIC_PORT_TYPE "fc-public"
56 #define FP_FC_PRIVATE_PORT_TYPE "fc-private"
57 #define FP_FC_PT_TO_PT_PORT_TYPE "fc-pt_to_pt"
58
59 /* Indicates no plag passing */
60 #define NO_FLAG 0
61
62 /* defines for retry algorithm */
63 #define OPEN_RETRY_COUNT 5
64 #define OPEN_RETRY_INTERVAL 10000 /* 1/100 of a sec. */
65 #define IOCTL_RETRY_COUNT 5
66 #define IOCTL_RETRY_INTERVAL 5000000 /* 5 sec */
67
68 /* define for fcp scsi passthru wait */
69 #define FCP_SCSI_CMD_TIMEOUT 10
70
71 /* define for fcp pseudo node */
72 #define FCP_PATH "/devices/pseudo/fcp@0:fcp"
73
74 /* Function prototypes */
75 static fpcfga_ret_t postprocess_list_data(const ldata_list_t *listp,
76 fpcfga_cmd_t cmd, cfga_stat_t chld_config, int *np, uint_t flags);
77 static int stat_fc_dev(di_node_t node, void *arg);
78 static int stat_FCP_dev(di_node_t node, void *arg);
79 static fpcfga_ret_t do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat,
80 HBA_PORTATTRIBUTES portAttrs);
81 static int get_xport_state(di_node_t node, void *arg);
82
83 static fpcfga_ret_t do_stat_fc_dev(const di_node_t node, const char *nodepath,
84 fpcfga_list_t *lap, int limited_stat);
85 static fpcfga_ret_t do_stat_FCP_dev(const di_node_t node, const char *nodepath,
86 fpcfga_list_t *lap, int limited_stat);
87 static cfga_stat_t xport_devinfo_to_recep_state(uint_t xport_di_state);
88 static cfga_stat_t dev_devinfo_to_occupant_state(uint_t dev_di_state);
89 static void get_hw_info(di_node_t node, cfga_list_data_t *clp);
90 static const char *get_device_type(di_node_t);
91 static fpcfga_ret_t init_ldata_for_accessible_dev(const char *dyncomp,
92 uchar_t inq_type, fpcfga_list_t *lap);
93 static fpcfga_ret_t init_ldata_for_accessible_FCP_dev(const char *port_wwn,
94 int num_luns, struct report_lun_resp *resp_buf,
95 fpcfga_list_t *larg, int *l_errnop);
96 static fpcfga_ret_t is_dyn_ap_on_ldata_list(const char *port_wwn,
97 const ldata_list_t *listp, ldata_list_t **matchldpp, int *l_errno);
98 static fpcfga_ret_t is_FCP_dev_ap_on_ldata_list(const char *port_wwn,
99 const int lun_num, ldata_list_t *ldatap, ldata_list_t **matchldpp);
100
101 static fpcfga_ret_t init_ldata_for_mpath_dev(di_path_t path, char *port_wwn,
102 int *l_errnop, fpcfga_list_t *lap);
103 static fpcfga_ret_t insert_ldata_to_ldatalist(const char *port_wwn,
104 int *lun_nump, ldata_list_t *listp, ldata_list_t **ldatapp);
105 static fpcfga_ret_t insert_fc_dev_ldata(const char *port_wwn,
106 ldata_list_t *listp, ldata_list_t **ldatapp);
107 static fpcfga_ret_t insert_FCP_dev_ldata(const char *port_wwn, int lun_num,
108 ldata_list_t *listp, ldata_list_t **ldatapp);
109 static int stat_path_info_fc_dev(di_node_t root, fpcfga_list_t *lap,
110 int *l_errnop);
111 static int stat_path_info_FCP_dev(di_node_t root, fpcfga_list_t *lap,
112 int *l_errnop);
113 static fpcfga_ret_t get_accessible_FCP_dev_ldata(const char *dyncomp,
114 fpcfga_list_t *lap, int *l_errnop);
115 static fpcfga_ret_t get_standard_inq_data(const char *xport_phys,
116 const char *dyncomp, uchar_t *lun_num, struct scsi_inquiry **inq_buf,
117 int *l_errnop);
118 static void init_fcp_scsi_cmd(struct fcp_scsi_cmd *fscsi, uchar_t *lun_num,
119 la_wwn_t *pwwn, void *scmdbuf, size_t scmdbuf_len, void *respbuf,
120 size_t respbuf_len, void *sensebuf, size_t sensebuf_len);
121 static fpcfga_ret_t issue_fcp_scsi_cmd(const char *xport_phys,
122 struct fcp_scsi_cmd *fscsi, int *l_errnop);
123 static uchar_t get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle,
124 HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs);
125
126 static fpcfga_devtype_t device_list[] = {
127 { DTYPE_DIRECT, DDI_NT_BLOCK_CHAN, "disk"},
128 { DTYPE_DIRECT, DDI_NT_BLOCK, "disk"},
129 { DTYPE_DIRECT, DDI_NT_BLOCK_WWN, "disk"},
130 { DTYPE_DIRECT, DDI_NT_BLOCK_FABRIC, "disk"},
131 { DTYPE_SEQUENTIAL, DDI_NT_TAPE, "tape"},
132 { DTYPE_PRINTER, NULL, "printer"},
133 { DTYPE_PROCESSOR, NULL, "processor"},
134 { DTYPE_WORM, NULL, "WORM"},
135 { DTYPE_RODIRECT, DDI_NT_CD_CHAN, "CD-ROM"},
136 { DTYPE_RODIRECT, DDI_NT_CD, "CD-ROM"},
137 { DTYPE_SCANNER, NULL, "scanner"},
138 { DTYPE_OPTICAL, NULL, "optical"},
139 { DTYPE_CHANGER, NULL, "med-changer"},
140 { DTYPE_COMM, NULL, "comm-device"},
141 { DTYPE_ARRAY_CTRL, NULL, "array-ctrl"},
142 { DTYPE_ESI, NULL, "ESI"},
143 /*
144 * This has to be the LAST entry for DTYPE_UNKNOWN_INDEX.
145 * Add entries before this.
146 */
147 { DTYPE_UNKNOWN, NULL, "unknown"}
148 };
149
150 #define N_DEVICE_TYPES (sizeof (device_list) / sizeof (device_list[0]))
151
152 #define DTYPE_UNKNOWN_INDEX (N_DEVICE_TYPES - 1)
153
154 /*
155 * Main routine for list operation.
156 * It calls various routines to consturct ldata list and
157 * postprocess the list data.
158 *
159 * Overall algorithm:
160 * Get the device list on input hba port and construct ldata list for
161 * accesible devices.
162 * Stat hba port and devices through walking the device tree.
163 * Verify the validity of the list data.
164 */
165 fpcfga_ret_t
do_list(apid_t * apidp,fpcfga_cmd_t cmd,ldata_list_t ** llpp,int * nelemp,char ** errstring)166 do_list(
167 apid_t *apidp,
168 fpcfga_cmd_t cmd,
169 ldata_list_t **llpp,
170 int *nelemp,
171 char **errstring)
172 {
173 int n = -1, l_errno = 0, limited_stat;
174 walkarg_t walkarg;
175 fpcfga_list_t larg = {NULL};
176 fpcfga_ret_t ret;
177 la_wwn_t pwwn;
178 char *dyncomp = NULL;
179 HBA_HANDLE handle;
180 HBA_PORTATTRIBUTES portAttrs;
181 HBA_PORTATTRIBUTES discPortAttrs;
182 HBA_STATUS status;
183 int portIndex, discIndex;
184 int retry;
185 uchar_t inq_dtype;
186
187 if (*llpp != NULL || *nelemp != 0) {
188 return (FPCFGA_ERR);
189 }
190
191 /* Create the hba logid (also base component of logical ap_id) */
192 ret = make_xport_logid(apidp->xport_phys, &larg.xport_logp, &l_errno);
193 if (ret != FPCFGA_OK) {
194 cfga_err(errstring, l_errno, ERR_LIST, 0);
195 return (FPCFGA_ERR);
196 }
197
198 assert(larg.xport_logp != NULL);
199
200 larg.cmd = cmd;
201 larg.apidp = apidp;
202 larg.xport_rstate = CFGA_STAT_NONE;
203
204 if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle,
205 &portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
206 S_FREE(larg.xport_logp);
207 return (ret);
208 }
209
210 /*
211 * If stating a specific device, we will do limited stat on fca port.
212 * otherwise full stat on fca part is required.
213 * If stating a specific device we don't know if it exists or is
214 * configured yet. larg.ret is set to apid noexist for do_stat_dev.
215 * otherwise larg.ret is set to ok initially.
216 */
217 if (larg.cmd == FPCFGA_STAT_FC_DEV) {
218 limited_stat = 1; /* for do_stat_fca_xport */
219 larg.ret = FPCFGA_APID_NOEXIST; /* for stat_fc_dev */
220 } else {
221 limited_stat = 0; /* for do_stat_fca_xport */
222 larg.ret = FPCFGA_OK; /* for stat_fc_dev */
223 }
224
225 /* For all list commands, the fca port needs to be stat'ed */
226 if ((ret = do_stat_fca_xport(&larg, limited_stat,
227 portAttrs)) != FPCFGA_OK) {
228 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
229 list_free(&larg.listp);
230 S_FREE(larg.xport_logp);
231 HBA_CloseAdapter(handle);
232 HBA_FreeLibrary();
233 return (ret);
234 }
235
236 #ifdef DEBUG
237 if (limited_stat) {
238 assert(larg.listp == NULL);
239 } else {
240 assert(larg.listp != NULL);
241 }
242 #endif
243 /*
244 * If stat'ing a FCA port or ALL, we have the bus stat data at
245 * this point.
246 * Assume that the bus has no configured children.
247 */
248 larg.chld_config = CFGA_STAT_UNCONFIGURED;
249
250 switch (larg.cmd) {
251 case FPCFGA_STAT_FC_DEV:
252 /* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */
253 if (cvt_dyncomp_to_lawwn(apidp->dyncomp, &pwwn) != 0) {
254 cfga_err(errstring, 0, ERR_LIST, 0);
255 list_free(&larg.listp);
256 S_FREE(larg.xport_logp);
257 HBA_CloseAdapter(handle);
258 HBA_FreeLibrary();
259 return (FPCFGA_LIB_ERR);
260 }
261 /*
262 * if the dyncomp exists on disco ports construct list_data
263 * otherwise return FPCFGA_APID_NOEXIST.
264 */
265 retry = 0;
266 do {
267 status = getPortAttrsByWWN(handle,
268 *((HBA_WWN *)(&pwwn)), &discPortAttrs);
269 if (status == HBA_STATUS_ERROR_STALE_DATA) {
270 /* get Port Attributes again after refresh. */
271 HBA_RefreshInformation(handle);
272 } else {
273 break; /* either okay or some other error */
274 }
275 } while (retry++ < HBA_MAX_RETRIES);
276
277 if (status == HBA_STATUS_OK) {
278 /*
279 * if dyncomp found in disco ports
280 * construct ldata_list and return.
281 * otherwise continue to stat on dev tree with
282 * larg.ret set to access_ok which informs stat_fc_dev
283 * the existence of device on disco ports.
284 *
285 * if path is null that guatantees the node is not
286 * configured. if node is detached the path
287 * is incomplete and not usable for further
288 * operations like uscsi_inq so take care of it here.
289 */
290 inq_dtype = get_inq_dtype(apidp->xport_phys,
291 apidp->dyncomp, handle, &portAttrs, &discPortAttrs);
292
293 if (init_ldata_for_accessible_dev(apidp->dyncomp,
294 inq_dtype, &larg) != FPCFGA_OK) {
295 cfga_err(errstring, larg.l_errno,
296 ERR_LIST, 0);
297 list_free(&larg.listp);
298 S_FREE(larg.xport_logp);
299 HBA_CloseAdapter(handle);
300 HBA_FreeLibrary();
301 return (FPCFGA_LIB_ERR);
302 }
303 if (apidp->lunlist == NULL) {
304 n = 0;
305 if (postprocess_list_data(
306 larg.listp, cmd,
307 larg.chld_config, &n, NO_FLAG) !=
308 FPCFGA_OK) {
309 cfga_err(errstring,
310 larg.l_errno, ERR_LIST, 0);
311 list_free(&larg.listp);
312 S_FREE(larg.xport_logp);
313 HBA_CloseAdapter(handle);
314 HBA_FreeLibrary();
315 return (FPCFGA_LIB_ERR);
316 }
317 *nelemp = n;
318 *llpp = larg.listp;
319 S_FREE(larg.xport_logp);
320 HBA_CloseAdapter(handle);
321 HBA_FreeLibrary();
322 return (FPCFGA_OK);
323 }
324 larg.ret = FPCFGA_ACCESS_OK;
325 } else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
326 /*
327 * path indicates if the node exists in dev tree.
328 * if not found in dev tree return apid no exist.
329 * otherwise continue to stat with larg.ret set to
330 * apid_noexist.
331 */
332 if (apidp->lunlist == NULL) {
333 list_free(&larg.listp);
334 S_FREE(larg.xport_logp);
335 HBA_CloseAdapter(handle);
336 HBA_FreeLibrary();
337 return (FPCFGA_APID_NOEXIST);
338 }
339 } else { /* any error */
340 /*
341 * path indicates if the node exists in dev tree.
342 * if not found in dev tree return lib error.
343 * otherwise continue to stat with larg.ret set to
344 * apid_noexist.
345 */
346 if (apidp->lunlist == NULL) {
347 cfga_err(errstring, 0, ERR_FC_GET_DEVLIST, 0);
348 list_free(&larg.listp);
349 S_FREE(larg.xport_logp);
350 HBA_CloseAdapter(handle);
351 HBA_FreeLibrary();
352 return (FPCFGA_LIB_ERR);
353 }
354 }
355 break;
356 case FPCFGA_STAT_ALL:
357 /*
358 * for each dev in disco ports, create a ldata_list element.
359 * if if no disco ports found, continue to stat on devinfo tree
360 * to see if any node exist on the fca port.
361 */
362 for (discIndex = 0;
363 discIndex < portAttrs.NumberofDiscoveredPorts;
364 discIndex++) {
365 if (getDiscPortAttrs(handle, portIndex,
366 discIndex, &discPortAttrs)) {
367 /* Move on to the next target */
368 continue;
369 }
370 memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t));
371 cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno);
372 if (dyncomp == NULL) {
373 cfga_err(errstring, l_errno, ERR_LIST, 0);
374 list_free(&larg.listp);
375 S_FREE(larg.xport_logp);
376 HBA_CloseAdapter(handle);
377 HBA_FreeLibrary();
378 return (FPCFGA_LIB_ERR);
379 }
380 inq_dtype = get_inq_dtype(apidp->xport_phys, dyncomp,
381 handle, &portAttrs, &discPortAttrs);
382
383 if ((ret = init_ldata_for_accessible_dev(
384 dyncomp, inq_dtype, &larg)) != FPCFGA_OK) {
385 S_FREE(dyncomp);
386 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
387 list_free(&larg.listp);
388 S_FREE(larg.xport_logp);
389 HBA_CloseAdapter(handle);
390 HBA_FreeLibrary();
391 return (FPCFGA_LIB_ERR);
392 }
393 S_FREE(dyncomp);
394 }
395 break;
396 default:
397 break;
398 }
399
400 /* we need to stat at least 1 device for all commands */
401 if (apidp->flags == FLAG_DEVINFO_FORCE) {
402 walkarg.flags = FLAG_DEVINFO_FORCE;
403 } else {
404 walkarg.flags = 0;
405 }
406
407 walkarg.flags |= FLAG_PATH_INFO_WALK;
408 walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST;
409 walkarg.walkmode.node_args.fcn = stat_fc_dev;
410
411 /*
412 * Subtree is ALWAYS rooted at the HBA (not at the device) as
413 * otherwise deadlock may occur if bus is disconnected.
414 *
415 * DINFOPROP was sufficient on apidp->xport_phys prior to the support
416 * on scsi_vhci child node. In order to get the link between
417 * scsi_vhci node and path info node the snap shot of the
418 * the whole device tree is required with DINFOCPYALL | DINFOPATH flag.
419 */
420 ret = walk_tree(apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH,
421 &walkarg, FPCFGA_WALK_NODE, &larg.l_errno);
422
423 /*
424 * ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR.
425 * larg.ret is used to detect other errors. Make sure larg.ret
426 * is set to a correct error.
427 */
428 if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) {
429 if (ret != FPCFGA_APID_NOEXIST) {
430 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
431 }
432 /* if larg.ret = FPCFGA_APID_NOEXIST; */
433 goto out;
434 }
435
436 assert(larg.listp != NULL);
437
438 n = 0;
439 ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n,
440 NO_FLAG);
441 if (ret != FPCFGA_OK) {
442 cfga_err(errstring, 0, ERR_LIST, 0);
443 ret = FPCFGA_LIB_ERR;
444 goto out;
445 }
446
447 *nelemp = n;
448 *llpp = larg.listp;
449 ret = FPCFGA_OK;
450 /* FALLTHROUGH */
451 out:
452 if (ret != FPCFGA_OK) list_free(&larg.listp);
453 S_FREE(larg.xport_logp);
454 HBA_CloseAdapter(handle);
455 HBA_FreeLibrary();
456 return (ret);
457 }
458
459 /*
460 * Main routine for list operation when show_FCP_dev option is given.
461 * It calls various routines to consturct ldata list and
462 * postprocess the list data.
463 *
464 * The difference between do_list() and do_list_FCP_dev() is to
465 * process FCP SCSI LUN data list via uscsi report lun operation and
466 * stat lun level instead of port WWN based target level.
467 * The rest of logic is same.
468 *
469 * Overall algorithm:
470 * Get the device list on input hba port and construct ldata list for
471 * accesible devices.
472 * For each configured device, USCSI report lun is issued and ldata list
473 * with FCP device level(LUN) information is created.
474 * Stat hba port and LUN devices through walking the device tree.
475 * Verify the validity of the list data.
476 */
477 fpcfga_ret_t
do_list_FCP_dev(const char * ap_id,uint_t flags,fpcfga_cmd_t cmd,ldata_list_t ** llpp,int * nelemp,char ** errstring)478 do_list_FCP_dev(
479 const char *ap_id,
480 uint_t flags,
481 fpcfga_cmd_t cmd,
482 ldata_list_t **llpp,
483 int *nelemp,
484 char **errstring)
485 {
486 int n = -1, l_errno = 0, limited_stat, len;
487 walkarg_t walkarg;
488 fpcfga_list_t larg = {NULL};
489 fpcfga_ret_t ret;
490 la_wwn_t pwwn;
491 char *xport_phys = NULL, *dyn = NULL, *dyncomp = NULL,
492 *lun_dyn = NULL;
493 apid_t apid_con = {NULL};
494 HBA_HANDLE handle;
495 HBA_PORTATTRIBUTES portAttrs;
496 HBA_PORTATTRIBUTES discPortAttrs;
497 HBA_STATUS status;
498 int portIndex, discIndex;
499 int retry;
500 uint64_t lun = 0;
501 struct scsi_inquiry inq;
502 struct scsi_extended_sense sense;
503 HBA_UINT8 scsiStatus;
504 uint32_t inquirySize = sizeof (inq),
505 senseSize = sizeof (sense);
506
507 if (*llpp != NULL || *nelemp != 0) {
508 return (FPCFGA_ERR);
509 }
510
511 if ((xport_phys = pathdup(ap_id, &l_errno)) == NULL) {
512 cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
513 return (FPCFGA_LIB_ERR);
514 }
515
516 /* Extract the base(hba) and dynamic(device) component if any */
517 if ((dyn = GET_DYN(xport_phys)) != NULL) {
518 len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
519 dyncomp = calloc(1, len);
520 if (dyncomp == NULL) {
521 cfga_err(errstring, errno, ERR_OP_FAILED, 0);
522 S_FREE(xport_phys);
523 return (FPCFGA_LIB_ERR);
524 }
525
526 (void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
527 /* Remove the dynamic component from the base. */
528 *dyn = '\0';
529 /* if lun dyncomp exists delete it */
530 if ((lun_dyn = GET_LUN_DYN(dyncomp)) != NULL) {
531 *lun_dyn = '\0';
532 }
533 }
534
535 apid_con.xport_phys = xport_phys;
536 apid_con.dyncomp = dyncomp;
537 apid_con.flags = flags;
538
539 larg.apidp = &apid_con;
540
541 /* Create the hba logid (also base component of logical ap_id) */
542 ret = make_xport_logid(larg.apidp->xport_phys, &larg.xport_logp,
543 &l_errno);
544 if (ret != FPCFGA_OK) {
545 cfga_err(errstring, l_errno, ERR_LIST, 0);
546 S_FREE(larg.apidp->xport_phys);
547 S_FREE(larg.apidp->dyncomp);
548 return (FPCFGA_ERR);
549 }
550
551 assert(larg.xport_logp != NULL);
552
553 larg.cmd = cmd;
554 larg.xport_rstate = CFGA_STAT_NONE;
555
556 if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle,
557 &portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
558 S_FREE(larg.xport_logp);
559 S_FREE(larg.apidp->dyncomp);
560 return (ret);
561 }
562
563 /*
564 * If stating a specific device, we will do limited stat on fca port.
565 * otherwise full stat on fca part is required.
566 * If stating a specific device we don't know if it exists or is
567 * configured yet. larg.ret is set to apid noexist for do_stat_dev.
568 * otherwise larg.ret is set to ok initially.
569 */
570 if (larg.cmd == FPCFGA_STAT_FC_DEV) {
571 limited_stat = 1; /* for do_stat_fca_xport */
572 larg.ret = FPCFGA_APID_NOEXIST; /* for stat_fc_dev */
573 } else {
574 limited_stat = 0; /* for do_stat_fca_xport */
575 larg.ret = FPCFGA_OK; /* for stat_fc_dev */
576 }
577
578 /* For all list commands, the fca port needs to be stat'ed */
579 if ((ret = do_stat_fca_xport(&larg, limited_stat,
580 portAttrs)) != FPCFGA_OK) {
581 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
582 list_free(&larg.listp);
583 S_FREE(larg.xport_logp);
584 S_FREE(larg.apidp->xport_phys);
585 S_FREE(larg.apidp->dyncomp);
586 HBA_CloseAdapter(handle);
587 HBA_FreeLibrary();
588 return (ret);
589 }
590
591 /*
592 * If stat'ing a FCA port or ALL, we have the bus stat data at
593 * this point.
594 * Assume that the bus has no configured children.
595 */
596 larg.chld_config = CFGA_STAT_UNCONFIGURED;
597
598 switch (larg.cmd) {
599 case FPCFGA_STAT_FC_DEV:
600 /* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */
601 if (cvt_dyncomp_to_lawwn(larg.apidp->dyncomp, &pwwn) != 0) {
602 cfga_err(errstring, 0, ERR_LIST, 0);
603 list_free(&larg.listp);
604 S_FREE(larg.xport_logp);
605 S_FREE(larg.apidp->xport_phys);
606 S_FREE(larg.apidp->dyncomp);
607 HBA_CloseAdapter(handle);
608 HBA_FreeLibrary();
609 return (FPCFGA_LIB_ERR);
610 }
611 /*
612 * if the dyncomp exists on disco ports construct list_data
613 * otherwise return FPCFGA_APID_NOEXIST.
614 */
615 retry = 0;
616 do {
617 status = getPortAttrsByWWN(handle,
618 *((HBA_WWN *)(&pwwn)), &discPortAttrs);
619 if (status == HBA_STATUS_ERROR_STALE_DATA) {
620 /* get Port Attributes again after refresh. */
621 HBA_RefreshInformation(handle);
622 } else {
623 break; /* either okay or some other error */
624 }
625 } while (retry++ < HBA_MAX_RETRIES);
626
627 if (status == HBA_STATUS_OK) {
628 /*
629 * if dyncomp exists only in dev list
630 * construct ldata_list and return.
631 * otherwise continue to stat on dev tree with
632 * larg.ret set to access_ok which informs stat_fc_dev
633 * the existence of device on dev_list.
634 *
635 * if path is null that guatantees the node is not
636 * configured. if node is detached the path
637 * is incomplete and not usable for further
638 * operations like uscsi_inq so take care of it here.
639 */
640 status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
641 discPortAttrs.PortWWN, lun, 0, 0,
642 &inq, &inquirySize, &scsiStatus,
643 &sense, &senseSize);
644 if (status == HBA_STATUS_OK) {
645 inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
646 } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
647 inq.inq_dtype = DTYPE_UNKNOWN;
648 } else {
649 inq.inq_dtype = ERR_INQ_DTYPE;
650 }
651
652 if (init_ldata_for_accessible_dev(larg.apidp->dyncomp,
653 inq.inq_dtype, &larg) != FPCFGA_OK) {
654 cfga_err(errstring, larg.l_errno,
655 ERR_LIST, 0);
656 list_free(&larg.listp);
657 S_FREE(larg.xport_logp);
658 S_FREE(larg.apidp->xport_phys);
659 S_FREE(larg.apidp->dyncomp);
660 HBA_CloseAdapter(handle);
661 HBA_FreeLibrary();
662 return (FPCFGA_LIB_ERR);
663 }
664 if ((ret = get_accessible_FCP_dev_ldata(
665 larg.apidp->dyncomp, &larg, &l_errno))
666 != FPCFGA_OK) {
667 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
668 list_free(&larg.listp);
669 S_FREE(larg.xport_logp);
670 S_FREE(larg.apidp->xport_phys);
671 S_FREE(larg.apidp->dyncomp);
672 HBA_CloseAdapter(handle);
673 HBA_FreeLibrary();
674 return (FPCFGA_LIB_ERR);
675 } else {
676 /* continue to stat dev with access okay. */
677 larg.ret = FPCFGA_ACCESS_OK;
678 }
679 } else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
680 /*
681 * path indicates if the node exists in dev tree.
682 * if not found in dev tree return apid no exist.
683 * otherwise continue to stat with larg.ret set to
684 * apid_noexist.
685 */
686 if (larg.apidp->lunlist == NULL) {
687 list_free(&larg.listp);
688 S_FREE(larg.xport_logp);
689 HBA_CloseAdapter(handle);
690 HBA_FreeLibrary();
691 return (FPCFGA_APID_NOEXIST);
692 }
693 } else { /* not found or any error */
694 /*
695 * continue to stat dev with larg.ret set to
696 * apid_noexist.
697 */
698 larg.ret = FPCFGA_APID_NOEXIST;
699 }
700 break;
701 case FPCFGA_STAT_ALL:
702 /*
703 * for each dev in disco ports, create a ldata_list element.
704 * if if no disco ports found, continue to stat on devinfo tree
705 * to see if any node exist on the fca port.
706 */
707 for (discIndex = 0;
708 discIndex < portAttrs.NumberofDiscoveredPorts;
709 discIndex++) {
710 if (getDiscPortAttrs(handle, portIndex,
711 discIndex, &discPortAttrs)) {
712 /* Move on to the next target */
713 continue;
714 }
715 memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t));
716 cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno);
717 if (dyncomp == NULL) {
718 cfga_err(errstring, l_errno, ERR_LIST, 0);
719 list_free(&larg.listp);
720 S_FREE(larg.xport_logp);
721 S_FREE(larg.apidp->xport_phys);
722 S_FREE(larg.apidp->dyncomp);
723 HBA_CloseAdapter(handle);
724 HBA_FreeLibrary();
725 return (FPCFGA_LIB_ERR);
726 }
727 status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
728 discPortAttrs.PortWWN, lun, 0, 0,
729 &inq, &inquirySize, &scsiStatus,
730 &sense, &senseSize);
731 if (status == HBA_STATUS_OK) {
732 inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
733 } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
734 inq.inq_dtype = DTYPE_UNKNOWN;
735 } else {
736 inq.inq_dtype = ERR_INQ_DTYPE;
737 }
738 if ((ret = init_ldata_for_accessible_dev(
739 dyncomp, inq.inq_dtype, &larg)) != FPCFGA_OK) {
740 S_FREE(dyncomp);
741 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
742 list_free(&larg.listp);
743 S_FREE(larg.xport_logp);
744 S_FREE(larg.apidp->xport_phys);
745 S_FREE(larg.apidp->dyncomp);
746 HBA_CloseAdapter(handle);
747 HBA_FreeLibrary();
748 return (FPCFGA_LIB_ERR);
749 }
750 if ((ret = get_accessible_FCP_dev_ldata(
751 dyncomp, &larg, &l_errno)) != FPCFGA_OK) {
752 S_FREE(dyncomp);
753 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
754 list_free(&larg.listp);
755 S_FREE(larg.xport_logp);
756 S_FREE(larg.apidp->xport_phys);
757 S_FREE(larg.apidp->dyncomp);
758 HBA_CloseAdapter(handle);
759 HBA_FreeLibrary();
760 return (ret);
761 }
762 S_FREE(dyncomp);
763 }
764 break;
765 /* default: continue */
766 }
767
768 /* we need to stat at least 1 device for all commands */
769 if ((larg.apidp->flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) {
770 walkarg.flags = FLAG_DEVINFO_FORCE;
771 } else {
772 walkarg.flags = 0;
773 }
774
775 walkarg.flags |= FLAG_PATH_INFO_WALK;
776 walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST;
777 walkarg.walkmode.node_args.fcn = stat_FCP_dev;
778
779 /*
780 * Subtree is ALWAYS rooted at the HBA (not at the device) as
781 * otherwise deadlock may occur if bus is disconnected.
782 *
783 * DINFOPROP was sufficient on apidp->xport_phys prior to the support
784 * on scsi_vhci child node. In order to get the link between
785 * scsi_vhci node and path info node the snap shot of the
786 * the whole device tree is required with DINFOCPYALL | DINFOPATH flag.
787 */
788 ret = walk_tree(larg.apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH,
789 &walkarg, FPCFGA_WALK_NODE, &larg.l_errno);
790
791 /*
792 * ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR.
793 * larg.ret is used to detect other errors. Make sure larg.ret
794 * is set to a correct error.
795 */
796 if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) {
797 if (ret != FPCFGA_APID_NOEXIST) {
798 cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
799 }
800 /* if larg.ret = FPCFGA_APID_NOEXIST return. */
801 list_free(&larg.listp);
802 S_FREE(larg.xport_logp);
803 S_FREE(larg.apidp->xport_phys);
804 S_FREE(larg.apidp->dyncomp);
805 HBA_CloseAdapter(handle);
806 HBA_FreeLibrary();
807 return (ret);
808 }
809
810 assert(larg.listp != NULL);
811
812 n = 0;
813 ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n,
814 flags);
815 if (ret != FPCFGA_OK) {
816 cfga_err(errstring, 0, ERR_LIST, 0);
817 list_free(&larg.listp);
818 S_FREE(larg.xport_logp);
819 S_FREE(larg.apidp->xport_phys);
820 S_FREE(larg.apidp->dyncomp);
821 HBA_CloseAdapter(handle);
822 HBA_FreeLibrary();
823 return (FPCFGA_LIB_ERR);
824 }
825
826 *nelemp = n;
827 *llpp = larg.listp;
828 ret = FPCFGA_OK;
829 S_FREE(larg.xport_logp);
830 S_FREE(larg.apidp->xport_phys);
831 S_FREE(larg.apidp->dyncomp);
832 HBA_CloseAdapter(handle);
833 HBA_FreeLibrary();
834 return (FPCFGA_OK);
835 }
836
837 /*
838 * This routine returns initialize struct fcp_ioctl.
839 */
840 static void
init_fcp_scsi_cmd(struct fcp_scsi_cmd * fscsi,uchar_t * lun_num,la_wwn_t * pwwn,void * scmdbuf,size_t scmdbuf_len,void * respbuf,size_t respbuf_len,void * sensebuf,size_t sensebuf_len)841 init_fcp_scsi_cmd(
842 struct fcp_scsi_cmd *fscsi,
843 uchar_t *lun_num,
844 la_wwn_t *pwwn,
845 void *scmdbuf,
846 size_t scmdbuf_len,
847 void *respbuf,
848 size_t respbuf_len,
849 void *sensebuf,
850 size_t sensebuf_len)
851 {
852 memset(fscsi, 0, sizeof (struct fcp_scsi_cmd));
853 memset(scmdbuf, 0, scmdbuf_len);
854 memcpy(fscsi->scsi_fc_pwwn.raw_wwn, pwwn, sizeof (u_longlong_t));
855 fscsi->scsi_fc_rspcode = 0;
856 fscsi->scsi_flags = FCP_SCSI_READ;
857 fscsi->scsi_timeout = FCP_SCSI_CMD_TIMEOUT; /* second */
858 fscsi->scsi_cdbbufaddr = (caddr_t)scmdbuf;
859 fscsi->scsi_cdblen = scmdbuf_len;
860 fscsi->scsi_bufaddr = (caddr_t)respbuf;
861 fscsi->scsi_buflen = respbuf_len;
862 fscsi->scsi_bufresid = 0;
863 fscsi->scsi_bufstatus = 0;
864 fscsi->scsi_rqbufaddr = (caddr_t)sensebuf;
865 fscsi->scsi_rqlen = sensebuf_len;
866 fscsi->scsi_rqresid = 0;
867 memcpy(&fscsi->scsi_lun, lun_num, sizeof (fscsi->scsi_lun));
868 }
869
870 /*
871 * This routine returns issues FCP_TGT_SEND_SCSI
872 */
873 static fpcfga_ret_t
issue_fcp_scsi_cmd(const char * xport_phys,struct fcp_scsi_cmd * fscsi,int * l_errnop)874 issue_fcp_scsi_cmd(
875 const char *xport_phys,
876 struct fcp_scsi_cmd *fscsi,
877 int *l_errnop)
878 {
879 struct stat stbuf;
880 int fcp_fd, retry, rv;
881
882 if (stat(xport_phys, &stbuf) < 0) {
883 *l_errnop = errno;
884 return (FPCFGA_LIB_ERR);
885 }
886
887 fscsi->scsi_fc_port_num = (uint32_t)minor(stbuf.st_rdev);
888 fcp_fd = open(FCP_PATH, O_RDONLY | O_NDELAY);
889 retry = 0;
890 while (fcp_fd < 0 && retry++ < OPEN_RETRY_COUNT && (
891 errno == EBUSY || errno == EAGAIN)) {
892 (void) usleep(OPEN_RETRY_INTERVAL);
893 fcp_fd = open(FCP_PATH, O_RDONLY|O_NDELAY);
894 }
895 if (fcp_fd < 0) {
896 *l_errnop = errno;
897 return (FPCFGA_LIB_ERR);
898 }
899
900 rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi);
901 retry = 0;
902 while ((rv != 0 && retry++ < IOCTL_RETRY_COUNT &&
903 (errno == EBUSY || errno == EAGAIN)) ||
904 (retry++ < IOCTL_RETRY_COUNT &&
905 ((uchar_t)fscsi->scsi_bufstatus & STATUS_MASK)
906 == STATUS_BUSY)) {
907 (void) usleep(IOCTL_RETRY_INTERVAL);
908 rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi);
909 }
910 close(fcp_fd);
911
912 if (fscsi->scsi_fc_status == FC_DEVICE_NOT_TGT) {
913 return (FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT);
914 } else if (rv != 0 || fscsi->scsi_bufstatus != 0) {
915 *l_errnop = errno;
916 return (FPCFGA_FCP_TGT_SEND_SCSI_FAILED);
917 }
918 return (FPCFGA_OK);
919 }
920
921 /*
922 * This routine returns standard inq data for
923 * a target represented by dyncomp.
924 *
925 * Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get inquiry data.
926 *
927 * Caller should free the *inq_buf.
928 */
929 static fpcfga_ret_t
get_standard_inq_data(const char * xport_phys,const char * dyncomp,uchar_t * lun_num,struct scsi_inquiry ** inq_buf,int * l_errnop)930 get_standard_inq_data(
931 const char *xport_phys,
932 const char *dyncomp,
933 uchar_t *lun_num,
934 struct scsi_inquiry **inq_buf,
935 int *l_errnop)
936 {
937 struct fcp_scsi_cmd fscsi;
938 struct scsi_extended_sense sensebuf;
939 union scsi_cdb scsi_inq_req;
940 la_wwn_t pwwn;
941 int alloc_len;
942 fpcfga_ret_t ret;
943
944
945 alloc_len = sizeof (struct scsi_inquiry);
946 if ((*inq_buf = (struct scsi_inquiry *)calloc(1, alloc_len)) == NULL) {
947 *l_errnop = errno;
948 return (FPCFGA_LIB_ERR);
949 }
950
951 if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) {
952 return (FPCFGA_LIB_ERR);
953 }
954
955 init_fcp_scsi_cmd(&fscsi, lun_num, &pwwn, &scsi_inq_req,
956 sizeof (scsi_inq_req), *inq_buf, alloc_len, &sensebuf,
957 sizeof (struct scsi_extended_sense));
958 scsi_inq_req.scc_cmd = SCMD_INQUIRY;
959 scsi_inq_req.g0_count0 = sizeof (struct scsi_inquiry);
960
961 if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
962 != FPCFGA_OK) {
963 S_FREE(*inq_buf);
964 return (ret);
965 }
966
967 return (FPCFGA_OK);
968 }
969
970 /*
971 * This routine returns report lun data and number of luns found
972 * on a target represented by dyncomp.
973 *
974 * Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get report lun data.
975 *
976 * Caller should free the *resp_buf when FPCFGA_OK is returned.
977 */
978 fpcfga_ret_t
get_report_lun_data(const char * xport_phys,const char * dyncomp,int * num_luns,report_lun_resp_t ** resp_buf,struct scsi_extended_sense * sensebuf,int * l_errnop)979 get_report_lun_data(
980 const char *xport_phys,
981 const char *dyncomp,
982 int *num_luns,
983 report_lun_resp_t **resp_buf,
984 struct scsi_extended_sense *sensebuf,
985 int *l_errnop)
986 {
987 struct fcp_scsi_cmd fscsi;
988 union scsi_cdb scsi_rl_req;
989 la_wwn_t pwwn;
990 int alloc_len;
991 fpcfga_ret_t ret;
992 uchar_t lun_data[SAM_LUN_SIZE];
993
994 alloc_len = sizeof (struct report_lun_resp);
995 if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len)) == NULL) {
996 *l_errnop = errno;
997 return (FPCFGA_LIB_ERR);
998 }
999
1000 if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) {
1001 S_FREE(*resp_buf);
1002 return (FPCFGA_LIB_ERR);
1003 }
1004
1005 /* sending to LUN 0 so initializing lun_data buffer to be 0 */
1006 memset(lun_data, 0, sizeof (lun_data));
1007 init_fcp_scsi_cmd(&fscsi, lun_data, &pwwn, &scsi_rl_req,
1008 sizeof (scsi_rl_req), *resp_buf, alloc_len, sensebuf,
1009 sizeof (struct scsi_extended_sense));
1010 scsi_rl_req.scc_cmd = FP_SCMD_REPORT_LUN;
1011 FORMG5COUNT(&scsi_rl_req, alloc_len);
1012
1013 if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
1014 != FPCFGA_OK) {
1015 S_FREE(*resp_buf);
1016 return (ret);
1017 }
1018
1019 if (ntohl((*resp_buf)->num_lun) >
1020 (sizeof (struct report_lun_resp) - REPORT_LUN_HDR_SIZE)) {
1021 alloc_len = (*resp_buf)->num_lun + REPORT_LUN_HDR_SIZE;
1022 S_FREE(*resp_buf);
1023 if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len))
1024 == NULL) {
1025 *l_errnop = errno;
1026 return (FPCFGA_LIB_ERR);
1027 }
1028 (void) memset((char *)*resp_buf, 0, alloc_len);
1029 FORMG5COUNT(&scsi_rl_req, alloc_len);
1030
1031 fscsi.scsi_bufaddr = (caddr_t)*resp_buf;
1032 fscsi.scsi_buflen = alloc_len;
1033
1034 if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
1035 != FPCFGA_OK) {
1036 S_FREE(*resp_buf);
1037 return (ret);
1038 }
1039 }
1040
1041 /* num_lun represent number of luns * 8. */
1042 *num_luns = ntohl((*resp_buf)->num_lun) >> 3;
1043
1044 return (FPCFGA_OK);
1045 }
1046
1047 /*
1048 * Routine for consturct ldata list for each FCP SCSI LUN device
1049 * for a discovered target device.
1050 * It calls get_report_lun_data to get report lun data and
1051 * construct ldata list per each lun.
1052 *
1053 * It is called only when show_FCP_dev option is given.
1054 *
1055 * Overall algorithm:
1056 * Get the report lun data thru FCP passthru ioctl.
1057 * Call init_ldata_for_accessible_FCP_dev to process the report LUN data.
1058 * For each LUN found standard inquiry is issued to get device type.
1059 */
1060 static fpcfga_ret_t
get_accessible_FCP_dev_ldata(const char * dyncomp,fpcfga_list_t * lap,int * l_errnop)1061 get_accessible_FCP_dev_ldata(
1062 const char *dyncomp,
1063 fpcfga_list_t *lap,
1064 int *l_errnop)
1065 {
1066 report_lun_resp_t *resp_buf;
1067 struct scsi_extended_sense sense;
1068 int num_luns;
1069 fpcfga_ret_t ret;
1070
1071 memset(&sense, 0, sizeof (sense));
1072 if ((ret = get_report_lun_data(lap->apidp->xport_phys, dyncomp,
1073 &num_luns, &resp_buf, &sense, l_errnop)) != FPCFGA_OK) {
1074 /*
1075 * when report lun data fails then return FPCFGA_OK thus
1076 * keep the ldata for the target which is acquired previously.
1077 * For remote hba node this will be normal.
1078 * For a target error may already be detected through
1079 * FCP_TGT_INQ.
1080 */
1081 if ((ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) ||
1082 (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT)) {
1083 ret = FPCFGA_OK;
1084 }
1085 return (ret);
1086 }
1087
1088 if (num_luns > 0) {
1089 ret = init_ldata_for_accessible_FCP_dev(
1090 dyncomp, num_luns, resp_buf, lap, l_errnop);
1091 } else {
1092 /*
1093 * proceed with to stat if no lun found.
1094 * This will make the target apid will be kept.
1095 */
1096 ret = FPCFGA_OK;
1097 }
1098
1099 S_FREE(resp_buf);
1100 return (ret);
1101 }
1102
1103 /*
1104 * Routine for checking validity of ldata list based on input argumemnt.
1105 * Set the occupant state of hba port if the list is valid.
1106 */
1107 static fpcfga_ret_t
postprocess_list_data(const ldata_list_t * listp,fpcfga_cmd_t cmd,cfga_stat_t chld_config,int * np,uint_t flags)1108 postprocess_list_data(
1109 const ldata_list_t *listp,
1110 fpcfga_cmd_t cmd,
1111 cfga_stat_t chld_config,
1112 int *np,
1113 uint_t flags)
1114 {
1115 ldata_list_t *tmplp = NULL;
1116 cfga_list_data_t *xport_ldatap = NULL;
1117 int i;
1118
1119
1120 *np = 0;
1121
1122 if (listp == NULL) {
1123 return (FPCFGA_ERR);
1124 }
1125
1126 tmplp = (ldata_list_t *)listp;
1127 for (i = 0; tmplp != NULL; tmplp = tmplp->next) {
1128 i++;
1129 if (GET_DYN(tmplp->ldata.ap_phys_id) == NULL) {
1130 /* A bus stat data */
1131 assert(GET_DYN(tmplp->ldata.ap_log_id) == NULL);
1132 xport_ldatap = &tmplp->ldata;
1133 #ifdef DEBUG
1134 } else {
1135 assert(GET_DYN(tmplp->ldata.ap_log_id) != NULL);
1136 #endif
1137 }
1138 }
1139
1140 switch (cmd) {
1141 case FPCFGA_STAT_FC_DEV:
1142 if ((flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) {
1143 if (i < 1 || xport_ldatap != NULL) {
1144 return (FPCFGA_LIB_ERR);
1145 }
1146 } else {
1147 if (i != 1 || xport_ldatap != NULL) {
1148 return (FPCFGA_LIB_ERR);
1149 }
1150 }
1151 break;
1152 case FPCFGA_STAT_FCA_PORT:
1153 if (i != 1 || xport_ldatap == NULL) {
1154 return (FPCFGA_LIB_ERR);
1155 }
1156 break;
1157 case FPCFGA_STAT_ALL:
1158 if (i < 1 || xport_ldatap == NULL) {
1159 return (FPCFGA_LIB_ERR);
1160 }
1161 break;
1162 default:
1163 return (FPCFGA_LIB_ERR);
1164 }
1165
1166 *np = i;
1167
1168 /* Fill in the occupant (child) state. */
1169 if (xport_ldatap != NULL) {
1170 xport_ldatap->ap_o_state = chld_config;
1171 }
1172 return (FPCFGA_OK);
1173 }
1174
1175 /*
1176 * Routine for checking each target device found in device tree.
1177 * When the matching port WWN dev is found from the accessble ldata list
1178 * the target device is updated with configured ostate.
1179 *
1180 * Overall algorithm:
1181 * Parse the device tree to find configured devices which matches with
1182 * list argument. If cmd is stat on a specific target device it
1183 * matches port WWN and continues to further processing. If cmd is
1184 * stat on hba port all the device target under the hba are processed.
1185 */
1186 static int
stat_fc_dev(di_node_t node,void * arg)1187 stat_fc_dev(di_node_t node, void *arg)
1188 {
1189 fpcfga_list_t *lap = NULL;
1190 char *devfsp = NULL, *nodepath = NULL;
1191 size_t len = 0;
1192 int limited_stat = 0, match_minor, rv;
1193 fpcfga_ret_t ret;
1194 di_prop_t prop = DI_PROP_NIL;
1195 uchar_t *port_wwn_data;
1196 char port_wwn[WWN_SIZE*2+1];
1197 int count;
1198
1199 lap = (fpcfga_list_t *)arg;
1200
1201 /*
1202 * Skip partial nodes
1203 *
1204 * This checking is from the scsi plug-in and will be deleted for
1205 * fp plug-in. The node will be processed for fp even if it is
1206 * in driver detached state. From fp perspective the node is configured
1207 * as long as the node is not in offline or down state.
1208 * scsi plug-in considers the known state when it is offlined
1209 * regradless of driver detached state or when it is not in driver
1210 * detached state like normal state.
1211 * If the node is only in driver detached state it is considered as
1212 * unknown state.
1213 *
1214 * if (!known_state(node) && (lap->cmd != FPCFGA_STAT_FC_DEV)) {
1215 * return (DI_WALK_CONTINUE);
1216 *
1217 */
1218
1219 devfsp = di_devfs_path(node);
1220 if (devfsp == NULL) {
1221 rv = DI_WALK_CONTINUE;
1222 goto out;
1223 }
1224
1225 len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
1226
1227 nodepath = calloc(1, len);
1228 if (nodepath == NULL) {
1229 lap->l_errno = errno;
1230 lap->ret = FPCFGA_LIB_ERR;
1231 rv = DI_WALK_TERMINATE;
1232 goto out;
1233 }
1234
1235 (void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
1236
1237 /* Skip node if it is HBA */
1238 match_minor = 0;
1239 if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) {
1240 rv = DI_WALK_CONTINUE;
1241 goto out;
1242 }
1243
1244 /* If stat'ing a specific device, is this node that device */
1245 if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1246 /* checks port wwn property to find a match */
1247 while ((prop = di_prop_next(node, prop))
1248 != DI_PROP_NIL) {
1249 if ((strcmp(PORT_WWN_PROP,
1250 di_prop_name(prop)) == 0) &&
1251 (di_prop_type(prop) ==
1252 DI_PROP_TYPE_BYTE)) {
1253 break;
1254 }
1255 }
1256
1257 if (prop != DI_PROP_NIL) {
1258 count = di_prop_bytes(prop, &port_wwn_data);
1259 if (count != WWN_SIZE) {
1260 lap->ret = FPCFGA_LIB_ERR;
1261 rv = DI_WALK_TERMINATE;
1262 goto out;
1263 }
1264 (void) sprintf(port_wwn, "%016llx",
1265 (wwnConversion(port_wwn_data)));
1266 /*
1267 * port wwn doesn't match contine to walk
1268 * if match call do_stat_fc_dev.
1269 */
1270 if (strncmp(port_wwn, lap->apidp->dyncomp,
1271 WWN_SIZE*2)) {
1272 rv = DI_WALK_CONTINUE;
1273 goto out;
1274 }
1275 } else {
1276 rv = DI_WALK_CONTINUE;
1277 goto out;
1278 }
1279 }
1280
1281 /*
1282 * If stat'ing a xport only, we look at device nodes only to get
1283 * xport configuration status. So a limited stat will suffice.
1284 */
1285 if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
1286 limited_stat = 1;
1287 } else {
1288 limited_stat = 0;
1289 }
1290
1291 /*
1292 * Ignore errors if stat'ing a bus or listing all
1293 */
1294 ret = do_stat_fc_dev(node, nodepath, lap, limited_stat);
1295 if (ret != FPCFGA_OK) {
1296 if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1297 lap->ret = ret;
1298 rv = DI_WALK_TERMINATE;
1299 } else {
1300 rv = DI_WALK_CONTINUE;
1301 }
1302 goto out;
1303 }
1304
1305 /* Are we done ? */
1306 rv = DI_WALK_CONTINUE;
1307 if (lap->cmd == FPCFGA_STAT_FCA_PORT &&
1308 lap->chld_config == CFGA_STAT_CONFIGURED) {
1309 rv = DI_WALK_TERMINATE;
1310 } else if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1311 /*
1312 * If stat'ing a specific device, we are done at this point.
1313 */
1314 rv = DI_WALK_TERMINATE;
1315 }
1316
1317 /*FALLTHRU*/
1318 out:
1319 S_FREE(nodepath);
1320 if (devfsp != NULL) di_devfs_path_free(devfsp);
1321 return (rv);
1322 }
1323
1324 /*
1325 * Routine for checking each FCP SCSI LUN device found in device tree.
1326 * When the matching port WWN and LUN are found from the accessble ldata list
1327 * the FCP SCSI LUN is updated with configured ostate.
1328 *
1329 * Overall algorithm:
1330 * Parse the device tree to find configured devices which matches with
1331 * list argument. If cmd is stat on a specific target device it
1332 * matches port WWN and continues to further processing. If cmd is
1333 * stat on hba port all the FCP SCSI LUN under the hba are processed.
1334 */
1335 static int
stat_FCP_dev(di_node_t node,void * arg)1336 stat_FCP_dev(di_node_t node, void *arg)
1337 {
1338 fpcfga_list_t *lap = NULL;
1339 char *devfsp = NULL, *nodepath = NULL;
1340 size_t len = 0;
1341 int limited_stat = 0, match_minor, rv, di_ret;
1342 fpcfga_ret_t ret;
1343 uchar_t *port_wwn_data;
1344 char port_wwn[WWN_SIZE*2+1];
1345
1346 lap = (fpcfga_list_t *)arg;
1347
1348 devfsp = di_devfs_path(node);
1349 if (devfsp == NULL) {
1350 rv = DI_WALK_CONTINUE;
1351 goto out;
1352 }
1353
1354 len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
1355
1356 nodepath = calloc(1, len);
1357 if (nodepath == NULL) {
1358 lap->l_errno = errno;
1359 lap->ret = FPCFGA_LIB_ERR;
1360 rv = DI_WALK_TERMINATE;
1361 goto out;
1362 }
1363
1364 (void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
1365
1366 /* Skip node if it is HBA */
1367 match_minor = 0;
1368 if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) {
1369 rv = DI_WALK_CONTINUE;
1370 goto out;
1371 }
1372
1373 /* If stat'ing a specific device, is this node that device */
1374 if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1375 /* checks port wwn property to find a match */
1376 di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
1377 PORT_WWN_PROP, &port_wwn_data);
1378 if (di_ret == -1) {
1379 rv = DI_WALK_CONTINUE;
1380 goto out;
1381 } else {
1382 (void) sprintf(port_wwn, "%016llx",
1383 (wwnConversion(port_wwn_data)));
1384 /*
1385 * port wwn doesn't match contine to walk
1386 * if match call do_stat_FCP_dev.
1387 */
1388 if (strncmp(port_wwn, lap->apidp->dyncomp,
1389 WWN_SIZE*2)) {
1390 rv = DI_WALK_CONTINUE;
1391 goto out;
1392 }
1393 }
1394 }
1395
1396 /*
1397 * If stat'ing a xport only, we look at device nodes only to get
1398 * xport configuration status. So a limited stat will suffice.
1399 */
1400 if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
1401 limited_stat = 1;
1402 } else {
1403 limited_stat = 0;
1404 }
1405
1406 /*
1407 * Ignore errors if stat'ing a bus or listing all
1408 */
1409 ret = do_stat_FCP_dev(node, nodepath, lap, limited_stat);
1410 if (ret != FPCFGA_OK) {
1411 rv = DI_WALK_CONTINUE;
1412 goto out;
1413 }
1414
1415 /* Are we done ? */
1416 rv = DI_WALK_CONTINUE;
1417 if (lap->cmd == FPCFGA_STAT_FCA_PORT &&
1418 lap->chld_config == CFGA_STAT_CONFIGURED) {
1419 rv = DI_WALK_TERMINATE;
1420 }
1421
1422 /*FALLTHRU*/
1423 out:
1424 S_FREE(nodepath);
1425 if (devfsp != NULL) di_devfs_path_free(devfsp);
1426 return (rv);
1427 }
1428
1429 static fpcfga_ret_t
do_stat_fca_xport(fpcfga_list_t * lap,int limited_stat,HBA_PORTATTRIBUTES portAttrs)1430 do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat,
1431 HBA_PORTATTRIBUTES portAttrs)
1432 {
1433 cfga_list_data_t *clp = NULL;
1434 ldata_list_t *listp = NULL;
1435 int l_errno = 0;
1436 uint_t devinfo_state = 0;
1437 walkarg_t walkarg;
1438 fpcfga_ret_t ret;
1439 cfga_cond_t cond = CFGA_COND_UNKNOWN;
1440
1441 assert(lap->xport_logp != NULL);
1442
1443 /* Get xport state */
1444 if (lap->apidp->flags == FLAG_DEVINFO_FORCE) {
1445 walkarg.flags = FLAG_DEVINFO_FORCE;
1446 } else {
1447 walkarg.flags = 0;
1448 }
1449 walkarg.walkmode.node_args.flags = 0;
1450 walkarg.walkmode.node_args.fcn = get_xport_state;
1451
1452 ret = walk_tree(lap->apidp->xport_phys, &devinfo_state,
1453 DINFOCPYALL | DINFOPATH, &walkarg, FPCFGA_WALK_NODE, &l_errno);
1454 if (ret == FPCFGA_OK) {
1455 lap->xport_rstate = xport_devinfo_to_recep_state(devinfo_state);
1456 } else {
1457 lap->xport_rstate = CFGA_STAT_NONE;
1458 }
1459
1460 /*
1461 * Get topology works okay even if the fp port is connected
1462 * to a switch and no devices connected to the switch.
1463 * In this case the list will only shows fp port info without
1464 * any device listed.
1465 */
1466 switch (portAttrs.PortType) {
1467 case HBA_PORTTYPE_NLPORT:
1468 (void) snprintf(lap->xport_type,
1469 sizeof (lap->xport_type), "%s",
1470 FP_FC_PUBLIC_PORT_TYPE);
1471 break;
1472 case HBA_PORTTYPE_NPORT:
1473 (void) snprintf(lap->xport_type,
1474 sizeof (lap->xport_type), "%s",
1475 FP_FC_FABRIC_PORT_TYPE);
1476 break;
1477 case HBA_PORTTYPE_LPORT:
1478 (void) snprintf(lap->xport_type,
1479 sizeof (lap->xport_type), "%s",
1480 FP_FC_PRIVATE_PORT_TYPE);
1481 break;
1482 case HBA_PORTTYPE_PTP:
1483 (void) snprintf(lap->xport_type,
1484 sizeof (lap->xport_type), "%s",
1485 FP_FC_PT_TO_PT_PORT_TYPE);
1486 break;
1487 /*
1488 * HBA_PORTTYPE_UNKNOWN means nothing is connected
1489 */
1490 case HBA_PORTTYPE_UNKNOWN:
1491 (void) snprintf(lap->xport_type,
1492 sizeof (lap->xport_type), "%s",
1493 FP_FC_PORT_TYPE);
1494 break;
1495 /* NOT_PRESENT, OTHER, FPORT, FLPORT */
1496 default:
1497 (void) snprintf(lap->xport_type,
1498 sizeof (lap->xport_type), "%s",
1499 FP_FC_PORT_TYPE);
1500 cond = CFGA_COND_FAILED;
1501 break;
1502 }
1503
1504 if (limited_stat) {
1505 /* We only want to know bus(receptacle) connect status */
1506 return (FPCFGA_OK);
1507 }
1508
1509 listp = calloc(1, sizeof (ldata_list_t));
1510 if (listp == NULL) {
1511 lap->l_errno = errno;
1512 return (FPCFGA_LIB_ERR);
1513 }
1514
1515 clp = &listp->ldata;
1516
1517 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
1518 lap->xport_logp);
1519 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s",
1520 lap->apidp->xport_phys);
1521
1522 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
1523 clp->ap_r_state = lap->xport_rstate;
1524 clp->ap_o_state = lap->chld_config;
1525 clp->ap_cond = cond;
1526 clp->ap_busy = 0;
1527 clp->ap_status_time = (time_t)-1;
1528 clp->ap_info[0] = '\0';
1529 (void) strncpy(clp->ap_type, lap->xport_type, sizeof (clp->ap_type));
1530
1531 /* Link it in. lap->listp is NULL originally. */
1532 listp->next = lap->listp;
1533 /* lap->listp now gets cfga_list_data for the fca port. */
1534 lap->listp = listp;
1535
1536 return (FPCFGA_OK);
1537 }
1538
1539
1540 static int
get_xport_state(di_node_t node,void * arg)1541 get_xport_state(di_node_t node, void *arg)
1542 {
1543 uint_t *di_statep = (uint_t *)arg;
1544
1545 *di_statep = di_state(node);
1546
1547 return (DI_WALK_TERMINATE);
1548 }
1549
1550 /*
1551 * Routine for updating ldata list based on the state of device node.
1552 * When no matching accessible ldata is found a new ldata is created
1553 * with proper state information.
1554 *
1555 * Overall algorithm:
1556 * If the device node is online and the matching ldata is found
1557 * the target device is updated with configued and unknown condition.
1558 * If the device node is offline or down and the matching ldata is found
1559 * the target device is updated with configued and unusable condition.
1560 * If the device node is online but the matching ldata is not found
1561 * the target device is created with configued and failing condition.
1562 * If the device node is offline or down and the matching ldata is not found
1563 * the target device is created with configued and unusable condition.
1564 */
1565 static fpcfga_ret_t
do_stat_fc_dev(const di_node_t node,const char * nodepath,fpcfga_list_t * lap,int limited_stat)1566 do_stat_fc_dev(
1567 const di_node_t node,
1568 const char *nodepath,
1569 fpcfga_list_t *lap,
1570 int limited_stat)
1571 {
1572 uint_t dctl_state = 0, devinfo_state = 0;
1573 char *dyncomp = NULL;
1574 cfga_list_data_t *clp = NULL;
1575 cfga_busy_t busy;
1576 ldata_list_t *listp = NULL;
1577 ldata_list_t *matchldp = NULL;
1578 int l_errno = 0;
1579 cfga_stat_t ostate;
1580 cfga_cond_t cond;
1581 fpcfga_ret_t ret;
1582
1583 assert(lap->apidp->xport_phys != NULL);
1584 assert(lap->xport_logp != NULL);
1585
1586 cond = CFGA_COND_UNKNOWN;
1587
1588 devinfo_state = di_state(node);
1589 ostate = dev_devinfo_to_occupant_state(devinfo_state);
1590
1591 /*
1592 * NOTE: The framework cannot currently detect layered driver
1593 * opens, so the busy indicator is not very reliable. Also,
1594 * non-root users will not be able to determine busy
1595 * status (libdevice needs root permissions).
1596 * This should probably be fixed by adding a DI_BUSY to the di_state()
1597 * routine in libdevinfo.
1598 */
1599 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state,
1600 &l_errno) == FPCFGA_OK) {
1601 busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
1602 } else {
1603 busy = 0;
1604 }
1605
1606 /* We only want to know device config state */
1607 if (limited_stat) {
1608 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
1609 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
1610 lap->chld_config = CFGA_STAT_CONFIGURED;
1611 } else {
1612 if (ostate != CFGA_STAT_UNCONFIGURED) {
1613 lap->chld_config = CFGA_STAT_CONFIGURED;
1614 }
1615 }
1616 return (FPCFGA_OK);
1617 }
1618
1619 /*
1620 * If child device is configured, see if it is accessible also
1621 * for FPCFGA_STAT_FC_DEV cmd.
1622 */
1623 if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1624 switch (ostate) {
1625 case CFGA_STAT_CONFIGURED:
1626 /*
1627 * if configured and not accessble, the device is
1628 * till be displayed with failing condition.
1629 * return code should be FPCFGA_OK to display it.
1630 */
1631 case CFGA_STAT_NONE:
1632 /*
1633 * If not unconfigured and not attached
1634 * the state is set to CFGA_STAT_NONE currently.
1635 * This is okay for the detached node due to
1636 * the driver being unloaded.
1637 * May need to define another state to
1638 * isolate the detached only state.
1639 *
1640 * handle the same way as configured.
1641 */
1642 if (lap->ret != FPCFGA_ACCESS_OK) {
1643 cond = CFGA_COND_FAILING;
1644 }
1645 lap->chld_config = CFGA_STAT_CONFIGURED;
1646 break;
1647 case CFGA_STAT_UNCONFIGURED:
1648 /*
1649 * if unconfigured - offline or down,
1650 * set to cond to unusable regardless of accessibility.
1651 * This behavior needs to be examined further.
1652 * When the device is not accessible the node
1653 * may get offline or down. In that case failing
1654 * cond may make more sense.
1655 * In anycase the ostate will be set to configured
1656 * configured.
1657 */
1658 cond = CFGA_COND_UNUSABLE;
1659 /*
1660 * For fabric port the fca port is considered as
1661 * configured since user configured previously
1662 * for any existing node. Otherwise when the
1663 * device was accessible, the hba is considered as
1664 * configured.
1665 */
1666 if (((strcmp(lap->xport_type,
1667 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
1668 (strcmp(lap->xport_type,
1669 FP_FC_FABRIC_PORT_TYPE) == 0)) ||
1670 (lap->ret == FPCFGA_ACCESS_OK)) {
1671 lap->chld_config = CFGA_STAT_CONFIGURED;
1672 } else {
1673 lap->ret = FPCFGA_APID_NOEXIST;
1674 return (FPCFGA_OK);
1675 }
1676 break;
1677 default:
1678 break;
1679 }
1680
1681 /* if device found in disco ports, ldata already created. */
1682 if (lap->ret == FPCFGA_ACCESS_OK) {
1683 /*
1684 * if cond is not changed then don't update
1685 * condition to keep the previous condition.
1686 */
1687 if (cond != CFGA_COND_UNKNOWN) {
1688 lap->listp->ldata.ap_cond = cond;
1689 }
1690 lap->listp->ldata.ap_o_state = CFGA_STAT_CONFIGURED;
1691 lap->listp->ldata.ap_busy = busy;
1692 lap->ret = FPCFGA_OK;
1693 return (FPCFGA_OK);
1694 }
1695 }
1696
1697 /*
1698 * if cmd is stat all check ldata list
1699 * to see if the node exist on the dev list. Otherwise create
1700 * the list element.
1701 */
1702 if (lap->cmd == FPCFGA_STAT_ALL) {
1703 if (lap->listp != NULL) {
1704 if ((ret = make_dyncomp_from_dinode(node,
1705 &dyncomp, &l_errno)) != FPCFGA_OK) {
1706 return (ret);
1707 }
1708 ret = is_dyn_ap_on_ldata_list(dyncomp, lap->listp,
1709 &matchldp, &l_errno);
1710 switch (ret) {
1711 case FPCFGA_ACCESS_OK:
1712 /* node exists so set ostate to configured. */
1713 lap->chld_config = CFGA_STAT_CONFIGURED;
1714 matchldp->ldata.ap_o_state =
1715 CFGA_STAT_CONFIGURED;
1716 matchldp->ldata.ap_busy = busy;
1717 clp = &matchldp->ldata;
1718 switch (ostate) {
1719 case CFGA_STAT_CONFIGURED:
1720 /*
1721 * If not unconfigured and not attached
1722 * the state is set to CFGA_STAT_NONE currently.
1723 * This is okay for the detached node due to
1724 * the driver being unloaded.
1725 * May need to define another state to
1726 * isolate the detached only state.
1727 */
1728 case CFGA_STAT_NONE:
1729 /* update ap_type and ap_info */
1730 get_hw_info(node, clp);
1731 break;
1732 /*
1733 * node is offline or down.
1734 * set cond to unusable.
1735 */
1736 case CFGA_STAT_UNCONFIGURED:
1737 /*
1738 * if cond is not unknown
1739 * we already set the cond from
1740 * a different node with the same
1741 * port WWN or initial probing
1742 * was failed so don't update again.
1743 */
1744 if (matchldp->ldata.ap_cond ==
1745 CFGA_COND_UNKNOWN) {
1746 matchldp->ldata.ap_cond =
1747 CFGA_COND_UNUSABLE;
1748 }
1749 break;
1750 default:
1751 break;
1752 }
1753 /* node found in ldata list so just return. */
1754 lap->ret = FPCFGA_OK;
1755 S_FREE(dyncomp);
1756 return (FPCFGA_OK);
1757 case FPCFGA_LIB_ERR:
1758 lap->l_errno = l_errno;
1759 S_FREE(dyncomp);
1760 return (ret);
1761 case FPCFGA_APID_NOACCESS:
1762 switch (ostate) {
1763 /* node is attached but not in dev list */
1764 case CFGA_STAT_CONFIGURED:
1765 case CFGA_STAT_NONE:
1766 lap->chld_config = CFGA_STAT_CONFIGURED;
1767 cond = CFGA_COND_FAILING;
1768 break;
1769 /*
1770 * node is offline or down.
1771 * set cond to unusable.
1772 */
1773 case CFGA_STAT_UNCONFIGURED:
1774 /*
1775 * For fabric port the fca port is
1776 * considered as configured since user
1777 * configured previously for any
1778 * existing node.
1779 */
1780 cond = CFGA_COND_UNUSABLE;
1781 if ((strcmp(lap->xport_type,
1782 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
1783 (strcmp(lap->xport_type,
1784 FP_FC_FABRIC_PORT_TYPE) == 0)) {
1785 lap->chld_config =
1786 CFGA_STAT_CONFIGURED;
1787 } else {
1788 lap->ret = FPCFGA_OK;
1789 S_FREE(dyncomp);
1790 return (FPCFGA_OK);
1791 }
1792 break;
1793 default:
1794 /*
1795 * continue to create ldata_list struct for
1796 * this node
1797 */
1798 break;
1799 }
1800 default:
1801 break;
1802 }
1803 } else {
1804 /*
1805 * dev_list is null so there is no accessible dev.
1806 * set the cond and continue to create ldata.
1807 */
1808 switch (ostate) {
1809 case CFGA_STAT_CONFIGURED:
1810 case CFGA_STAT_NONE:
1811 cond = CFGA_COND_FAILING;
1812 lap->chld_config = CFGA_STAT_CONFIGURED;
1813 break;
1814 /*
1815 * node is offline or down.
1816 * set cond to unusable.
1817 */
1818 case CFGA_STAT_UNCONFIGURED:
1819 cond = CFGA_COND_UNUSABLE;
1820 /*
1821 * For fabric port the fca port is
1822 * considered as configured since user
1823 * configured previously for any
1824 * existing node.
1825 */
1826 if ((strcmp(lap->xport_type,
1827 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
1828 (strcmp(lap->xport_type,
1829 FP_FC_FABRIC_PORT_TYPE) == 0)) {
1830 lap->chld_config =
1831 CFGA_STAT_CONFIGURED;
1832 } else {
1833 lap->ret = FPCFGA_OK;
1834 S_FREE(dyncomp);
1835 return (FPCFGA_OK);
1836 }
1837 break;
1838 default:
1839 break;
1840 }
1841 }
1842 }
1843
1844 listp = calloc(1, sizeof (ldata_list_t));
1845 if (listp == NULL) {
1846 lap->l_errno = errno;
1847 S_FREE(dyncomp);
1848 return (FPCFGA_LIB_ERR);
1849 }
1850
1851 clp = &listp->ldata;
1852
1853 /* Create the dynamic component. */
1854 if (dyncomp == NULL) {
1855 ret = make_dyncomp_from_dinode(node, &dyncomp, &l_errno);
1856 if (ret != FPCFGA_OK) {
1857 S_FREE(listp);
1858 return (ret);
1859 }
1860 }
1861
1862 /* Create logical and physical ap_id */
1863 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
1864 lap->xport_logp, DYN_SEP, dyncomp);
1865
1866 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
1867 lap->apidp->xport_phys, DYN_SEP, dyncomp);
1868
1869 S_FREE(dyncomp);
1870
1871 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
1872 clp->ap_r_state = lap->xport_rstate;
1873 /* set to ostate to configured and set cond with info. */
1874 clp->ap_o_state = CFGA_STAT_CONFIGURED;
1875 clp->ap_cond = cond;
1876 clp->ap_busy = busy;
1877 clp->ap_status_time = (time_t)-1;
1878
1879 /* get ap_type and ap_info. */
1880 get_hw_info(node, clp);
1881
1882 /* Link it in */
1883 listp->next = lap->listp;
1884 lap->listp = listp;
1885
1886 lap->ret = FPCFGA_OK;
1887 return (FPCFGA_OK);
1888 }
1889
1890 /*
1891 * Wrapper routine for handling path info.
1892 *
1893 * When show_FCP_dev option is given stat_path_info_FCP_dev() is called.
1894 * Otherwise stat_path_info_fc_dev() is called.
1895 */
1896 int
stat_path_info_node(di_node_t root,void * arg,int * l_errnop)1897 stat_path_info_node(
1898 di_node_t root,
1899 void *arg,
1900 int *l_errnop)
1901 {
1902 fpcfga_list_t *lap = NULL;
1903
1904 lap = (fpcfga_list_t *)arg;
1905 if ((lap->apidp->flags & (FLAG_FCP_DEV)) == FLAG_FCP_DEV) {
1906 return (stat_path_info_FCP_dev(root, lap, l_errnop));
1907 } else {
1908 return (stat_path_info_fc_dev(root, lap, l_errnop));
1909 }
1910 }
1911
1912 /*
1913 * Routine for updating ldata list based on the state of path info node.
1914 * When no matching accessible ldata is found a new ldata is created
1915 * with proper state information.
1916 *
1917 * Overall algorithm:
1918 * If the path info node is not offline and the matching ldata is found
1919 * the target device is updated with configued and unknown condition.
1920 * If the path info node is offline or failed and the matching ldata is found
1921 * the target device is updated with configued and unusable condition.
1922 * If the path info node is online but the matching ldata is not found
1923 * the target device is created with configued and failing condition.
1924 * If the path info is offline or failed and the matching ldata is not found
1925 * the target device is created with configued and unusable condition.
1926 */
1927 static int
stat_path_info_fc_dev(di_node_t root,fpcfga_list_t * lap,int * l_errnop)1928 stat_path_info_fc_dev(
1929 di_node_t root,
1930 fpcfga_list_t *lap,
1931 int *l_errnop)
1932 {
1933 ldata_list_t *matchldp = NULL;
1934 di_path_t path = DI_PATH_NIL;
1935 uchar_t *port_wwn_data;
1936 char port_wwn[WWN_SIZE*2+1];
1937 int count;
1938 fpcfga_ret_t ret;
1939 di_path_state_t pstate;
1940
1941 if (root == DI_NODE_NIL) {
1942 return (FPCFGA_LIB_ERR);
1943 }
1944
1945 /*
1946 * if stat on a specific dev and walk_node found it okay
1947 * then just return ok.
1948 */
1949 if ((lap->cmd == FPCFGA_STAT_FC_DEV) && (lap->ret == FPCFGA_OK)) {
1950 return (FPCFGA_OK);
1951 }
1952
1953 /*
1954 * if stat on a fca xport and chld_config is set
1955 * then just return ok.
1956 */
1957 if ((lap->cmd == FPCFGA_STAT_FCA_PORT) &&
1958 (lap->chld_config == CFGA_STAT_CONFIGURED)) {
1959 return (FPCFGA_OK);
1960 }
1961
1962 /*
1963 * when there is no path_info node return FPCFGA_OK.
1964 * That way the result from walk_node shall be maintained.
1965 */
1966 if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) {
1967 /*
1968 * if the dev was in dev list but not found
1969 * return OK to indicate is not configured.
1970 */
1971 if (lap->ret == FPCFGA_ACCESS_OK) {
1972 lap->ret = FPCFGA_OK;
1973 }
1974 return (FPCFGA_OK);
1975 }
1976
1977 /* if stat on fca port return. */
1978 if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
1979 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
1980 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
1981 lap->chld_config = CFGA_STAT_CONFIGURED;
1982 return (FPCFGA_OK);
1983 } else {
1984 if ((pstate = di_path_state(path)) !=
1985 DI_PATH_STATE_OFFLINE) {
1986 lap->chld_config = CFGA_STAT_CONFIGURED;
1987 return (FPCFGA_OK);
1988 }
1989 }
1990 }
1991 /*
1992 * now parse the path info node.
1993 */
1994 do {
1995 count = di_path_prop_lookup_bytes(path, PORT_WWN_PROP,
1996 &port_wwn_data);
1997 if (count != WWN_SIZE) {
1998 ret = FPCFGA_LIB_ERR;
1999 break;
2000 }
2001
2002 (void) sprintf(port_wwn, "%016llx",
2003 (wwnConversion(port_wwn_data)));
2004 switch (lap->cmd) {
2005 case FPCFGA_STAT_FC_DEV:
2006 /* if no match contine to the next path info node. */
2007 if (strncmp(port_wwn, lap->apidp->dyncomp,
2008 WWN_SIZE*2)) {
2009 break;
2010 }
2011 /* if device in dev_list, ldata already created. */
2012 if (lap->ret == FPCFGA_ACCESS_OK) {
2013 lap->listp->ldata.ap_o_state =
2014 CFGA_STAT_CONFIGURED;
2015 if (((pstate = di_path_state(path)) ==
2016 DI_PATH_STATE_OFFLINE) ||
2017 (pstate == DI_PATH_STATE_FAULT)) {
2018 lap->listp->ldata.ap_cond =
2019 CFGA_COND_UNUSABLE;
2020 }
2021 lap->ret = FPCFGA_OK;
2022 return (FPCFGA_OK);
2023 } else {
2024 if ((strcmp(lap->xport_type,
2025 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2026 (strcmp(lap->xport_type,
2027 FP_FC_FABRIC_PORT_TYPE) == 0)) {
2028 lap->chld_config = CFGA_STAT_CONFIGURED;
2029 return (init_ldata_for_mpath_dev(
2030 path, port_wwn, l_errnop, lap));
2031 } else {
2032 if ((di_path_state(path)) !=
2033 DI_PATH_STATE_OFFLINE) {
2034 return (init_ldata_for_mpath_dev(
2035 path, port_wwn, l_errnop, lap));
2036 } else {
2037 lap->ret = FPCFGA_APID_NOEXIST;
2038 return (FPCFGA_OK);
2039 }
2040 }
2041 }
2042 case FPCFGA_STAT_ALL:
2043 /* check if there is list data. */
2044 if (lap->listp != NULL) {
2045 ret = is_dyn_ap_on_ldata_list(port_wwn,
2046 lap->listp, &matchldp, l_errnop);
2047 if (ret == FPCFGA_ACCESS_OK) {
2048 lap->chld_config = CFGA_STAT_CONFIGURED;
2049 matchldp->ldata.ap_o_state =
2050 CFGA_STAT_CONFIGURED;
2051 /*
2052 * Update the condition as unusable
2053 * if the pathinfo state is failed
2054 * or offline.
2055 */
2056 if (((pstate = di_path_state(path)) ==
2057 DI_PATH_STATE_OFFLINE) ||
2058 (pstate ==
2059 DI_PATH_STATE_FAULT)) {
2060 matchldp->ldata.ap_cond =
2061 CFGA_COND_UNUSABLE;
2062 }
2063 break;
2064 } else if (ret == FPCFGA_LIB_ERR) {
2065 lap->l_errno = *l_errnop;
2066 return (ret);
2067 }
2068 }
2069 /*
2070 * now create ldata for this particular path info node.
2071 * if port top is private loop and pathinfo is in
2072 * in offline state don't include to ldata list.
2073 */
2074 if (((strcmp(lap->xport_type,
2075 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2076 (strcmp(lap->xport_type,
2077 FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2078 (di_path_state(path) !=
2079 DI_PATH_STATE_OFFLINE)) {
2080 lap->chld_config = CFGA_STAT_CONFIGURED;
2081 ret = init_ldata_for_mpath_dev(
2082 path, port_wwn, l_errnop, lap);
2083 if (ret != FPCFGA_OK) {
2084 return (ret);
2085 }
2086 }
2087 break;
2088 case FPCFGA_STAT_FCA_PORT:
2089 if (di_path_state(path) != DI_PATH_STATE_OFFLINE) {
2090 lap->chld_config = CFGA_STAT_CONFIGURED;
2091 return (FPCFGA_OK);
2092 }
2093 }
2094 path = di_path_next_client(root, path);
2095 } while (path != DI_PATH_NIL);
2096
2097 return (FPCFGA_OK);
2098
2099 }
2100
2101 /*
2102 * Routine for updating ldata list based on the state of path info node.
2103 * When no matching accessible ldata is found a new ldata is created
2104 * with proper state information.
2105 *
2106 * The difference from stat_path_info_fc_dev() is
2107 * to handle FCP SCSI LUN information. Otherwise overall algorithm is
2108 * same.
2109 *
2110 * Overall algorithm:
2111 * If the path info node is not offline and the matching ldata is found
2112 * the target device is updated with configued and unknown condition.
2113 * If the path info node is offline or failed and the matching ldata is found
2114 * the target device is updated with configued and unusable condition.
2115 * If the path info node is online but the matching ldata is not found
2116 * the target device is created with configued and failing condition.
2117 * If the path info is offline or failed and the matching ldata is not found
2118 * the target device is created with configued and unusable condition.
2119 */
2120 static int
stat_path_info_FCP_dev(di_node_t root,fpcfga_list_t * lap,int * l_errnop)2121 stat_path_info_FCP_dev(
2122 di_node_t root,
2123 fpcfga_list_t *lap,
2124 int *l_errnop)
2125 {
2126 ldata_list_t *matchldp = NULL, *listp = NULL;
2127 cfga_list_data_t *clp;
2128 di_path_t path = DI_PATH_NIL;
2129 di_node_t client_node = DI_NODE_NIL;
2130 char *port_wwn = NULL, *nodepath = NULL;
2131 int *lun_nump;
2132 fpcfga_ret_t ldata_ret;
2133 di_path_state_t pstate;
2134 cfga_busy_t busy;
2135 uint_t dctl_state = 0;
2136
2137 if (root == DI_NODE_NIL) {
2138 return (FPCFGA_LIB_ERR);
2139 }
2140
2141 /*
2142 * if stat on a fca xport and chld_config is set
2143 * then just return ok.
2144 */
2145 if ((lap->cmd == FPCFGA_STAT_FCA_PORT) &&
2146 (lap->chld_config == CFGA_STAT_CONFIGURED)) {
2147 return (FPCFGA_OK);
2148 }
2149 /*
2150 * when there is no path_info node return FPCFGA_OK.
2151 * That way the result from walk_node shall be maintained.
2152 */
2153 if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) {
2154 /*
2155 * if the dev was in dev list but not found
2156 * return ok.
2157 */
2158 if (lap->ret == FPCFGA_ACCESS_OK) {
2159 lap->ret = FPCFGA_OK;
2160 }
2161 return (FPCFGA_OK);
2162 }
2163 /*
2164 * If stat on fca port and port topology is fabric return here.
2165 * If not fabric return only when path state is not offfline.
2166 * The other cases are handbled below.
2167 */
2168 if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
2169 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
2170 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
2171 lap->chld_config = CFGA_STAT_CONFIGURED;
2172 return (FPCFGA_OK);
2173 } else {
2174 if ((pstate = di_path_state(path)) !=
2175 DI_PATH_STATE_OFFLINE) {
2176 lap->chld_config = CFGA_STAT_CONFIGURED;
2177 return (FPCFGA_OK);
2178 }
2179 }
2180 }
2181 /*
2182 * now parse the path info node.
2183 */
2184 do {
2185 switch (lap->cmd) {
2186 case FPCFGA_STAT_FC_DEV:
2187 if ((make_portwwn_luncomp_from_pinode(path, &port_wwn,
2188 &lun_nump, l_errnop)) != FPCFGA_OK) {
2189 return (FPCFGA_LIB_ERR);
2190 }
2191
2192 if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn,
2193 *lun_nump, lap->listp, &matchldp))
2194 == FPCFGA_LIB_ERR) {
2195 S_FREE(port_wwn);
2196 return (ldata_ret);
2197 }
2198
2199 if (ldata_ret == FPCFGA_ACCESS_OK) {
2200 lap->chld_config = CFGA_STAT_CONFIGURED;
2201 matchldp->ldata.ap_o_state =
2202 CFGA_STAT_CONFIGURED;
2203 /*
2204 * Update the condition as unusable
2205 * if the pathinfo state is failed
2206 * or offline.
2207 */
2208 if (((pstate = di_path_state(path)) ==
2209 DI_PATH_STATE_OFFLINE) ||
2210 (pstate == DI_PATH_STATE_FAULT)) {
2211 matchldp->ldata.ap_cond =
2212 CFGA_COND_UNUSABLE;
2213 }
2214 lap->ret = FPCFGA_OK;
2215 break;
2216 }
2217
2218 if (strncmp(port_wwn, lap->apidp->dyncomp, WWN_SIZE*2)
2219 != 0) {
2220 break;
2221 }
2222 /*
2223 * now create ldata for this particular path info node.
2224 * if port top is private loop and pathinfo is in
2225 * in offline state don't include to ldata list.
2226 */
2227 if (((strcmp(lap->xport_type,
2228 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2229 (strcmp(lap->xport_type,
2230 FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2231 (di_path_state(path) !=
2232 DI_PATH_STATE_OFFLINE)) {
2233 lap->chld_config = CFGA_STAT_CONFIGURED;
2234 /* create ldata for this pi node. */
2235 client_node = di_path_client_node(path);
2236 if (client_node == DI_NODE_NIL) {
2237 *l_errnop = errno;
2238 S_FREE(port_wwn);
2239 return (FPCFGA_LIB_ERR);
2240 }
2241 if ((construct_nodepath_from_dinode(
2242 client_node, &nodepath, l_errnop))
2243 != FPCFGA_OK) {
2244 S_FREE(port_wwn);
2245 return (FPCFGA_LIB_ERR);
2246 }
2247
2248 listp = calloc(1, sizeof (ldata_list_t));
2249 if (listp == NULL) {
2250 S_FREE(port_wwn);
2251 S_FREE(nodepath);
2252 lap->l_errno = errno;
2253 return (FPCFGA_LIB_ERR);
2254 }
2255
2256 clp = &listp->ldata;
2257
2258 /* Create logical and physical ap_id */
2259 (void) snprintf(clp->ap_log_id,
2260 sizeof (clp->ap_log_id), "%s%s%s%s%d",
2261 lap->xport_logp, DYN_SEP, port_wwn,
2262 LUN_COMP_SEP, *lun_nump);
2263 (void) snprintf(clp->ap_phys_id,
2264 sizeof (clp->ap_phys_id), "%s%s%s%s%d",
2265 lap->apidp->xport_phys, DYN_SEP, port_wwn,
2266 LUN_COMP_SEP, *lun_nump);
2267 /*
2268 * We reached here since FCP dev is not found
2269 * in ldata list but path info node exists.
2270 *
2271 * Update the condition as failing
2272 * if the pathinfo state was normal.
2273 * Update the condition as unusable
2274 * if the pathinfo state is failed
2275 * or offline.
2276 */
2277 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
2278 clp->ap_o_state = CFGA_STAT_CONFIGURED;
2279 if (((pstate = di_path_state(path))
2280 == DI_PATH_STATE_OFFLINE) ||
2281 (pstate == DI_PATH_STATE_FAULT)) {
2282 clp->ap_cond = CFGA_COND_UNUSABLE;
2283 } else {
2284 clp->ap_cond = CFGA_COND_FAILING;
2285 }
2286 clp->ap_r_state = lap->xport_rstate;
2287 clp->ap_info[0] = '\0';
2288 /* update ap_type and ap_info */
2289 get_hw_info(client_node, clp);
2290 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE,
2291 &dctl_state, l_errnop) == FPCFGA_OK) {
2292 busy = ((dctl_state & DEVICE_BUSY)
2293 == DEVICE_BUSY) ? 1 : 0;
2294 } else {
2295 busy = 0;
2296 }
2297 clp->ap_busy = busy;
2298 clp->ap_status_time = (time_t)-1;
2299
2300 (void) insert_ldata_to_ldatalist(port_wwn,
2301 lun_nump, listp, &(lap->listp));
2302 }
2303 break;
2304 case FPCFGA_STAT_ALL:
2305 if ((make_portwwn_luncomp_from_pinode(path, &port_wwn,
2306 &lun_nump, l_errnop)) != FPCFGA_OK) {
2307 return (FPCFGA_LIB_ERR);
2308 }
2309
2310 if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn,
2311 *lun_nump, lap->listp, &matchldp))
2312 == FPCFGA_LIB_ERR) {
2313 S_FREE(port_wwn);
2314 return (ldata_ret);
2315 }
2316
2317 if (ldata_ret == FPCFGA_ACCESS_OK) {
2318 lap->chld_config = CFGA_STAT_CONFIGURED;
2319 matchldp->ldata.ap_o_state =
2320 CFGA_STAT_CONFIGURED;
2321 /*
2322 * Update the condition as unusable
2323 * if the pathinfo state is failed
2324 * or offline.
2325 */
2326 if (((pstate = di_path_state(path)) ==
2327 DI_PATH_STATE_OFFLINE) ||
2328 (pstate == DI_PATH_STATE_FAULT)) {
2329 matchldp->ldata.ap_cond =
2330 CFGA_COND_UNUSABLE;
2331 }
2332 break;
2333 }
2334 /*
2335 * now create ldata for this particular path info node.
2336 * if port top is private loop and pathinfo is in
2337 * in offline state don't include to ldata list.
2338 */
2339 if (((strcmp(lap->xport_type,
2340 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2341 (strcmp(lap->xport_type,
2342 FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2343 (di_path_state(path) !=
2344 DI_PATH_STATE_OFFLINE)) {
2345 lap->chld_config = CFGA_STAT_CONFIGURED;
2346 /* create ldata for this pi node. */
2347 client_node = di_path_client_node(path);
2348 if (client_node == DI_NODE_NIL) {
2349 *l_errnop = errno;
2350 S_FREE(port_wwn);
2351 return (FPCFGA_LIB_ERR);
2352 }
2353 if ((construct_nodepath_from_dinode(
2354 client_node, &nodepath, l_errnop))
2355 != FPCFGA_OK) {
2356 S_FREE(port_wwn);
2357 return (FPCFGA_LIB_ERR);
2358 }
2359
2360 listp = calloc(1, sizeof (ldata_list_t));
2361 if (listp == NULL) {
2362 S_FREE(port_wwn);
2363 S_FREE(nodepath);
2364 lap->l_errno = errno;
2365 return (FPCFGA_LIB_ERR);
2366 }
2367
2368 clp = &listp->ldata;
2369
2370 /* Create logical and physical ap_id */
2371 (void) snprintf(clp->ap_log_id,
2372 sizeof (clp->ap_log_id), "%s%s%s%s%d",
2373 lap->xport_logp, DYN_SEP, port_wwn,
2374 LUN_COMP_SEP, *lun_nump);
2375 (void) snprintf(clp->ap_phys_id,
2376 sizeof (clp->ap_phys_id), "%s%s%s%s%d",
2377 lap->apidp->xport_phys, DYN_SEP, port_wwn,
2378 LUN_COMP_SEP, *lun_nump);
2379 /*
2380 * We reached here since FCP dev is not found
2381 * in ldata list but path info node exists.
2382 *
2383 * Update the condition as failing
2384 * if the pathinfo state was normal.
2385 * Update the condition as unusable
2386 * if the pathinfo state is failed
2387 * or offline.
2388 */
2389 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
2390 clp->ap_o_state = CFGA_STAT_CONFIGURED;
2391 if (((pstate = di_path_state(path))
2392 == DI_PATH_STATE_OFFLINE) ||
2393 (pstate == DI_PATH_STATE_FAULT)) {
2394 clp->ap_cond = CFGA_COND_UNUSABLE;
2395 } else {
2396 clp->ap_cond = CFGA_COND_FAILING;
2397 }
2398 clp->ap_r_state = lap->xport_rstate;
2399 clp->ap_info[0] = '\0';
2400 /* update ap_type and ap_info */
2401 get_hw_info(client_node, clp);
2402 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE,
2403 &dctl_state, l_errnop) == FPCFGA_OK) {
2404 busy = ((dctl_state & DEVICE_BUSY)
2405 == DEVICE_BUSY) ? 1 : 0;
2406 } else {
2407 busy = 0;
2408 }
2409 clp->ap_busy = busy;
2410 clp->ap_status_time = (time_t)-1;
2411
2412 (void) insert_ldata_to_ldatalist(port_wwn,
2413 lun_nump, listp, &(lap->listp));
2414 }
2415 break;
2416 case FPCFGA_STAT_FCA_PORT:
2417 if (di_path_state(path) != DI_PATH_STATE_OFFLINE) {
2418 lap->chld_config = CFGA_STAT_CONFIGURED;
2419 lap->ret = FPCFGA_OK;
2420 return (FPCFGA_OK);
2421 }
2422 }
2423 path = di_path_next_client(root, path);
2424 } while (path != DI_PATH_NIL);
2425
2426 lap->ret = FPCFGA_OK;
2427 S_FREE(port_wwn);
2428 S_FREE(nodepath);
2429 return (FPCFGA_OK);
2430
2431 }
2432
2433 /*
2434 * Routine for updating ldata list based on the state of device node.
2435 * When no matching accessible ldata is found a new ldata is created
2436 * with proper state information.
2437 *
2438 * The difference from do_stat_fc_dev() is
2439 * to handle FCP SCSI LUN information. Otherwise overall algorithm is
2440 * same.
2441 *
2442 * Overall algorithm:
2443 * If the device node is online and the matching ldata is found
2444 * the target device is updated with configued and unknown condition.
2445 * If the device node is offline or down and the matching ldata is found
2446 * the target device is updated with configued and unusable condition.
2447 * If the device node is online but the matching ldata is not found
2448 * the target device is created with configued and failing condition.
2449 * If the device node is offline or down and the matching ldata is not found
2450 * the target device is created with configued and unusable condition.
2451 */
2452 static fpcfga_ret_t
do_stat_FCP_dev(const di_node_t node,const char * nodepath,fpcfga_list_t * lap,int limited_stat)2453 do_stat_FCP_dev(
2454 const di_node_t node,
2455 const char *nodepath,
2456 fpcfga_list_t *lap,
2457 int limited_stat)
2458 {
2459 uint_t dctl_state = 0, devinfo_state = 0;
2460 char *port_wwn = NULL;
2461 cfga_list_data_t *clp = NULL;
2462 cfga_busy_t busy;
2463 ldata_list_t *listp = NULL;
2464 ldata_list_t *matchldp = NULL;
2465 int l_errno = 0, *lun_nump;
2466 cfga_stat_t ostate;
2467 cfga_cond_t cond;
2468 fpcfga_ret_t ldata_ret;
2469
2470 assert(lap->apidp->xport_phys != NULL);
2471 assert(lap->xport_logp != NULL);
2472
2473 cond = CFGA_COND_UNKNOWN;
2474
2475 devinfo_state = di_state(node);
2476 ostate = dev_devinfo_to_occupant_state(devinfo_state);
2477
2478 /*
2479 * NOTE: The devctl framework cannot currently detect layered driver
2480 * opens, so the busy indicator is not very reliable. Also,
2481 * non-root users will not be able to determine busy
2482 * status (libdevice needs root permissions).
2483 * This should probably be fixed by adding a DI_BUSY to the di_state()
2484 * routine in libdevinfo.
2485 */
2486 if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state,
2487 &l_errno) == FPCFGA_OK) {
2488 busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
2489 } else {
2490 busy = 0;
2491 }
2492
2493 /* We only want to know device config state */
2494 if (limited_stat) {
2495 if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
2496 strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
2497 lap->chld_config = CFGA_STAT_CONFIGURED;
2498 } else {
2499 if (ostate != CFGA_STAT_UNCONFIGURED) {
2500 lap->chld_config = CFGA_STAT_CONFIGURED;
2501 }
2502 }
2503 return (FPCFGA_OK);
2504 }
2505
2506 /*
2507 * If child device is configured, see if it is accessible also
2508 * for FPCFGA_STAT_FC_DEV cmd.
2509 */
2510 if ((make_portwwn_luncomp_from_dinode(node, &port_wwn, &lun_nump,
2511 &l_errno)) != FPCFGA_OK) {
2512 lap->l_errno = l_errno;
2513 return (FPCFGA_LIB_ERR);
2514 }
2515
2516 if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn, *lun_nump,
2517 lap->listp, &matchldp)) == FPCFGA_LIB_ERR) {
2518 lap->l_errno = l_errno;
2519 S_FREE(port_wwn);
2520 return (ldata_ret);
2521 }
2522
2523 if (lap->cmd == FPCFGA_STAT_FC_DEV) {
2524 switch (ostate) {
2525 case CFGA_STAT_CONFIGURED:
2526 /*
2527 * if configured and not accessble, the device is
2528 * till be displayed with failing condition.
2529 * return code should be FPCFGA_OK to display it.
2530 */
2531 case CFGA_STAT_NONE:
2532 /*
2533 * If not unconfigured and not attached
2534 * the state is set to CFGA_STAT_NONE currently.
2535 * This is okay for the detached node due to
2536 * the driver being unloaded.
2537 * May need to define another state to
2538 * isolate the detached only state.
2539 *
2540 * handle the same way as configured.
2541 */
2542 if (ldata_ret != FPCFGA_ACCESS_OK) {
2543 cond = CFGA_COND_FAILING;
2544 }
2545 lap->chld_config = CFGA_STAT_CONFIGURED;
2546 break;
2547 case CFGA_STAT_UNCONFIGURED:
2548 /*
2549 * if unconfigured - offline or down,
2550 * set to cond to unusable regardless of accessibility.
2551 * This behavior needs to be examined further.
2552 * When the device is not accessible the node
2553 * may get offline or down. In that case failing
2554 * cond may make more sense.
2555 * In anycase the ostate will be set to configured
2556 * configured.
2557 */
2558 cond = CFGA_COND_UNUSABLE;
2559 /*
2560 * For fabric port the fca port is considered as
2561 * configured since user configured previously
2562 * for any existing node. Otherwise when the
2563 * device was accessible, the hba is considered as
2564 * configured.
2565 */
2566 if (((strcmp(lap->xport_type,
2567 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2568 (strcmp(lap->xport_type,
2569 FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2570 (lap->ret == FPCFGA_ACCESS_OK)) {
2571 lap->chld_config = CFGA_STAT_CONFIGURED;
2572 } else {
2573 /*
2574 * if lap->ret is okay there is at least
2575 * one matching ldata exist. Need to keep
2576 * okay ret to display the matching ones.
2577 */
2578 if (lap->ret != FPCFGA_OK) {
2579 lap->ret = FPCFGA_APID_NOEXIST;
2580 }
2581 S_FREE(port_wwn);
2582 return (FPCFGA_OK);
2583 }
2584 break;
2585 default:
2586 break;
2587 }
2588
2589 /* if device found in dev_list, ldata already created. */
2590 if (ldata_ret == FPCFGA_ACCESS_OK) {
2591 /*
2592 * if cond is not changed then don't update
2593 * condition to keep any condtion
2594 * from initial discovery. If the initial
2595 * cond was failed the same condition will be kept.
2596 */
2597 if (cond != CFGA_COND_UNKNOWN) {
2598 matchldp->ldata.ap_cond = cond;
2599 }
2600 matchldp->ldata.ap_o_state = CFGA_STAT_CONFIGURED;
2601 matchldp->ldata.ap_busy = busy;
2602 /* update ap_info via inquiry */
2603 clp = &matchldp->ldata;
2604 /* update ap_type and ap_info */
2605 get_hw_info(node, clp);
2606 lap->ret = FPCFGA_OK;
2607 S_FREE(port_wwn);
2608 return (FPCFGA_OK);
2609 }
2610 }
2611
2612 /*
2613 * if cmd is stat all check ldata list
2614 * to see if the node exist on the dev list. Otherwise create
2615 * the list element.
2616 */
2617 if (lap->cmd == FPCFGA_STAT_ALL) {
2618 switch (ldata_ret) {
2619 case FPCFGA_ACCESS_OK:
2620 /* node exists so set ostate to configured. */
2621 lap->chld_config = CFGA_STAT_CONFIGURED;
2622 matchldp->ldata.ap_o_state =
2623 CFGA_STAT_CONFIGURED;
2624 matchldp->ldata.ap_busy = busy;
2625 clp = &matchldp->ldata;
2626 switch (ostate) {
2627 case CFGA_STAT_CONFIGURED:
2628 /*
2629 * If not unconfigured and not attached
2630 * the state is set to CFGA_STAT_NONE currently.
2631 * This is okay for the detached node due to
2632 * the driver being unloaded.
2633 * May need to define another state to
2634 * isolate the detached only state.
2635 */
2636 case CFGA_STAT_NONE:
2637 /* update ap_type and ap_info */
2638 get_hw_info(node, clp);
2639 break;
2640 /*
2641 * node is offline or down.
2642 * set cond to unusable.
2643 */
2644 case CFGA_STAT_UNCONFIGURED:
2645 /*
2646 * if cond is not unknown
2647 * initial probing was failed
2648 * so don't update again.
2649 */
2650 if (matchldp->ldata.ap_cond ==
2651 CFGA_COND_UNKNOWN) {
2652 matchldp->ldata.ap_cond =
2653 CFGA_COND_UNUSABLE;
2654 }
2655 break;
2656 default:
2657 break;
2658 }
2659 /* node found in ldata list so just return. */
2660 lap->ret = FPCFGA_OK;
2661 S_FREE(port_wwn);
2662 return (FPCFGA_OK);
2663 case FPCFGA_APID_NOACCESS:
2664 switch (ostate) {
2665 /* node is attached but not in dev list */
2666 case CFGA_STAT_CONFIGURED:
2667 case CFGA_STAT_NONE:
2668 lap->chld_config = CFGA_STAT_CONFIGURED;
2669 cond = CFGA_COND_FAILING;
2670 break;
2671 /*
2672 * node is offline or down.
2673 * set cond to unusable.
2674 */
2675 case CFGA_STAT_UNCONFIGURED:
2676 /*
2677 * For fabric port the fca port is
2678 * considered as configured since user
2679 * configured previously for any
2680 * existing node.
2681 */
2682 cond = CFGA_COND_UNUSABLE;
2683 if ((strcmp(lap->xport_type,
2684 FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2685 (strcmp(lap->xport_type,
2686 FP_FC_FABRIC_PORT_TYPE) == 0)) {
2687 lap->chld_config =
2688 CFGA_STAT_CONFIGURED;
2689 } else {
2690 lap->ret = FPCFGA_OK;
2691 S_FREE(port_wwn);
2692 return (FPCFGA_OK);
2693 }
2694 break;
2695 default:
2696 /*
2697 * continue to create ldata_list struct for
2698 * this node
2699 */
2700 break;
2701 }
2702 default:
2703 break;
2704 }
2705 }
2706
2707 listp = calloc(1, sizeof (ldata_list_t));
2708 if (listp == NULL) {
2709 lap->l_errno = errno;
2710 S_FREE(port_wwn);
2711 return (FPCFGA_LIB_ERR);
2712 }
2713
2714 clp = &listp->ldata;
2715
2716 /* Create logical and physical ap_id */
2717 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id),
2718 "%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn,
2719 LUN_COMP_SEP, *lun_nump);
2720 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id),
2721 "%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn,
2722 LUN_COMP_SEP, *lun_nump);
2723 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
2724 clp->ap_r_state = lap->xport_rstate;
2725 clp->ap_o_state = CFGA_STAT_CONFIGURED;
2726 clp->ap_cond = cond;
2727 clp->ap_busy = busy;
2728 clp->ap_status_time = (time_t)-1;
2729 clp->ap_info[0] = '\0';
2730
2731 get_hw_info(node, clp);
2732
2733 (void) insert_ldata_to_ldatalist(port_wwn, lun_nump, listp,
2734 &(lap->listp));
2735
2736 lap->ret = FPCFGA_OK;
2737 S_FREE(port_wwn);
2738 return (FPCFGA_OK);
2739 }
2740
2741 /*
2742 * Searches the ldata_list to find if the the input port_wwn exist.
2743 *
2744 * Input: port_wwn, ldata_list.
2745 * Return value: FPCFGA_APID_NOACCESS if not found on ldata_list.
2746 * FPCFGA_ACCESS_OK if found on ldata_list.
2747 */
2748 static fpcfga_ret_t
is_dyn_ap_on_ldata_list(const char * port_wwn,const ldata_list_t * listp,ldata_list_t ** matchldpp,int * l_errnop)2749 is_dyn_ap_on_ldata_list(const char *port_wwn, const ldata_list_t *listp,
2750 ldata_list_t **matchldpp, int *l_errnop)
2751 {
2752 char *dyn = NULL, *dyncomp = NULL;
2753 int len;
2754 ldata_list_t *tmplp;
2755 fpcfga_ret_t ret;
2756
2757
2758 ret = FPCFGA_APID_NOACCESS;
2759
2760 tmplp = (ldata_list_t *)listp;
2761 while (tmplp != NULL) {
2762 if ((dyn = GET_DYN(tmplp->ldata.ap_phys_id)) != NULL) {
2763 len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
2764 dyncomp = calloc(1, len);
2765 if (dyncomp == NULL) {
2766 *l_errnop = errno;
2767 ret = FPCFGA_LIB_ERR;
2768 break;
2769 }
2770 (void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
2771 if (!(strncmp(port_wwn, dyncomp, WWN_SIZE*2))) {
2772 *matchldpp = tmplp;
2773 S_FREE(dyncomp);
2774 ret = FPCFGA_ACCESS_OK;
2775 break;
2776 }
2777 S_FREE(dyncomp);
2778 }
2779 tmplp = tmplp->next;
2780 }
2781
2782 return (ret);
2783 }
2784
2785 /*
2786 * Searches the ldata_list to find if the the input port_wwn and lun exist.
2787 *
2788 * Input: port_wwn, ldata_list.
2789 * Return value: FPCFGA_APID_NOACCESS if not found on ldata_list.
2790 * FPCFGA_ACCESS_OK if found on ldata_list.
2791 */
2792 static fpcfga_ret_t
is_FCP_dev_ap_on_ldata_list(const char * port_wwn,const int lun_num,ldata_list_t * ldatap,ldata_list_t ** matchldpp)2793 is_FCP_dev_ap_on_ldata_list(const char *port_wwn, const int lun_num,
2794 ldata_list_t *ldatap,
2795 ldata_list_t **matchldpp)
2796 {
2797 ldata_list_t *curlp = NULL;
2798 char *dyn = NULL, *dyncomp = NULL;
2799 char *lun_dyn = NULL, *lunp = NULL;
2800 int ldata_lun;
2801 fpcfga_ret_t ret;
2802
2803 /*
2804 * if there is no list data just return the FCP dev list.
2805 * Normally this should not occur since list data should
2806 * be created through discoveredPort list.
2807 */
2808 ret = FPCFGA_APID_NOACCESS;
2809 if (ldatap == NULL) {
2810 return (ret);
2811 }
2812
2813 dyn = GET_DYN(ldatap->ldata.ap_phys_id);
2814 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
2815 if ((dyncomp != NULL) &&
2816 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
2817 lun_dyn = GET_LUN_DYN(dyncomp);
2818 if (lun_dyn != NULL) {
2819 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
2820 if ((ldata_lun = atoi(lunp)) == lun_num) {
2821 *matchldpp = ldatap;
2822 return (FPCFGA_ACCESS_OK);
2823 } else if (ldata_lun > lun_num) {
2824 return (ret);
2825 }
2826 /* else continue */
2827 } else {
2828 /* we have match without lun comp. */
2829 *matchldpp = ldatap;
2830 return (FPCFGA_ACCESS_OK);
2831 }
2832 }
2833
2834 curlp = ldatap->next;
2835
2836 dyn = dyncomp = NULL;
2837 lun_dyn = lunp = NULL;
2838 while (curlp != NULL) {
2839 dyn = GET_DYN(curlp->ldata.ap_phys_id);
2840 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
2841 if ((dyncomp != NULL) &&
2842 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
2843 lun_dyn = GET_LUN_DYN(dyncomp);
2844 if (lun_dyn != NULL) {
2845 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
2846 if ((ldata_lun = atoi(lunp)) == lun_num) {
2847 *matchldpp = curlp;
2848 return (FPCFGA_ACCESS_OK);
2849 } else if (ldata_lun > lun_num) {
2850 return (ret);
2851 }
2852 /* else continue */
2853 } else {
2854 /* we have match without lun comp. */
2855 *matchldpp = curlp;
2856 return (FPCFGA_ACCESS_OK);
2857 }
2858 }
2859 dyn = dyncomp = NULL;
2860 lun_dyn = lunp = NULL;
2861 curlp = curlp->next;
2862 }
2863
2864 return (ret);
2865
2866 }
2867
2868 /*
2869 * This routine is called when a pathinfo without matching pwwn in dev_list
2870 * is found.
2871 */
2872 static fpcfga_ret_t
init_ldata_for_mpath_dev(di_path_t path,char * pwwn,int * l_errnop,fpcfga_list_t * lap)2873 init_ldata_for_mpath_dev(di_path_t path, char *pwwn, int *l_errnop,
2874 fpcfga_list_t *lap)
2875 {
2876 ldata_list_t *listp = NULL;
2877 cfga_list_data_t *clp = NULL;
2878 size_t devlen;
2879 char *devpath;
2880 di_node_t client_node = DI_NODE_NIL;
2881 uint_t dctl_state = 0;
2882 cfga_busy_t busy;
2883 char *client_path;
2884 di_path_state_t pstate;
2885
2886 /* get the client node path */
2887 if (path == DI_PATH_NIL) {
2888 return (FPCFGA_LIB_ERR);
2889 }
2890 client_node = di_path_client_node(path);
2891 if (client_node == DI_NODE_NIL) {
2892 return (FPCFGA_LIB_ERR);
2893 }
2894 if ((client_path = di_devfs_path(client_node)) == NULL) {
2895 return (FPCFGA_LIB_ERR);
2896 }
2897 devlen = strlen(DEVICES_DIR) + strlen(client_path) + 1;
2898 devpath = calloc(1, devlen);
2899 if (devpath == NULL) {
2900 di_devfs_path_free(client_path);
2901 *l_errnop = errno;
2902 return (FPCFGA_LIB_ERR);
2903 }
2904 (void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, client_path);
2905
2906 /* now need to create ldata for this dev */
2907 listp = calloc(1, sizeof (ldata_list_t));
2908 if (listp == NULL) {
2909 di_devfs_path_free(client_path);
2910 S_FREE(devpath);
2911 *l_errnop = errno;
2912 return (FPCFGA_LIB_ERR);
2913 }
2914
2915 clp = &listp->ldata;
2916
2917 /* Create logical and physical ap_id */
2918 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
2919 lap->xport_logp, DYN_SEP, pwwn);
2920 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
2921 lap->apidp->xport_phys, DYN_SEP, pwwn);
2922
2923 /* Filled in by libcfgadm */
2924 clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
2925 clp->ap_r_state = lap->xport_rstate;
2926 /* set to ostate to configured. */
2927 clp->ap_o_state = CFGA_STAT_CONFIGURED;
2928 /*
2929 * This routine is called when a port WWN is not found in dev list
2930 * but path info node exists.
2931 *
2932 * Update the condition as failing if the pathinfo state was normal.
2933 * Update the condition as unusable if the pathinfo state is failed
2934 * or offline.
2935 */
2936 if (((pstate = di_path_state(path)) == DI_PATH_STATE_OFFLINE) ||
2937 (pstate == DI_PATH_STATE_FAULT)) {
2938 clp->ap_cond = CFGA_COND_UNUSABLE;
2939 } else {
2940 clp->ap_cond = CFGA_COND_FAILING;
2941 }
2942 clp->ap_status_time = (time_t)-1;
2943 /* update ap_type and ap_info */
2944 get_hw_info(client_node, clp);
2945
2946 if (devctl_cmd(devpath, FPCFGA_DEV_GETSTATE,
2947 &dctl_state, l_errnop) == FPCFGA_OK) {
2948 busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
2949 } else {
2950 busy = 0;
2951 }
2952 clp->ap_busy = busy;
2953 /* Link it in */
2954 listp->next = lap->listp;
2955 lap->listp = listp;
2956
2957 di_devfs_path_free(client_path);
2958 S_FREE(devpath);
2959
2960 /* now return with ok status with ldata. */
2961 lap->ret = FPCFGA_OK;
2962 return (FPCFGA_OK);
2963 }
2964
2965 /*
2966 * Initialize the cfga_list_data struct for an accessible device
2967 * from g_get_dev_list().
2968 *
2969 * Input: fca port ldata.
2970 * Output: device cfga_list_data.
2971 *
2972 */
2973 static fpcfga_ret_t
init_ldata_for_accessible_dev(const char * dyncomp,uchar_t inq_type,fpcfga_list_t * lap)2974 init_ldata_for_accessible_dev(const char *dyncomp, uchar_t inq_type,
2975 fpcfga_list_t *lap)
2976 {
2977 ldata_list_t *listp = NULL;
2978 cfga_list_data_t *clp = NULL;
2979 int i;
2980
2981 listp = calloc(1, sizeof (ldata_list_t));
2982 if (listp == NULL) {
2983 lap->l_errno = errno;
2984 return (FPCFGA_LIB_ERR);
2985 }
2986
2987 clp = &listp->ldata;
2988
2989 assert(dyncomp != NULL);
2990
2991 /* Create logical and physical ap_id */
2992 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
2993 lap->xport_logp, DYN_SEP, dyncomp);
2994
2995 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
2996 lap->apidp->xport_phys, DYN_SEP, dyncomp);
2997
2998 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
2999 clp->ap_r_state = lap->xport_rstate;
3000 clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
3001 clp->ap_cond = CFGA_COND_UNKNOWN;
3002 clp->ap_busy = 0;
3003 clp->ap_status_time = (time_t)-1;
3004 clp->ap_info[0] = '\0';
3005 for (i = 0; i < N_DEVICE_TYPES; i++) {
3006 if (inq_type == device_list[i].itype) {
3007 (void) snprintf(clp->ap_type, sizeof (clp->ap_type),
3008 "%s", (char *)device_list[i].name);
3009 break;
3010 }
3011 }
3012 if (i == N_DEVICE_TYPES) {
3013 if (inq_type == ERR_INQ_DTYPE) {
3014 clp->ap_cond = CFGA_COND_FAILED;
3015 snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
3016 (char *)GET_MSG_STR(ERR_UNAVAILABLE));
3017 } else {
3018 (void) snprintf(clp->ap_type, sizeof (clp->ap_type),
3019 "%s", "unknown");
3020 }
3021 }
3022
3023 /* Link it in */
3024 (void) insert_ldata_to_ldatalist(dyncomp, NULL, listp, &(lap->listp));
3025
3026 return (FPCFGA_OK);
3027 }
3028
3029 /*
3030 * Initialize the cfga_list_data struct for an accessible FCP SCSI LUN device
3031 * from the report lun data.
3032 *
3033 * Input: fca port ldata. report lun info
3034 * Output: device cfga_list_data.
3035 *
3036 */
3037 static fpcfga_ret_t
init_ldata_for_accessible_FCP_dev(const char * port_wwn,int num_luns,struct report_lun_resp * resp_buf,fpcfga_list_t * lap,int * l_errnop)3038 init_ldata_for_accessible_FCP_dev(
3039 const char *port_wwn,
3040 int num_luns,
3041 struct report_lun_resp *resp_buf,
3042 fpcfga_list_t *lap,
3043 int *l_errnop)
3044 {
3045 ldata_list_t *listp = NULL, *listp_start = NULL, *listp_end = NULL,
3046 *prevlp = NULL, *curlp = NULL, *matchp_start = NULL,
3047 *matchp_end = NULL;
3048 cfga_list_data_t *clp = NULL;
3049 char *dyn = NULL, *dyncomp = NULL;
3050 uchar_t *lun_string;
3051 uint16_t lun_num;
3052 int i, j, str_ret;
3053 fpcfga_ret_t ret;
3054 char dtype[CFGA_TYPE_LEN];
3055 struct scsi_inquiry *inq_buf;
3056 uchar_t peri_qual;
3057 cfga_cond_t cond = CFGA_COND_UNKNOWN;
3058 uchar_t lun_num_raw[SAM_LUN_SIZE];
3059
3060 /* when number of lun is 0 it is not an error. so just return ok. */
3061 if (num_luns == 0) {
3062 return (FPCFGA_OK);
3063 }
3064
3065 for (i = 0; i < num_luns; i++) {
3066 lun_string = (uchar_t *)&(resp_buf->lun_string[i]);
3067 memcpy(lun_num_raw, lun_string, sizeof (lun_num_raw));
3068 if ((ret = get_standard_inq_data(lap->apidp->xport_phys, port_wwn,
3069 lun_num_raw, &inq_buf, l_errnop))
3070 != FPCFGA_OK) {
3071 if (ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) {
3072 (void) strlcpy(dtype,
3073 (char *)GET_MSG_STR(ERR_UNAVAILABLE), CFGA_TYPE_LEN);
3074 cond = CFGA_COND_FAILED;
3075 } else {
3076 S_FREE(inq_buf);
3077 return (FPCFGA_LIB_ERR);
3078 }
3079 } else {
3080 peri_qual = inq_buf->inq_dtype & FP_PERI_QUAL_MASK;
3081 /*
3082 * peripheral qualifier is not 0 so the device node should not
3083 * included in the ldata list. There should not be a device
3084 * node for the lun either.
3085 */
3086 if (peri_qual != DPQ_POSSIBLE) {
3087 S_FREE(inq_buf);
3088 continue;
3089 }
3090 *dtype = NULL;
3091 for (j = 0; j < N_DEVICE_TYPES; j++) {
3092 if ((inq_buf->inq_dtype & DTYPE_MASK)
3093 == device_list[j].itype) {
3094 (void) strlcpy(dtype, (char *)device_list[j].name,
3095 CFGA_TYPE_LEN);
3096 break;
3097 }
3098 }
3099 if (*dtype == NULL) {
3100 (void) strlcpy(dtype,
3101 (char *)device_list[DTYPE_UNKNOWN_INDEX].name,
3102 CFGA_TYPE_LEN);
3103 }
3104 }
3105 /*
3106 * Followed FCP driver for getting lun number from report
3107 * lun data.
3108 * According to SAM-2 there are multiple address method for
3109 * FCP SCIS LUN. Logincal unit addressing, peripheral device
3110 * addressing, flat space addressing, and extended logical
3111 * unit addressing.
3112 *
3113 * as of 11/2001 FCP supports logical unit addressing and
3114 * peripheral device addressing even thoough 3 defined.
3115 * SSFCP_LUN_ADDRESSING 0x80
3116 * SSFCP_PD_ADDRESSING 0x00
3117 * SSFCP_VOLUME_ADDRESSING 0x40
3118 *
3119 * the menthod below is used by FCP when (lun_string[0] & 0xC0)
3120 * is either SSFCP_LUN_ADDRESSING or SSFCP_PD_ADDRESSING mode.
3121 */
3122 lun_num = ((lun_string[0] & 0x3F) << 8) | lun_string[1];
3123 listp = calloc(1, sizeof (ldata_list_t));
3124 if (listp == NULL) {
3125 *l_errnop = errno;
3126 list_free(&listp_start);
3127 return (FPCFGA_LIB_ERR);
3128 }
3129
3130 clp = &listp->ldata;
3131 /* Create logical and physical ap_id */
3132 (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id),
3133 "%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn,
3134 LUN_COMP_SEP, lun_num);
3135 (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id),
3136 "%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn,
3137 LUN_COMP_SEP, lun_num);
3138 (void) strncpy(clp->ap_type, dtype, strlen(dtype));
3139 clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
3140 clp->ap_r_state = lap->xport_rstate;
3141 clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
3142 clp->ap_cond = cond;
3143 clp->ap_busy = 0;
3144 clp->ap_status_time = (time_t)-1;
3145 clp->ap_info[0] = '\0';
3146 if (listp_start == NULL) {
3147 listp_start = listp;
3148 } else {
3149 if ((ret = insert_FCP_dev_ldata(
3150 port_wwn, lun_num, listp,
3151 &listp_start)) != FPCFGA_OK) {
3152 list_free(&listp_start);
3153 return (ret);
3154 }
3155 }
3156 listp = NULL;
3157 S_FREE(inq_buf);
3158 }
3159
3160 /*
3161 * list data can be null when device peripheral qualifier is not 0
3162 * for any luns. Return ok to continue.
3163 */
3164 if (listp_start == NULL) {
3165 return (FPCFGA_OK);
3166 }
3167 /*
3168 * get the end of list for later uses.
3169 */
3170 curlp = listp_start->next;
3171 prevlp = listp_start;
3172 while (curlp) {
3173 prevlp = curlp;
3174 curlp = curlp->next;
3175 }
3176 listp_end = prevlp;
3177
3178 /*
3179 * if there is no list data just return the FCP dev list.
3180 * Normally this should not occur since list data should
3181 * be created through g_get_dev_list().
3182 */
3183 if (lap->listp == NULL) {
3184 lap->listp = listp_start;
3185 for (listp = listp_start; listp != NULL; listp = listp->next) {
3186 listp->ldata.ap_cond = CFGA_COND_FAILING;
3187 }
3188 return (FPCFGA_OK);
3189 }
3190
3191 dyn = GET_DYN(lap->listp->ldata.ap_phys_id);
3192 if ((dyn != NULL) && ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
3193 if ((str_ret = strncmp(dyncomp, port_wwn, WWN_SIZE*2)) == 0) {
3194 matchp_start = matchp_end = lap->listp;
3195 while (matchp_end->next != NULL) {
3196 dyn = GET_DYN(
3197 matchp_end->next->ldata.ap_phys_id);
3198 if ((dyn != NULL) &&
3199 ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
3200 if ((str_ret = strncmp(dyncomp,
3201 port_wwn, WWN_SIZE*2)) == 0) {
3202 matchp_end = matchp_end->next;
3203 } else {
3204 break;
3205 }
3206 } else {
3207 break;
3208 }
3209 }
3210 /* fillup inqdtype */
3211 for (listp = listp_start; listp != NULL;
3212 listp = listp->next) {
3213 listp->ldata.ap_cond =
3214 lap->listp->ldata.ap_cond;
3215 }
3216 /* link the new elem of lap->listp. */
3217 listp_end->next = matchp_end->next;
3218 /* free the one matching wwn. */
3219 matchp_end->next = NULL;
3220 list_free(&matchp_start);
3221 /* link lap->listp to listp_start. */
3222 lap->listp = listp_start;
3223 return (FPCFGA_OK);
3224 } else if (str_ret > 0) {
3225 for (listp = listp_start; listp != NULL;
3226 listp = listp->next) {
3227 listp->ldata.ap_cond = CFGA_COND_FAILING;
3228 }
3229 listp_end->next = lap->listp->next;
3230 lap->listp = listp_start;
3231 return (FPCFGA_OK);
3232 }
3233 }
3234
3235 prevlp = lap->listp;
3236 curlp = lap->listp->next;
3237
3238 dyn = dyncomp = NULL;
3239 while (curlp != NULL) {
3240 dyn = GET_DYN(curlp->ldata.ap_phys_id);
3241 if ((dyn != NULL) &&
3242 ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
3243 if ((str_ret = strncmp(dyncomp, port_wwn,
3244 WWN_SIZE*2)) == 0) {
3245 matchp_start = matchp_end = curlp;
3246 while (matchp_end->next != NULL) {
3247 dyn = GET_DYN(
3248 matchp_end->next->ldata.ap_phys_id);
3249 if ((dyn != NULL) &&
3250 ((dyncomp = DYN_TO_DYNCOMP(dyn))
3251 != NULL)) {
3252 if ((str_ret = strncmp(dyncomp,
3253 port_wwn, WWN_SIZE*2))
3254 == 0) {
3255 matchp_end =
3256 matchp_end->next;
3257 } else {
3258 break;
3259 }
3260 } else {
3261 break;
3262 }
3263 }
3264 for (listp = listp_start; listp != NULL;
3265 listp = listp->next) {
3266 listp->ldata.ap_cond = curlp->ldata.ap_cond;
3267 }
3268 /* link the next elem to listp_end. */
3269 listp_end->next = matchp_end->next;
3270 /* link prevlp to listp_start to drop curlp. */
3271 prevlp->next = listp_start;
3272 /* free matching pwwn elem. */
3273 matchp_end->next = NULL;
3274 list_free(&matchp_start);
3275 return (FPCFGA_OK);
3276 } else if (str_ret > 0) {
3277 for (listp = listp_start; listp != NULL;
3278 listp = listp->next) {
3279 /*
3280 * Dev not found from accessible
3281 * fc dev list but the node should
3282 * exist. Set to failing cond now
3283 * and check the node state later.
3284 */
3285 listp->ldata.ap_cond = CFGA_COND_FAILING;
3286 }
3287 /* keep the cur elem by linking to list_end. */
3288 listp_end->next = curlp;
3289 prevlp->next = listp_start;
3290 return (FPCFGA_OK);
3291 }
3292 }
3293 dyn = dyncomp = NULL;
3294 prevlp = curlp;
3295 curlp = curlp->next;
3296 }
3297
3298 prevlp->next = listp_start;
3299 for (listp = listp_start; listp != NULL; listp = listp->next) {
3300 listp->ldata.ap_cond = CFGA_COND_FAILING;
3301 }
3302
3303 return (FPCFGA_OK);
3304
3305 }
3306
3307 /* fill in device type, vid, pid from properties */
3308 static void
get_hw_info(di_node_t node,cfga_list_data_t * clp)3309 get_hw_info(di_node_t node, cfga_list_data_t *clp)
3310 {
3311 char *cp = NULL;
3312 char *inq_vid, *inq_pid;
3313 int i;
3314
3315 /*
3316 * if the type is not previously assigned with valid SCSI device type
3317 * check devinfo to find the type.
3318 * once device is configured it should have a valid device type.
3319 * device node is configured but no valid device type is found
3320 * the type will be set to unavailable.
3321 */
3322 if (clp->ap_type != NULL) {
3323 /*
3324 * if the type is not one of defined SCSI device type
3325 * check devinfo to find the type.
3326 *
3327 * Note: unknown type is not a valid device type.
3328 * It is added in to the device list table to provide
3329 * constant string of "unknown".
3330 */
3331 for (i = 0; i < (N_DEVICE_TYPES -1); i++) {
3332 if (strncmp((char *)clp->ap_type, (char *)device_list[i].name,
3333 sizeof (clp->ap_type)) == 0) {
3334 break;
3335 }
3336 }
3337 if (i == (N_DEVICE_TYPES - 1)) {
3338 cp = (char *)get_device_type(node);
3339 if (cp == NULL) {
3340 cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
3341 }
3342 (void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
3343 S_STR(cp));
3344 }
3345 } else {
3346 cp = (char *)get_device_type(node);
3347 if (cp == NULL) {
3348 cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
3349 }
3350 (void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
3351 S_STR(cp));
3352 }
3353
3354 /*
3355 * Fill in vendor and product ID.
3356 */
3357 if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
3358 "inquiry-product-id", &inq_pid) == 1) &&
3359 (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
3360 "inquiry-vendor-id", &inq_vid) == 1)) {
3361 (void) snprintf(clp->ap_info, sizeof (clp->ap_info),
3362 "%s %s", inq_vid, inq_pid);
3363 }
3364 }
3365
3366 /*
3367 * Get dtype from "inquiry-device-type" property. If not present,
3368 * derive it from minor node type
3369 */
3370 static const char *
get_device_type(di_node_t node)3371 get_device_type(di_node_t node)
3372 {
3373 char *name = NULL;
3374 int *inq_dtype;
3375 int i;
3376
3377 if (node == DI_NODE_NIL) {
3378 return (NULL);
3379 }
3380
3381 /* first, derive type based on inquiry property */
3382 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
3383 &inq_dtype) != -1) {
3384 int itype = (*inq_dtype) & DTYPE_MASK;
3385
3386 for (i = 0; i < N_DEVICE_TYPES; i++) {
3387 if (itype == device_list[i].itype) {
3388 name = (char *)device_list[i].name;
3389 break;
3390 }
3391 }
3392 /*
3393 * when found to be unknown type, set name to null to check
3394 * device minor node type.
3395 */
3396 if (i == (N_DEVICE_TYPES - 1)) {
3397 name = NULL;
3398 }
3399 }
3400
3401 /* if property fails, use minor nodetype */
3402 if (name == NULL) {
3403 char *nodetype;
3404 di_minor_t minor = di_minor_next(node, DI_MINOR_NIL);
3405
3406 if ((minor != DI_MINOR_NIL) &&
3407 ((nodetype = di_minor_nodetype(minor)) != NULL)) {
3408 for (i = 0; i < N_DEVICE_TYPES; i++) {
3409 if (device_list[i].ntype &&
3410 (strcmp(nodetype, device_list[i].ntype)
3411 == 0)) {
3412 name = (char *)device_list[i].name;
3413 break;
3414 }
3415 }
3416 }
3417 }
3418
3419 return (name);
3420 }
3421
3422 /* Transform list data to stat data */
3423 fpcfga_ret_t
list_ext_postprocess(ldata_list_t ** llpp,int nelem,cfga_list_data_t ** ap_id_list,int * nlistp,char ** errstring)3424 list_ext_postprocess(
3425 ldata_list_t **llpp,
3426 int nelem,
3427 cfga_list_data_t **ap_id_list,
3428 int *nlistp,
3429 char **errstring)
3430 {
3431 cfga_list_data_t *ldatap = NULL;
3432 ldata_list_t *tmplp = NULL;
3433 int i = -1;
3434
3435 *ap_id_list = NULL;
3436 *nlistp = 0;
3437
3438 if (*llpp == NULL || nelem < 0) {
3439 return (FPCFGA_LIB_ERR);
3440 }
3441
3442 if (nelem == 0) {
3443 return (FPCFGA_APID_NOEXIST);
3444 }
3445
3446 ldatap = calloc(nelem, sizeof (cfga_list_data_t));
3447 if (ldatap == NULL) {
3448 cfga_err(errstring, errno, ERR_LIST, 0);
3449 return (FPCFGA_LIB_ERR);
3450 }
3451
3452 /* Extract the list_data structures from the linked list */
3453 tmplp = *llpp;
3454 for (i = 0; i < nelem && tmplp != NULL; i++) {
3455 ldatap[i] = tmplp->ldata;
3456 tmplp = tmplp->next;
3457 }
3458
3459 if (i < nelem || tmplp != NULL) {
3460 S_FREE(ldatap);
3461 return (FPCFGA_LIB_ERR);
3462 }
3463
3464 *nlistp = nelem;
3465 *ap_id_list = ldatap;
3466
3467 return (FPCFGA_OK);
3468 }
3469
3470 /*
3471 * Convert bus state to receptacle state
3472 */
3473 static cfga_stat_t
xport_devinfo_to_recep_state(uint_t xport_di_state)3474 xport_devinfo_to_recep_state(uint_t xport_di_state)
3475 {
3476 cfga_stat_t rs;
3477
3478 switch (xport_di_state) {
3479 case DI_BUS_QUIESCED:
3480 case DI_BUS_DOWN:
3481 rs = CFGA_STAT_DISCONNECTED;
3482 break;
3483 /*
3484 * NOTE: An explicit flag for active should probably be added to
3485 * libdevinfo.
3486 */
3487 default:
3488 rs = CFGA_STAT_CONNECTED;
3489 break;
3490 }
3491
3492 return (rs);
3493 }
3494
3495 /*
3496 * Convert device state to occupant state
3497 * if driver is attached the node is configured.
3498 * if offline or down the node is unconfigured.
3499 * if only driver detached it is none state which is treated the same
3500 * way as configured state.
3501 */
3502 static cfga_stat_t
dev_devinfo_to_occupant_state(uint_t dev_di_state)3503 dev_devinfo_to_occupant_state(uint_t dev_di_state)
3504 {
3505 /* Driver attached ? */
3506 if ((dev_di_state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
3507 return (CFGA_STAT_CONFIGURED);
3508 }
3509
3510 if ((dev_di_state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
3511 (dev_di_state & DI_DEVICE_DOWN) == DI_DEVICE_DOWN) {
3512 return (CFGA_STAT_UNCONFIGURED);
3513 } else {
3514 return (CFGA_STAT_NONE);
3515 }
3516 }
3517
3518 /*
3519 * Wrapper routine for inserting ldata to make an sorted ldata list.
3520 *
3521 * When show_FCP_dev option is given insert_FCP_dev_ldata() is called.
3522 * Otherwise insert_fc_dev_ldata() is called.
3523 */
3524 static fpcfga_ret_t
insert_ldata_to_ldatalist(const char * port_wwn,int * lun_nump,ldata_list_t * listp,ldata_list_t ** ldatapp)3525 insert_ldata_to_ldatalist(
3526 const char *port_wwn,
3527 int *lun_nump,
3528 ldata_list_t *listp,
3529 ldata_list_t **ldatapp)
3530 {
3531
3532 if (lun_nump == NULL) {
3533 return (insert_fc_dev_ldata(port_wwn, listp, ldatapp));
3534 } else {
3535 return
3536 (insert_FCP_dev_ldata(port_wwn, *lun_nump, listp, ldatapp));
3537 }
3538 }
3539
3540 /*
3541 * Insert an input ldata to ldata list to make sorted ldata list.
3542 */
3543 static fpcfga_ret_t
insert_fc_dev_ldata(const char * port_wwn,ldata_list_t * listp,ldata_list_t ** ldatapp)3544 insert_fc_dev_ldata(
3545 const char *port_wwn,
3546 ldata_list_t *listp,
3547 ldata_list_t **ldatapp)
3548 {
3549 ldata_list_t *prevlp = NULL, *curlp = NULL;
3550 char *dyn = NULL, *dyncomp = NULL;
3551
3552 if (*ldatapp == NULL) {
3553 *ldatapp = listp;
3554 return (FPCFGA_OK);
3555 }
3556
3557 dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id);
3558 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3559 if ((dyncomp != NULL) &&
3560 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) {
3561 listp->next = *ldatapp;
3562 *ldatapp = listp;
3563 return (FPCFGA_OK);
3564 }
3565 /* else continue */
3566
3567 prevlp = *ldatapp;
3568 curlp = (*ldatapp)->next;
3569
3570 dyn = dyncomp = NULL;
3571 while (curlp != NULL) {
3572 dyn = GET_DYN(curlp->ldata.ap_phys_id);
3573 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3574 if ((dyncomp != NULL) &&
3575 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) {
3576 listp->next = prevlp->next;
3577 prevlp->next = listp;
3578 return (FPCFGA_OK);
3579 }
3580 dyn = dyncomp = NULL;
3581 prevlp = curlp;
3582 curlp = curlp->next;
3583 }
3584
3585 /* add the ldata to the end of the list. */
3586 prevlp->next = listp;
3587 return (FPCFGA_OK);
3588 }
3589
3590 /*
3591 * Insert an input ldata to ldata list to make sorted ldata list.
3592 */
3593 static fpcfga_ret_t
insert_FCP_dev_ldata(const char * port_wwn,int lun_num,ldata_list_t * listp,ldata_list_t ** ldatapp)3594 insert_FCP_dev_ldata(
3595 const char *port_wwn,
3596 int lun_num,
3597 ldata_list_t *listp,
3598 ldata_list_t **ldatapp)
3599 {
3600 ldata_list_t *prevlp = NULL, *curlp = NULL;
3601 char *dyn = NULL, *dyncomp = NULL;
3602 char *lun_dyn = NULL, *lunp = NULL;
3603
3604 if (*ldatapp == NULL) {
3605 *ldatapp = listp;
3606 return (FPCFGA_OK);
3607 }
3608
3609 dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id);
3610 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3611 if ((dyncomp != NULL) &&
3612 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
3613 lun_dyn = GET_LUN_DYN(dyncomp);
3614 if (lun_dyn != NULL) {
3615 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
3616 if ((atoi(lunp)) >= lun_num) {
3617 listp->next = *ldatapp;
3618 *ldatapp = listp;
3619 return (FPCFGA_OK);
3620 }
3621 }
3622 } else if ((dyncomp != NULL) &&
3623 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) {
3624 listp->next = *ldatapp;
3625 *ldatapp = listp;
3626 return (FPCFGA_OK);
3627 }
3628
3629 prevlp = *ldatapp;
3630 curlp = (*ldatapp)->next;
3631
3632 dyn = dyncomp = NULL;
3633 lun_dyn = lunp = NULL;
3634 while (curlp != NULL) {
3635 dyn = GET_DYN(curlp->ldata.ap_phys_id);
3636 if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3637
3638 if ((dyncomp != NULL) &&
3639 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
3640 lun_dyn = GET_LUN_DYN(dyncomp);
3641 if (lun_dyn != NULL) {
3642 lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
3643 if ((atoi(lunp)) >= lun_num) {
3644 listp->next = prevlp->next;
3645 prevlp->next = listp;
3646 return (FPCFGA_OK);
3647 }
3648 }
3649 /* else continue */
3650 } else if ((dyncomp != NULL) &&
3651 (strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) {
3652 listp->next = prevlp->next;
3653 prevlp->next = listp;
3654 return (FPCFGA_OK);
3655 }
3656 /* else continue */
3657
3658 dyn = dyncomp = NULL;
3659 lun_dyn = lunp = NULL;
3660 prevlp = curlp;
3661 curlp = curlp->next;
3662 }
3663
3664 /* add the ldata to the end of the list. */
3665 prevlp->next = listp;
3666 return (FPCFGA_OK);
3667 }
3668
3669 /*
3670 * This function will return the dtype for the given device
3671 * It will first issue a report lun to lun 0 and then it will issue a SCSI
3672 * Inquiry to the first lun returned by report luns.
3673 *
3674 * If everything is successful, the dtype will be returned with the peri
3675 * qualifier masked out.
3676 *
3677 * If either the report lun or the scsi inquiry fails, we will first check
3678 * the return status. If the return status is SCSI_DEVICE_NOT_TGT, then
3679 * we will assume this is a remote HBA and return an UNKNOWN DTYPE
3680 * for all other failures, we will return a dtype of ERR_INQ_DTYPE
3681 */
3682 static uchar_t
get_inq_dtype(char * xport_phys,char * dyncomp,HBA_HANDLE handle,HBA_PORTATTRIBUTES * portAttrs,HBA_PORTATTRIBUTES * discPortAttrs)3683 get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle,
3684 HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs) {
3685 HBA_STATUS status;
3686 report_lun_resp_t *resp_buf;
3687 int num_luns = 0, ret, l_errno;
3688 uchar_t *lun_string;
3689 uint64_t lun = 0;
3690 struct scsi_inquiry inq;
3691 struct scsi_extended_sense sense;
3692 HBA_UINT8 scsiStatus;
3693 uint32_t inquirySize = sizeof (inq);
3694 uint32_t senseSize = sizeof (sense);
3695
3696 memset(&inq, 0, sizeof (inq));
3697 memset(&sense, 0, sizeof (sense));
3698 if ((ret = get_report_lun_data(xport_phys, dyncomp,
3699 &num_luns, &resp_buf, &sense, &l_errno))
3700 != FPCFGA_OK) {
3701 /*
3702 * Checking the sense key data as well as the additional
3703 * sense key. The SES Node is not required to repond
3704 * to Report LUN. In the case of Minnow, the SES node
3705 * returns with KEY_ILLEGAL_REQUEST and the additional
3706 * sense key of 0x20. In this case we will blindly
3707 * send the SCSI Inquiry call to lun 0
3708 *
3709 * if we get any other error we will set the inq_type
3710 * appropriately
3711 */
3712 if ((sense.es_key == KEY_ILLEGAL_REQUEST) &&
3713 (sense.es_add_code == 0x20)) {
3714 lun = 0;
3715 } else {
3716 if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) {
3717 inq.inq_dtype = DTYPE_UNKNOWN;
3718 } else {
3719 inq.inq_dtype = ERR_INQ_DTYPE;
3720 }
3721 return (inq.inq_dtype);
3722 }
3723 } else {
3724 /* send the inquiry to the first lun */
3725 lun_string = (uchar_t *)&(resp_buf->lun_string[0]);
3726 memcpy(&lun, lun_string, sizeof (lun));
3727 S_FREE(resp_buf);
3728 }
3729
3730 memset(&sense, 0, sizeof (sense));
3731 status = HBA_ScsiInquiryV2(handle,
3732 portAttrs->PortWWN, discPortAttrs->PortWWN, lun, 0, 0,
3733 &inq, &inquirySize, &scsiStatus, &sense, &senseSize);
3734 if (status == HBA_STATUS_OK) {
3735 inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
3736 } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
3737 inq.inq_dtype = DTYPE_UNKNOWN;
3738 } else {
3739 inq.inq_dtype = ERR_INQ_DTYPE;
3740 }
3741 return (inq.inq_dtype);
3742 }
3743