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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #define ALL_APID_LUNS_UNUSABLE 0x10
32 #define DEFAULT_LUN_COUNT 1024
34 #define LUN_HEADER_SIZE 8
35 #define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \
39 /* Some forward declarations */
40 static fpcfga_ret_t
do_devctl_dev_create(apid_t
*, char *, int,
42 static fpcfga_ret_t
dev_rcm_online(apid_t
*, int, cfga_flags_t
, char **);
43 static void dev_rcm_online_nonoperationalpath(apid_t
*, cfga_flags_t
, char **);
44 static fpcfga_ret_t
dev_rcm_offline(apid_t
*, cfga_flags_t
, char **);
45 static fpcfga_ret_t
dev_rcm_remove(apid_t
*, cfga_flags_t
, char **);
46 static fpcfga_ret_t
lun_unconf(char *, int, char *, char *, char **);
47 static fpcfga_ret_t
dev_unconf(apid_t
*, char **, uchar_t
*);
48 static fpcfga_ret_t
is_xport_phys_in_pathlist(apid_t
*, char **);
49 static void copy_pwwn_data_to_str(char *, const uchar_t
*);
50 static fpcfga_ret_t
unconf_vhci_nodes(di_path_t
, di_node_t
, char *,
51 char *, int, int *, int *, char **, cfga_flags_t
);
52 static fpcfga_ret_t
unconf_non_vhci_nodes(di_node_t
, char *, char *,
53 int, int *, int *, char **, cfga_flags_t
);
54 static fpcfga_ret_t
unconf_any_devinfo_nodes(apid_t
*, cfga_flags_t
, char **,
56 static fpcfga_ret_t
handle_devs(cfga_cmd_t
, apid_t
*, cfga_flags_t
,
57 char **, HBA_HANDLE
, int, HBA_PORTATTRIBUTES
);
61 * This function initiates the creation of the new device node for a given
63 * So, apidt->dyncomp CANNOT be NULL
66 do_devctl_dev_create(apid_t
*apidt
, char *dev_path
, int pathlen
,
67 uchar_t dev_dtype
, char **errstring
)
69 devctl_ddef_t ddef_hdl
;
70 devctl_hdl_t bus_hdl
, dev_hdl
;
71 char *drvr_name
= "dummy";
75 if ((ddef_hdl
= devctl_ddef_alloc(drvr_name
, 0)) == NULL
) {
76 cfga_err(errstring
, errno
, ERRARG_DC_DDEF_ALLOC
, drvr_name
, 0);
77 return (FPCFGA_LIB_ERR
);
80 if (cvt_dyncomp_to_lawwn(apidt
->dyncomp
, &pwwn
)) {
81 devctl_ddef_free(ddef_hdl
);
82 cfga_err(errstring
, 0, ERR_APID_INVAL
, 0);
83 return (FPCFGA_LIB_ERR
);
86 if (devctl_ddef_byte_array(ddef_hdl
, PORT_WWN_PROP
, FC_WWN_SIZE
,
87 pwwn
.raw_wwn
) == -1) {
88 devctl_ddef_free(ddef_hdl
);
89 cfga_err(errstring
, errno
, ERRARG_DC_BYTE_ARRAY
,
91 return (FPCFGA_LIB_ERR
);
94 if ((bus_hdl
= devctl_bus_acquire(apidt
->xport_phys
, 0)) == NULL
) {
95 devctl_ddef_free(ddef_hdl
);
96 cfga_err(errstring
, errno
, ERRARG_DC_BUS_ACQUIRE
,
97 apidt
->xport_phys
, 0);
98 return (FPCFGA_LIB_ERR
);
101 /* Let driver handle creation of the new path */
102 if (devctl_bus_dev_create(bus_hdl
, ddef_hdl
, 0, &dev_hdl
)) {
103 devctl_ddef_free(ddef_hdl
);
104 devctl_release(bus_hdl
);
105 if (dev_dtype
== DTYPE_UNKNOWN
) {
107 * Unknown DTYPES are devices such as another system's
108 * FC HBA port. We have tried to configure it but
109 * have failed. Since devices with no device type
110 * or an unknown dtype cannot be configured, we will
111 * return an appropriate error message.
113 cfga_err(errstring
, errno
,
114 ERRARG_BUS_DEV_CREATE_UNKNOWN
, apidt
->dyncomp
, 0);
116 cfga_err(errstring
, errno
, ERRARG_BUS_DEV_CREATE
,
119 return (FPCFGA_LIB_ERR
);
121 devctl_release(bus_hdl
);
122 devctl_ddef_free(ddef_hdl
);
124 devctl_get_pathname(dev_hdl
, dev_path
, pathlen
);
125 devctl_release(dev_hdl
);
131 * Online, in RCM, all the LUNs for a particular device.
132 * Caller can specify the # of luns in the lunlist that have to be onlined
133 * by passing a count that is not -ve.
136 * apidt - this is expected to have the list of luns for the device and so
137 * is assumed to be filled in prior to this call
138 * count - # of LUNs in the list that have to be onlined.
139 * errstring - If non-NULL, it will hold any error messages
146 dev_rcm_online(apid_t
*apidt
, int count
, cfga_flags_t flags
, char **errstring
)
148 luninfo_list_t
*lunlistp
;
150 fpcfga_ret_t retval
= FPCFGA_OK
;
152 /* This check may be redundant, but safer this way */
153 if ((apidt
->flags
& FLAG_DISABLE_RCM
) != 0) {
154 /* User has requested not to notify RCM framework */
158 lunlistp
= apidt
->lunlist
;
160 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
161 i
++, lunlistp
= lunlistp
->next
) {
162 if ((count
>= 0) && (i
>= count
))
164 if (fp_rcm_online(lunlistp
->path
, errstring
, flags
) !=
171 retval
= FPCFGA_LIB_ERR
;
177 * Online in RCM for devices which only have paths
178 * not in ONLINE/STANDBY state
181 dev_rcm_online_nonoperationalpath(apid_t
*apidt
, cfga_flags_t flags
,
184 luninfo_list_t
*lunlistp
;
186 if ((apidt
->flags
& FLAG_DISABLE_RCM
) != 0) {
190 lunlistp
= apidt
->lunlist
;
192 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
193 lunlistp
= lunlistp
->next
) {
194 if ((lunlistp
->lun_flag
& FLAG_SKIP_ONLINEOTHERS
) != 0) {
197 (void) fp_rcm_online(lunlistp
->path
, errstring
, flags
);
202 * Offline, in RCM, all the LUNs for a particular device.
203 * This function should not be called for the MPXIO case.
206 * apidt - this is expected to have the list of luns for the device and so
207 * is assumed to be filled in prior to this call
208 * errstring - If non-NULL, it will hold any error messages
211 * FPCFGA_OK on success
212 * error code otherwise
215 dev_rcm_offline(apid_t
*apidt
, cfga_flags_t flags
, char **errstring
)
218 luninfo_list_t
*lunlistp
;
220 if ((apidt
->flags
& FLAG_DISABLE_RCM
) != 0) {
221 /* User has requested not to notify RCM framework */
225 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
226 lunlistp
= lunlistp
->next
) {
227 if ((lunlistp
->lun_flag
& FLAG_SKIP_RCMOFFLINE
) != 0) {
230 if ((apidt
->flags
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
231 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
232 int ret
= strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
233 strlen(SCSI_VHCI_ROOT
));
236 (lunlistp
->node_state
== DI_PATH_STATE_OFFLINE
)) ||
238 ((lunlistp
->node_state
& DI_DEVICE_OFFLINE
) ==
239 DI_DEVICE_OFFLINE
))) {
240 /* Offline the device through RCM */
241 if (fp_rcm_offline(lunlistp
->path
, errstring
,
244 * Bring everything back online in
247 (void) dev_rcm_online(apidt
, count
,
249 return (FPCFGA_LIB_ERR
);
254 /* Offline the device through RCM */
255 if (fp_rcm_offline(lunlistp
->path
, errstring
,
258 * Bring everything back online in
261 (void) dev_rcm_online(apidt
, count
, flags
,
263 return (FPCFGA_LIB_ERR
);
272 * Remove, in RCM, all the LUNs for a particular device.
273 * This function should not be called for the MPXIO case.
276 * apidt - this is expected to have the list of luns for the device and so
277 * is assumed to be filled in prior to this call
278 * errstring - If non-NULL, it will hold any error messages
281 * FPCFGA_OK on success
282 * error code otherwise
285 dev_rcm_remove(apid_t
*apidt
, cfga_flags_t flags
, char **errstring
)
288 luninfo_list_t
*lunlistp
;
290 if ((apidt
->flags
& FLAG_DISABLE_RCM
) != 0) {
291 /* User has requested not to notify RCM framework */
295 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
296 lunlistp
= lunlistp
->next
) {
297 if ((lunlistp
->lun_flag
& FLAG_SKIP_RCMREMOVE
) != 0)
299 if ((apidt
->flags
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
300 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
301 int ret
= strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
302 strlen(SCSI_VHCI_ROOT
));
305 (lunlistp
->node_state
== DI_PATH_STATE_OFFLINE
)) ||
307 ((lunlistp
->node_state
& DI_DEVICE_OFFLINE
) ==
308 DI_DEVICE_OFFLINE
))) {
309 /* remove the device through RCM */
310 if (fp_rcm_remove(lunlistp
->path
, errstring
,
313 * Bring everything back online in
316 (void) dev_rcm_online(apidt
, count
,
318 return (FPCFGA_LIB_ERR
);
323 /* remove the device through RCM */
324 if (fp_rcm_remove(lunlistp
->path
, errstring
,
327 * Bring everything back online in rcm and
330 (void) dev_rcm_online(apidt
, count
, flags
,
332 return (FPCFGA_LIB_ERR
);
341 lun_unconf(char *path
, int lunnum
, char *xport_phys
, char *dyncomp
,
345 char *ptr
; /* To use as scratch/temp pointer */
346 char pathname
[MAXPATHLEN
];
351 if (strncmp(path
, SCSI_VHCI_ROOT
, strlen(SCSI_VHCI_ROOT
)) == 0) {
353 * We have an MPXIO managed device here.
354 * So, we have to concoct a path for the device.
356 * xport_phys looks like :
357 * /devices/pci@b,2000/pci@1/SUNW,qlc@5/fp@0,0:fc
359 (void) strlcpy(pathname
, xport_phys
, MAXPATHLEN
);
360 if ((ptr
= strrchr(pathname
, ':')) != NULL
) {
365 * Get pointer to driver name from VHCI path
366 * So, if lunlistp->path is
367 * /devices/scsi_vhci/ssd@g220000203707a417,
368 * we need a pointer to the last '/'
371 * With MPXIO there will be only one entry per lun
372 * So, there will only be one entry in the linked list
375 if ((ptr
= strrchr(path
, '/')) == NULL
) {
376 /* This shouldn't happen, but anyways ... */
377 cfga_err(errstring
, 0, ERRARG_INVALID_PATH
, path
, 0);
378 return (FPCFGA_LIB_ERR
);
382 * Make pathname to look something like :
383 * /devices/pci@x,xxxx/pci@x/SUNW,qlc@x/fp@x,x/ssd@w...
385 strcat(pathname
, ptr
);
388 * apidt_create() will make sure that lunlist->path
389 * has a "@<something>" at the end even if the driver
390 * state is "detached"
392 if ((ptr
= strrchr(pathname
, '@')) == NULL
) {
393 /* This shouldn't happen, but anyways ... */
394 cfga_err(errstring
, 0, ERRARG_INVALID_PATH
,
396 return (FPCFGA_LIB_ERR
);
400 /* Now, concoct the path */
401 sprintf(&pathname
[strlen(pathname
)], "@w%s,%x",
406 * non-MPXIO path, use the path that is passed in
411 if ((hdl
= devctl_device_acquire(ptr
, 0)) == NULL
) {
412 cfga_err(errstring
, errno
, ERRARG_DEV_ACQUIRE
, ptr
, 0);
413 return (FPCFGA_LIB_ERR
);
416 if (devctl_device_remove(hdl
) != 0) {
418 cfga_err(errstring
, errno
, ERRARG_DEV_REMOVE
, ptr
, 0);
419 return (FPCFGA_LIB_ERR
);
427 dev_unconf(apid_t
*apidt
, char **errstring
, uchar_t
*flag
)
429 luninfo_list_t
*lunlistp
;
430 fpcfga_ret_t ret
= FPCFGA_OK
;
431 int lun_cnt
= 0, unusable_lun_cnt
= 0;
433 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
434 lunlistp
= lunlistp
->next
) {
437 * Unconfigure each LUN.
438 * Note that for MPXIO devices, lunlistp->path will be a
441 if ((apidt
->flags
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
442 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
443 if (strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
444 strlen(SCSI_VHCI_ROOT
)) == 0) {
445 if (lunlistp
->node_state
==
446 DI_PATH_STATE_OFFLINE
) {
448 if ((ret
= lun_unconf(lunlistp
->path
,
449 lunlistp
->lunnum
, apidt
->xport_phys
,
450 apidt
->dyncomp
, errstring
)) != FPCFGA_OK
) {
455 if ((lunlistp
->node_state
& DI_DEVICE_OFFLINE
) ==
458 if ((ret
= lun_unconf(lunlistp
->path
,
459 lunlistp
->lunnum
, apidt
->xport_phys
,
460 apidt
->dyncomp
, errstring
)) != FPCFGA_OK
) {
467 * Unconfigure each LUN.
468 * Note that for MPXIO devices, lunlistp->path will be a
471 if ((ret
= lun_unconf(lunlistp
->path
, lunlistp
->lunnum
,
472 apidt
->xport_phys
, apidt
->dyncomp
,
473 errstring
)) != FPCFGA_OK
) {
479 if ((apidt
->flags
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
480 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
482 * when all luns are unconfigured
483 * indicate to remove repository entry.
485 if (lun_cnt
== unusable_lun_cnt
) {
486 *flag
= ALL_APID_LUNS_UNUSABLE
;
494 * Check if the given physical path (the xport_phys) is part of the
495 * pHCI list and if the RCM should be done for a particular pHCI.
496 * Skip non-MPxIO dev node if any.
499 is_xport_phys_in_pathlist(apid_t
*apidt
, char **errstring
)
501 di_node_t root
, vhci
, node
, phci
;
502 di_path_t path
= DI_PATH_NIL
;
503 int num_active_paths
, found
= 0;
504 char *vhci_path_ptr
, *pathname_ptr
, pathname
[MAXPATHLEN
];
505 char *phci_path
, *node_path
;
506 char phci_addr
[MAXPATHLEN
];
507 char *xport_phys
, *vhci_path
, *dyncomp
;
508 luninfo_list_t
*lunlistp
, *temp
;
509 int non_operational_path_count
;
512 if ((apidt
->dyncomp
== NULL
) || (*apidt
->dyncomp
== '\0')) {
513 return (FPCFGA_LIB_ERR
);
516 xport_phys
= apidt
->xport_phys
;
517 dyncomp
= apidt
->dyncomp
;
519 lunlistp
= apidt
->lunlist
;
520 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
521 lunlistp
= lunlistp
->next
) {
523 if (strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
524 strlen(SCSI_VHCI_ROOT
)) != 0) {
525 lunlistp
->lun_flag
|= FLAG_SKIP_ONLINEOTHERS
;
529 vhci_path
= lunlistp
->path
;
531 num_active_paths
= 0; /* # of paths in ONLINE/STANDBY */
532 non_operational_path_count
= 0;
534 if (xport_phys
== NULL
|| vhci_path
== NULL
) {
535 cfga_err(errstring
, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST
,
537 return (FPCFGA_LIB_ERR
);
540 (void) strlcpy(pathname
, xport_phys
, MAXPATHLEN
);
541 if ((pathname_ptr
= strrchr(pathname
, ':')) != NULL
) {
542 *pathname_ptr
= '\0';
544 /* strip off the /devices/from the path */
545 pathname_ptr
= pathname
+ strlen(DEVICES_DIR
);
547 root
= di_init("/", DINFOCPYALL
|DINFOPATH
);
549 if (root
== DI_NODE_NIL
) {
550 return (FPCFGA_LIB_ERR
);
553 vhci_path_ptr
= vhci_path
+ strlen(DEVICES_DIR
);
554 if ((vhci
= di_drv_first_node(SCSI_VHCI_DRVR
, root
)) ==
556 return (FPCFGA_LIB_ERR
);
559 for (node
= di_child_node(vhci
); node
!= DI_NODE_NIL
;
560 node
= di_sibling_node(node
)) {
561 if ((node_path
= di_devfs_path(node
)) != NULL
) {
562 if (strncmp(vhci_path_ptr
, node_path
,
563 strlen(node_path
)) != 0) {
564 di_devfs_path_free(node_path
);
572 cfga_err(errstring
, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST
,
575 return (FPCFGA_LIB_ERR
);
577 /* found vhci_path we are looking for */
578 di_devfs_path_free(node_path
);
580 for (path
= di_path_next_phci(node
, DI_PATH_NIL
);
582 path
= di_path_next_phci(node
, path
)) {
583 if ((phci
= di_path_phci_node(path
)) == DI_NODE_NIL
) {
584 cfga_err(errstring
, 0,
585 ERRARG_XPORT_NOT_IN_PHCI_LIST
,
588 return (FPCFGA_LIB_ERR
);
590 if ((phci_path
= di_devfs_path(phci
)) == NULL
) {
591 cfga_err(errstring
, 0,
592 ERRARG_XPORT_NOT_IN_PHCI_LIST
,
595 return (FPCFGA_LIB_ERR
);
597 (void) di_path_addr(path
, (char *)phci_addr
);
598 if ((phci_addr
== NULL
) || (*phci_addr
== '\0')) {
599 cfga_err(errstring
, 0,
600 ERRARG_XPORT_NOT_IN_PHCI_LIST
,
602 di_devfs_path_free(phci_path
);
604 return (FPCFGA_LIB_ERR
);
607 * Check if the phci path has the same
608 * xport addr and the target addr with current lun
610 if ((strncmp(phci_path
, pathname_ptr
,
611 strlen(pathname_ptr
)) == 0) &&
612 (strstr(phci_addr
, dyncomp
) != NULL
)) {
613 /* SUCCESS Found xport_phys */
615 } else if ((di_path_state(path
) ==
616 DI_PATH_STATE_ONLINE
) ||
617 (di_path_state(path
) == DI_PATH_STATE_STANDBY
)) {
621 * We have another path not in ONLINE/STANDBY
622 * state now, so should do a RCM online after
623 * the unconfiguration of current path.
625 non_operational_path_count
++;
627 di_devfs_path_free(phci_path
);
631 if (num_active_paths
!= 0) {
633 * There are other ONLINE/STANDBY paths,
634 * so no need to do the RCM
636 lunlistp
->lun_flag
|= FLAG_SKIP_RCMREMOVE
;
637 lunlistp
->lun_flag
|= FLAG_SKIP_RCMOFFLINE
;
639 if (non_operational_path_count
== 0) {
640 lunlistp
->lun_flag
|= FLAG_SKIP_ONLINEOTHERS
;
644 * Fail all operations here
646 cfga_err(errstring
, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST
,
648 return (FPCFGA_APID_NOEXIST
);
652 /* Mark duplicated paths for same vhci in the list */
653 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
654 lunlistp
= lunlistp
->next
) {
655 if (strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
656 strlen(SCSI_VHCI_ROOT
)) != 0) {
659 for (temp
= lunlistp
->next
; temp
!= NULL
;
661 if (strcmp(lunlistp
->path
, temp
->path
) == 0) {
663 * don't do RCM for dup
665 lunlistp
->lun_flag
|= FLAG_SKIP_RCMREMOVE
;
666 lunlistp
->lun_flag
|= FLAG_SKIP_RCMOFFLINE
;
667 lunlistp
->lun_flag
|= FLAG_SKIP_ONLINEOTHERS
;
674 * apidt->dyncomp has to be non-NULL by the time this routine is called
677 dev_change_state(cfga_cmd_t state_change_cmd
, apid_t
*apidt
, la_wwn_t
*pwwn
,
678 cfga_flags_t flags
, char **errstring
, HBA_HANDLE handle
,
679 HBA_PORTATTRIBUTES portAttrs
)
681 char dev_path
[MAXPATHLEN
];
682 char *update_str
, *t_apid
;
683 int optflag
= apidt
->flags
;
684 int no_config_attempt
= 0;
687 uchar_t unconf_flag
= 0, peri_qual
;
689 HBA_PORTATTRIBUTES discPortAttrs
;
691 struct scsi_inquiry inq
;
692 struct scsi_extended_sense sense
;
693 HBA_UINT8 scsiStatus
;
694 uint32_t inquirySize
= sizeof (inq
),
695 senseSize
= sizeof (sense
);
696 report_lun_resp_t
*resp_buf
;
697 int i
, l_errno
, num_luns
= 0;
700 if ((apidt
->dyncomp
== NULL
) || (*apidt
->dyncomp
== '\0')) {
702 * No dynamic component specified. Just return success.
703 * Should not see this case. Just a safety check.
708 /* Now construct the string we are going to put in the repository */
709 if ((update_str
= calloc(1, (strlen(apidt
->xport_phys
) +
710 strlen(DYN_SEP
) + strlen(apidt
->dyncomp
) + 1))) == NULL
) {
711 cfga_err(errstring
, errno
, ERR_MEM_ALLOC
, 0);
712 return (FPCFGA_LIB_ERR
);
714 strcpy(update_str
, apidt
->xport_phys
);
715 strcat(update_str
, DYN_SEP
);
716 strcat(update_str
, apidt
->dyncomp
);
718 /* If force update of repository is sought, do it first */
719 if (optflag
& FLAG_FORCE_UPDATE_REP
) {
720 /* Ignore any failure in rep update */
721 (void) update_fabric_wwn_list(
722 ((state_change_cmd
== CFGA_CMD_CONFIGURE
) ?
723 ADD_ENTRY
: REMOVE_ENTRY
),
724 update_str
, errstring
);
727 memset(&sense
, 0, sizeof (sense
));
728 if ((ret
= get_report_lun_data(apidt
->xport_phys
, apidt
->dyncomp
,
729 &num_luns
, &resp_buf
, &sense
, &l_errno
)) != FPCFGA_OK
) {
731 * Checking the sense key data as well as the additional
732 * sense key. The SES Node is not required to repond
733 * to Report LUN. In the case of Minnow, the SES node
734 * returns with KEY_ILLEGAL_REQUEST and the additional
735 * sense key of 0x20. In this case we will blindly
736 * send the SCSI Inquiry call to lun 0
738 * if we get any other error we will set the inq_type
741 if ((sense
.es_key
== KEY_ILLEGAL_REQUEST
) &&
742 (sense
.es_add_code
== 0x20)) {
745 if (ret
== FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT
) {
746 inq
.inq_dtype
= DTYPE_UNKNOWN
;
749 * Failed to get the LUN data for the device
750 * If we find that there is a lunlist for this
751 * device it could mean that there are dangling
752 * devinfo nodes. So, we will go ahead and try
753 * to unconfigure them.
755 if ((apidt
->lunlist
== NULL
) ||
756 (state_change_cmd
== CFGA_CMD_CONFIGURE
)) {
758 status
= getPortAttrsByWWN(handle
,
759 *((HBA_WWN
*)(pwwn
)),
762 HBA_STATUS_ERROR_ILLEGAL_WWN
) {
763 return (FPCFGA_APID_NOEXIST
);
765 cfga_err(errstring
, 0,
768 return (FPCFGA_LIB_ERR
);
771 /* unconfig with lunlist not empty */
777 for (i
= 0; i
< num_luns
; i
++) {
779 * issue the inquiry to the first valid lun found
782 lun_string
= (uchar_t
*)&(resp_buf
->lun_string
[i
]);
783 memcpy(&lun
, lun_string
, sizeof (lun
));
785 memset(&sense
, 0, sizeof (sense
));
786 status
= HBA_ScsiInquiryV2(handle
, portAttrs
.PortWWN
,
787 *(HBA_WWN
*)(pwwn
), lun
, 0, 0, &inq
, &inquirySize
,
788 &scsiStatus
, &sense
, &senseSize
);
790 * if Inquiry is returned correctly, check the
791 * peripheral qualifier for the lun. if it is non-zero
792 * then try the SCSI Inquiry on the next lun
794 if (status
== HBA_STATUS_OK
) {
795 peri_qual
= inq
.inq_dtype
& FP_PERI_QUAL_MASK
;
796 if (peri_qual
== DPQ_POSSIBLE
) {
802 if (ret
== FPCFGA_OK
)
806 * If there are no luns on this target, we will attempt to send
807 * the SCSI Inquiry to lun 0
811 status
= HBA_ScsiInquiryV2(handle
, portAttrs
.PortWWN
,
812 *(HBA_WWN
*)(pwwn
), lun
, 0, 0, &inq
, &inquirySize
,
813 &scsiStatus
, &sense
, &senseSize
);
816 if (status
!= HBA_STATUS_OK
) {
817 if (status
== HBA_STATUS_ERROR_NOT_A_TARGET
) {
818 inq
.inq_dtype
= DTYPE_UNKNOWN
;
819 } else if (status
== HBA_STATUS_ERROR_ILLEGAL_WWN
) {
821 return (FPCFGA_APID_NOEXIST
);
824 * Failed to get the inq_dtype of device
825 * If we find that there is a lunlist for this
826 * device it could mean that there dangling
827 * devinfo nodes. So, we will go ahead and try
828 * to unconfigure them. We'll just set the
829 * inq_dtype to some invalid value (0xFF)
831 if ((apidt
->lunlist
== NULL
) ||
832 (state_change_cmd
== CFGA_CMD_CONFIGURE
)) {
833 cfga_err(errstring
, 0,
837 return (FPCFGA_LIB_ERR
);
839 /* unconfig with lunlist not empty */
844 switch (state_change_cmd
) {
845 case CFGA_CMD_CONFIGURE
:
846 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
847 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
852 if (((inq
.inq_dtype
& DTYPE_MASK
) == DTYPE_UNKNOWN
) &&
853 ((flags
& CFGA_FLAG_FORCE
) == 0)) {
855 * We assume all DTYPE_UNKNOWNs are HBAs and we wont
856 * waste time trying to config them. If they are not
857 * HBAs, then there is something wrong since they should
858 * have had a valid dtype.
860 * However, if the force flag is set (cfgadm -f), we
861 * go ahead and try to configure.
863 * In this path, however, the force flag is not set.
871 * We'll issue the devctl_bus_dev_create() call even if the
872 * path exists in the devinfo tree. This is to take care of
873 * the situation where the device may be in a state other
874 * than the online and attached state.
876 if ((ret
= do_devctl_dev_create(apidt
, dev_path
, MAXPATHLEN
,
877 inq
.inq_dtype
, errstring
)) != FPCFGA_OK
) {
879 * Could not configure device. To provide a more
880 * meaningful error message, first see if the supplied port
881 * WWN is there on the fabric. Otherwise print the error
882 * message using the information received from the driver
884 status
= getPortAttrsByWWN(handle
, *((HBA_WWN
*)(pwwn
)),
887 if (status
== HBA_STATUS_ERROR_ILLEGAL_WWN
) {
888 return (FPCFGA_APID_NOEXIST
);
890 return (FPCFGA_LIB_ERR
);
894 if (((optflag
& (FLAG_FORCE_UPDATE_REP
|FLAG_NO_UPDATE_REP
)) == 0) &&
895 update_fabric_wwn_list(ADD_ENTRY
, update_str
, errstring
)) {
896 cfga_err(errstring
, 0, ERR_CONF_OK_UPD_REP
, 0);
901 if ((apidt
->flags
& FLAG_DISABLE_RCM
) == 0) {
903 * There may be multiple LUNs associated with the
904 * WWN we created nodes for. So, we'll call
905 * apidt_create() again and let it build a list of
906 * all the LUNs for this WWN using the devinfo tree.
907 * We will then online all those devices in RCM
909 if ((t_apid
= calloc(1, strlen(apidt
->xport_phys
) +
911 strlen(apidt
->dyncomp
) + 1)) == NULL
) {
912 cfga_err(errstring
, errno
, ERR_MEM_ALLOC
, 0);
913 return (FPCFGA_LIB_ERR
);
915 sprintf(t_apid
, "%s%s%s", apidt
->xport_phys
, DYN_SEP
,
917 if ((ret
= apidt_create(t_apid
, &my_apidt
,
918 errstring
)) != FPCFGA_OK
) {
923 my_apidt
.flags
= apidt
->flags
;
924 if ((ret
= dev_rcm_online(&my_apidt
, -1, flags
,
925 NULL
)) != FPCFGA_OK
) {
926 cfga_err(errstring
, 0, ERRARG_RCM_ONLINE
,
927 apidt
->lunlist
->path
, 0);
928 apidt_free(&my_apidt
);
933 apidt_free(&my_apidt
);
937 case CFGA_CMD_UNCONFIGURE
:
938 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
939 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
941 return (FPCFGA_OPNOTSUPP
);
944 status
= getPortAttrsByWWN(handle
, *((HBA_WWN
*)(pwwn
)),
946 if (apidt
->lunlist
== NULL
) {
948 * But first, remove entry from the repository if it is
949 * there ... provided the force update flag is not set
950 * (in which case the update is already done) or if
951 * the no-update flag is not set.
954 (FLAG_FORCE_UPDATE_REP
|FLAG_NO_UPDATE_REP
)) == 0) {
955 if (update_fabric_wwn_list(REMOVE_ENTRY
,
956 update_str
, errstring
)) {
958 cfga_err(errstring
, 0,
959 ERR_UNCONF_OK_UPD_REP
, 0);
961 (FPCFGA_UNCONF_OK_UPD_REP_FAILED
);
965 if (status
== HBA_STATUS_ERROR_ILLEGAL_WWN
) {
966 return (FPCFGA_APID_NOEXIST
);
971 * If there are multiple paths to the mpxio
972 * device, we will not check in RCM ONLY when there
973 * is atleast one other ONLINE/STANDBY path
975 if (is_xport_phys_in_pathlist(apidt
, errstring
) !=
978 return (FPCFGA_XPORT_NOT_IN_PHCI_LIST
);
982 * dev_rcm_offline() updates errstring
984 if ((ret
= dev_rcm_offline(apidt
, flags
, errstring
)) !=
989 if ((ret
= dev_unconf(apidt
, errstring
, &unconf_flag
)) !=
991 /* when inq failed don't attempt to reconfigure */
992 if (!no_config_attempt
) {
993 (void) do_devctl_dev_create(apidt
, dev_path
, MAXPATHLEN
,
994 inq
.inq_dtype
, NULL
);
995 (void) dev_rcm_online(apidt
, -1, flags
, NULL
);
1000 if ((ret
= dev_rcm_remove(apidt
, flags
, errstring
)) !=
1002 (void) do_devctl_dev_create(apidt
, dev_path
, MAXPATHLEN
,
1003 inq
.inq_dtype
, NULL
);
1004 (void) dev_rcm_online(apidt
, -1, flags
, NULL
);
1009 * If we offlined a lun in RCM when there are multiple paths but
1010 * none of them are ONLINE/STANDBY, we have to online it back
1011 * in RCM now. This is a try best, will not fail for it.
1013 dev_rcm_online_nonoperationalpath(apidt
, flags
, NULL
);
1015 /* Update the repository if we havent already done it */
1017 (FLAG_FORCE_UPDATE_REP
|FLAG_NO_UPDATE_REP
)) == 0) {
1018 if (((optflag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) !=
1019 FLAG_REMOVE_UNUSABLE_FCP_DEV
) ||
1020 (((optflag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
1021 FLAG_REMOVE_UNUSABLE_FCP_DEV
) &&
1022 (unconf_flag
== ALL_APID_LUNS_UNUSABLE
))) {
1023 if (update_fabric_wwn_list(REMOVE_ENTRY
,
1024 update_str
, errstring
)) {
1026 cfga_err(errstring
, errno
,
1027 ERR_UNCONF_OK_UPD_REP
, 0);
1028 return (FPCFGA_UNCONF_OK_UPD_REP_FAILED
);
1037 return (FPCFGA_OPNOTSUPP
);
1042 * This function copies a port_wwn got by reading the property on a device
1043 * node (from_ptr in the function below) on to an array (to_ptr) so that it is
1046 * Caller responsible to allocate enough memory in "to_ptr"
1049 copy_pwwn_data_to_str(char *to_ptr
, const uchar_t
*from_ptr
)
1051 if ((to_ptr
== NULL
) || (from_ptr
== NULL
))
1054 (void) sprintf(to_ptr
, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1055 from_ptr
[0], from_ptr
[1], from_ptr
[2], from_ptr
[3],
1056 from_ptr
[4], from_ptr
[5], from_ptr
[6], from_ptr
[7]);
1060 unconf_vhci_nodes(di_path_t pnode
, di_node_t fp_node
, char *xport_phys
,
1061 char *dyncomp
, int unusable_flag
,
1062 int *num_devs
, int *failure_count
, char **errstring
,
1065 int iret1
, iret2
, *lunnump
;
1066 char *ptr
; /* scratch pad */
1067 char *node_path
, *vhci_path
, *update_str
;
1068 char port_wwn
[WWN_SIZE
*2+1], pathname
[MAXPATHLEN
];
1069 uchar_t
*port_wwn_data
= NULL
;
1070 di_node_t client_node
;
1072 while (pnode
!= DI_PATH_NIL
) {
1077 if ((node_path
= di_devfs_path(fp_node
)) == NULL
) {
1078 cfga_err(errstring
, 0, ERRARG_DEVINFO
,
1081 pnode
= di_path_next_client(fp_node
, pnode
);
1085 iret1
= di_path_prop_lookup_bytes(pnode
, PORT_WWN_PROP
,
1088 iret2
= di_path_prop_lookup_ints(pnode
, LUN_PROP
, &lunnump
);
1090 if ((iret1
== -1) || (iret2
== -1)) {
1091 cfga_err(errstring
, 0, ERRARG_DI_GET_PROP
,
1093 di_devfs_path_free(node_path
);
1096 pnode
= di_path_next_client(fp_node
, pnode
);
1100 copy_pwwn_data_to_str(port_wwn
, port_wwn_data
);
1102 if ((client_node
= di_path_client_node(pnode
)) ==
1105 di_devfs_path_free(node_path
);
1107 pnode
= di_path_next_client(fp_node
, pnode
);
1111 if ((vhci_path
= di_devfs_path(client_node
)) == NULL
) {
1113 di_devfs_path_free(node_path
);
1115 pnode
= di_path_next_client(fp_node
, pnode
);
1119 if ((ptr
= strrchr(vhci_path
, '@')) != NULL
) {
1123 if ((ptr
= strrchr(vhci_path
, '/')) == NULL
) {
1125 di_devfs_path_free(node_path
);
1127 pnode
= di_path_next_client(fp_node
, pnode
);
1131 sprintf(pathname
, "%s%s/%s@w%s,%x", DEVICES_DIR
, node_path
,
1132 ++ptr
, port_wwn
, *lunnump
);
1134 di_devfs_path_free(node_path
);
1135 di_devfs_path_free(vhci_path
);
1136 node_path
= vhci_path
= NULL
;
1139 * Try to offline in RCM first and if that is successful,
1140 * unconfigure the LUN. If offlining in RCM fails, then
1141 * update the failure_count which gets passed back to caller
1143 * Here we got to check if unusable_flag is set or not.
1144 * If set, then unconfigure only those luns which are in
1145 * node_state DI_PATH_STATE_OFFLINE. If not set, unconfigure
1148 if ((unusable_flag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
1149 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
1150 if (pnode
->path_state
== DI_PATH_STATE_OFFLINE
) {
1151 if (fp_rcm_offline(pathname
, errstring
,
1154 pnode
= di_path_next_client(fp_node
,
1157 } else if (lun_unconf(pathname
, *lunnump
,
1158 xport_phys
,dyncomp
, errstring
)
1160 (void) fp_rcm_online(pathname
,
1163 pnode
= di_path_next_client(fp_node
,
1166 } else if (fp_rcm_remove(pathname
, errstring
,
1169 * Bring everything back online
1170 * in rcm and continue
1172 (void) fp_rcm_online(pathname
,
1175 pnode
= di_path_next_client(fp_node
,
1180 pnode
= di_path_next(fp_node
, pnode
);
1184 if (fp_rcm_offline(pathname
, errstring
, flags
) != 0) {
1186 pnode
= di_path_next_client(fp_node
, pnode
);
1188 } else if (lun_unconf(pathname
, *lunnump
, xport_phys
,
1189 dyncomp
, errstring
) != FPCFGA_OK
) {
1190 (void) fp_rcm_online(pathname
, NULL
, flags
);
1192 pnode
= di_path_next_client(fp_node
, pnode
);
1194 } else if (fp_rcm_remove(pathname
, errstring
,
1197 * Bring everything back online
1198 * in rcm and continue
1200 (void) fp_rcm_online(pathname
, NULL
, flags
);
1202 pnode
= di_path_next_client(fp_node
, pnode
);
1207 /* Update the repository only on a successful unconfigure */
1208 if ((update_str
= calloc(1, strlen(xport_phys
) +
1210 strlen(port_wwn
) + 1)) == NULL
) {
1211 cfga_err(errstring
, errno
, ERR_UNCONF_OK_UPD_REP
, 0);
1213 pnode
= di_path_next_client(fp_node
, pnode
);
1217 /* Init the string to be removed from repository */
1218 sprintf(update_str
, "%s%s%s", xport_phys
, DYN_SEP
, port_wwn
);
1220 if (update_fabric_wwn_list(REMOVE_ENTRY
, update_str
,
1223 cfga_err(errstring
, errno
,
1224 ERR_UNCONF_OK_UPD_REP
, 0);
1226 /* Cleanup and continue from here just for clarity */
1227 pnode
= di_path_next_client(fp_node
, pnode
);
1232 pnode
= di_path_next_client(fp_node
, pnode
);
1239 unconf_non_vhci_nodes(di_node_t dnode
, char *xport_phys
, char *dyncomp
,
1240 int unusable_flag
, int *num_devs
, int *failure_count
,
1241 char **errstring
, cfga_flags_t flags
)
1243 int ret1
, ret2
, *lunnump
;
1244 char pathname
[MAXPATHLEN
];
1245 char *node_path
, *update_str
;
1246 char port_wwn
[WWN_SIZE
*2+1];
1247 uchar_t
*port_wwn_data
= NULL
;
1249 while (dnode
!= DI_NODE_NIL
) {
1253 /* Get the physical path for this node */
1254 if ((node_path
= di_devfs_path(dnode
)) == NULL
) {
1256 * We don't try to offline in RCM here because we
1257 * don't know the path to offline. Just continue to
1260 cfga_err(errstring
, 0, ERRARG_DEVINFO
, xport_phys
, 0);
1262 dnode
= di_sibling_node(dnode
);
1266 /* Now get the LUN # of this device thru the property */
1267 ret1
= di_prop_lookup_ints(DDI_DEV_T_ANY
, dnode
,
1268 LUN_PROP
, &lunnump
);
1270 /* Next get the port WWN of the device */
1271 ret2
= di_prop_lookup_bytes(DDI_DEV_T_ANY
, dnode
,
1272 PORT_WWN_PROP
, &port_wwn_data
);
1274 /* A failure in any of the above is not good */
1275 if ((ret1
== -1) || (ret2
== -1)) {
1277 * We don't try to offline in RCM here because we
1278 * don't know the path to offline. Just continue to
1281 cfga_err(errstring
, 0,
1282 ERRARG_DI_GET_PROP
, node_path
, 0);
1283 di_devfs_path_free(node_path
);
1286 dnode
= di_sibling_node(dnode
);
1290 /* Prepend the "/devices" prefix to the path and copy it */
1291 sprintf(pathname
, "%s%s", DEVICES_DIR
, node_path
);
1292 di_devfs_path_free(node_path
);
1295 copy_pwwn_data_to_str(port_wwn
, port_wwn_data
);
1297 if (strstr(pathname
, "@w") == NULL
) {
1299 * If the driver is detached, some part of the path
1300 * may be missing and so we'll manually construct it
1302 sprintf(&pathname
[strlen(pathname
)], "@w%s,%x",
1303 port_wwn
, *lunnump
);
1307 * Try to offline in RCM first and if that is successful,
1308 * unconfigure the LUN. If offlining in RCM fails, then
1309 * update the failure count
1311 * Here we got to check if unusable_flag is set or not.
1312 * If set, then unconfigure only those luns which are in
1313 * node_state DI_DEVICE_OFFLINE or DI_DEVICE_DOWN.
1314 * If not set, unconfigure all luns.
1316 if ((unusable_flag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
1317 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
1318 if ((dnode
->node_state
== DI_DEVICE_OFFLINE
) ||
1319 (dnode
->node_state
== DI_DEVICE_DOWN
)) {
1320 if (fp_rcm_offline(pathname
, errstring
,
1323 dnode
= di_sibling_node(dnode
);
1325 } else if (lun_unconf(pathname
, *lunnump
,
1326 xport_phys
,dyncomp
, errstring
)
1328 (void) fp_rcm_online(pathname
,
1331 dnode
= di_sibling_node(dnode
);
1333 } else if (fp_rcm_remove(pathname
, errstring
,
1336 * Bring everything back online
1337 * in rcm and continue
1339 (void) fp_rcm_online(pathname
,
1342 dnode
= di_sibling_node(dnode
);
1346 dnode
= di_sibling_node(dnode
);
1350 if (fp_rcm_offline(pathname
, errstring
, flags
) != 0) {
1352 dnode
= di_sibling_node(dnode
);
1354 } else if (lun_unconf(pathname
, *lunnump
, xport_phys
,
1355 dyncomp
, errstring
) != FPCFGA_OK
) {
1356 (void) fp_rcm_online(pathname
, NULL
, flags
);
1358 dnode
= di_sibling_node(dnode
);
1360 } else if (fp_rcm_remove(pathname
, errstring
,
1363 * Bring everything back online
1364 * in rcm and continue
1366 (void) fp_rcm_online(pathname
, NULL
, flags
);
1368 dnode
= di_sibling_node(dnode
);
1373 /* Update the repository only on a successful unconfigure */
1374 if ((update_str
= calloc(1, strlen(xport_phys
) +
1376 strlen(port_wwn
) + 1)) == NULL
) {
1377 cfga_err(errstring
, errno
, ERR_UNCONF_OK_UPD_REP
, 0);
1379 dnode
= di_sibling_node(dnode
);
1383 /* Init the string to be removed from repository */
1384 sprintf(update_str
, "%s%s%s", xport_phys
, DYN_SEP
, port_wwn
);
1386 if (update_fabric_wwn_list(REMOVE_ENTRY
, update_str
,
1389 cfga_err(errstring
, errno
, ERR_UNCONF_OK_UPD_REP
, 0);
1391 dnode
= di_sibling_node(dnode
);
1396 dnode
= di_sibling_node(dnode
);
1404 * apidt - Pointer to apid_t structure with data filled in
1405 * flags - Flags for special handling
1408 * errstring - Applicable only on a failure from plugin
1409 * num_devs - Incremented per lun
1410 * failure_count - Incremented on any failed operation on lun
1413 * non-FPCFGA_OK on any validation check error. If this value is returned, no
1414 * devices were handled. Consequently num_devs and failure_count
1415 * will not be incremented.
1416 * FPCFGA_OK This return value doesn't mean that all devices were successfully
1417 * unconfigured, you have to check failure_count.
1420 unconf_any_devinfo_nodes(apid_t
*apidt
, cfga_flags_t flags
, char **errstring
,
1421 int *num_devs
, int *failure_count
)
1423 char *node_path
= NULL
;
1424 char pathname
[MAXPATHLEN
], *ptr
; /* scratch pad */
1425 di_node_t root_node
, direct_node
, fp_node
;
1426 di_path_t path_node
= DI_PATH_NIL
;
1429 * apidt->xport_phys is something like :
1430 * /devices/pci@.../SUNW,qlc@../fp@0,0:fc
1431 * Make sure we copy both the devinfo and pathinfo nodes
1433 (void) strlcpy(pathname
, apidt
->xport_phys
, MAXPATHLEN
);
1435 /* Now get rid of the ':' at the end */
1436 if ((ptr
= strstr(pathname
, MINOR_SEP
)) != NULL
)
1439 if (strncmp(pathname
, DEVICES_DIR
, strlen(DEVICES_DIR
))) {
1440 cfga_err(errstring
, 0, ERRARG_INVALID_PATH
, pathname
, 0);
1441 return (FPCFGA_INVALID_PATH
);
1444 if ((root_node
= di_init("/", DINFOCPYALL
| DINFOPATH
)) ==
1446 cfga_err(errstring
, errno
, ERRARG_DEVINFO
,
1447 apidt
->xport_phys
, 0);
1448 return (FPCFGA_LIB_ERR
);
1451 if ((fp_node
= di_drv_first_node("fp", root_node
)) == DI_NODE_NIL
) {
1452 cfga_err(errstring
, errno
, ERRARG_DEVINFO
,
1453 apidt
->xport_phys
, 0);
1455 return (FPCFGA_LIB_ERR
);
1459 * Search all the fp nodes to see if any match the one we are trying
1463 /* Skip the "/devices" prefix */
1464 ptr
= pathname
+ strlen(DEVICES_DIR
);
1466 while (fp_node
!= DI_NODE_NIL
) {
1467 node_path
= di_devfs_path(fp_node
);
1468 if (strcmp(node_path
, ptr
) == 0) {
1469 /* Found the fp node. 'pathname' has the full path */
1470 di_devfs_path_free(node_path
);
1474 fp_node
= di_drv_next_node(fp_node
);
1475 di_devfs_path_free(node_path
);
1478 if (fp_node
== DI_NODE_NIL
) {
1479 cfga_err(errstring
, 0, ERRARG_NOT_IN_DEVINFO
,
1480 apidt
->xport_phys
, 0);
1482 return (FPCFGA_LIB_ERR
);
1485 direct_node
= di_child_node(fp_node
);
1486 path_node
= di_path_next_client(fp_node
, path_node
);
1488 if ((direct_node
== DI_NODE_NIL
) && (path_node
== DI_PATH_NIL
)) {
1489 /* No devinfo or pathinfo nodes. Great ! Just return success */
1494 /* First unconfigure any non-MPXIO nodes */
1495 unconf_non_vhci_nodes(direct_node
, apidt
->xport_phys
, apidt
->dyncomp
,
1496 apidt
->flags
, num_devs
, failure_count
, errstring
, flags
);
1499 * Now we will traverse any path info nodes that are there
1501 * Only MPXIO devices have pathinfo nodes
1503 unconf_vhci_nodes(path_node
, fp_node
, apidt
->xport_phys
, apidt
->dyncomp
,
1504 apidt
->flags
, num_devs
, failure_count
, errstring
, flags
);
1509 * We don't want to check the return value of unconf_non_vhci_nodes()
1510 * and unconf_vhci_nodes(). But instead, we are interested only in
1511 * consistently incrementing num_devs and failure_count so that we can
1518 * This function handles configuring/unconfiguring all the devices w.r.t
1519 * the FCA port specified by apidt.
1521 * In the unconfigure case, it first unconfigures all the devices that are
1522 * seen through the given port at that moment and then unconfigures all the
1523 * devices that still (somehow) have devinfo nodes on the system for that FCA
1527 * cmd - CFGA_CMD_CONFIGURE or CFGA_CMD_UNCONFIGURE
1528 * apidt - Pointer to apid_t structure with data filled in
1529 * flags - Flags for special handling
1532 * errstring - Applicable only on a failure from plugin
1535 * FPCFGA_OK on success
1536 * non-FPCFGA_OK otherwise
1539 handle_devs(cfga_cmd_t cmd
, apid_t
*apidt
, cfga_flags_t flags
,
1540 char **errstring
, HBA_HANDLE handle
, int portIndex
,
1541 HBA_PORTATTRIBUTES portAttrs
)
1543 int num_devs
= 0, dev_cs_failed
= 0;
1544 char port_wwn
[WWN_S_LEN
];
1546 apid_t my_apidt
= {NULL
};
1548 HBA_PORTATTRIBUTES discPortAttrs
;
1550 fpcfga_ret_t rval
= FPCFGA_OK
;
1552 if ((my_apid
= calloc(
1553 1, strlen(apidt
->xport_phys
) + strlen(DYN_SEP
) +
1554 (2 * FC_WWN_SIZE
) + 1)) == NULL
) {
1555 cfga_err(errstring
, errno
, ERR_MEM_ALLOC
, 0);
1556 return (FPCFGA_LIB_ERR
);
1559 num_devs
= portAttrs
.NumberofDiscoveredPorts
;
1560 for (discIndex
= 0; discIndex
< portAttrs
.NumberofDiscoveredPorts
;
1562 if (getDiscPortAttrs(handle
, portIndex
,
1563 discIndex
, &discPortAttrs
)) {
1565 /* Move on to the next target */
1568 (void) sprintf(port_wwn
, "%016llx",
1569 wwnConversion(discPortAttrs
.PortWWN
.wwn
));
1571 * Construct a fake apid string similar to the one the
1572 * plugin gets from the framework and have apidt_create()
1573 * fill in the apid_t structure.
1575 strcpy(my_apid
, apidt
->xport_phys
);
1576 strcat(my_apid
, DYN_SEP
);
1577 strcat(my_apid
, port_wwn
);
1578 if (apidt_create(my_apid
, &my_apidt
, errstring
) != FPCFGA_OK
) {
1582 my_apidt
.flags
= apidt
->flags
;
1584 memcpy(&pwwn
, &(discPortAttrs
.PortWWN
), sizeof (la_wwn_t
));
1585 if (dev_change_state(cmd
, &my_apidt
, &pwwn
,
1586 flags
, errstring
, handle
, portAttrs
) != FPCFGA_OK
) {
1589 apidt_free(&my_apidt
);
1595 * We have now handled all the devices that are currently visible
1596 * through the given FCA port. But, it is possible that there are
1597 * some devinfo nodes hanging around. For the unconfigure operation,
1598 * this has to be looked into too.
1600 if (cmd
== CFGA_CMD_UNCONFIGURE
) {
1601 /* dev_cs_failed will be updated to indicate any failures */
1602 rval
= unconf_any_devinfo_nodes(apidt
, flags
, errstring
,
1603 &num_devs
, &dev_cs_failed
);
1606 if (rval
== FPCFGA_OK
) {
1607 if (dev_cs_failed
== 0)
1611 * For the discovered ports, num_devs is counted on target
1612 * basis, but for invisible targets, num_devs is counted on
1615 * But if dev_cs_failed and num_devs are incremented
1616 * consistently, comparation of these two counters is still
1619 if (dev_cs_failed
== num_devs
) {
1620 /* Failed on all devices seen through this FCA port */
1621 cfga_err(errstring
, 0,
1622 ((cmd
== CFGA_CMD_CONFIGURE
) ?
1623 ERR_FCA_CONFIGURE
: ERR_FCA_UNCONFIGURE
), 0);
1624 return (FPCFGA_LIB_ERR
);
1626 /* Failed only on some of the devices */
1627 cfga_err(errstring
, 0, ERR_PARTIAL_SUCCESS
, 0);
1628 return (FPCFGA_LIB_ERR
);
1631 if (dev_cs_failed
== num_devs
) {
1632 /* Failed on all devices seen through this FCA port */
1633 cfga_err(errstring
, 0,
1634 ((cmd
== CFGA_CMD_CONFIGURE
) ?
1635 ERR_FCA_CONFIGURE
: ERR_FCA_UNCONFIGURE
), 0);
1636 return (FPCFGA_LIB_ERR
);
1638 /* Failed only on some of the devices */
1639 cfga_err(errstring
, 0, ERR_PARTIAL_SUCCESS
, 0);
1640 return (FPCFGA_LIB_ERR
);
1645 * Should never get here
1650 fca_change_state(cfga_cmd_t state_change_cmd
, apid_t
*apidt
,
1651 cfga_flags_t flags
, char **errstring
)
1655 HBA_PORTATTRIBUTES portAttrs
;
1658 if ((ret
= findMatchingAdapterPort(apidt
->xport_phys
, &handle
,
1659 &portIndex
, &portAttrs
, errstring
)) != FPCFGA_OK
) {
1664 * Bail out if not fabric/public loop
1666 switch (state_change_cmd
) {
1667 case CFGA_CMD_CONFIGURE
:
1668 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
1669 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
1670 HBA_CloseAdapter(handle
);
1676 case CFGA_CMD_UNCONFIGURE
:
1677 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
1678 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
1679 HBA_CloseAdapter(handle
);
1681 return (FPCFGA_OPNOTSUPP
);
1685 HBA_CloseAdapter(handle
);
1687 return (FPCFGA_LIB_ERR
);
1689 ret
= (handle_devs(state_change_cmd
, apidt
, flags
, errstring
,
1690 handle
, portIndex
, portAttrs
));
1691 HBA_CloseAdapter(handle
);