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
)) !=
456 if ((lunlistp
->node_state
&
457 DI_DEVICE_OFFLINE
) == DI_DEVICE_OFFLINE
) {
459 if ((ret
= lun_unconf(lunlistp
->path
,
460 lunlistp
->lunnum
, apidt
->xport_phys
,
461 apidt
->dyncomp
, errstring
)) !=
469 * Unconfigure each LUN.
470 * Note that for MPXIO devices, lunlistp->path will be a
473 if ((ret
= lun_unconf(lunlistp
->path
, lunlistp
->lunnum
,
474 apidt
->xport_phys
, apidt
->dyncomp
,
475 errstring
)) != FPCFGA_OK
) {
481 if ((apidt
->flags
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
482 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
484 * when all luns are unconfigured
485 * indicate to remove repository entry.
487 if (lun_cnt
== unusable_lun_cnt
) {
488 *flag
= ALL_APID_LUNS_UNUSABLE
;
496 * Check if the given physical path (the xport_phys) is part of the
497 * pHCI list and if the RCM should be done for a particular pHCI.
498 * Skip non-MPxIO dev node if any.
501 is_xport_phys_in_pathlist(apid_t
*apidt
, char **errstring
)
503 di_node_t root
, vhci
, node
, phci
;
504 di_path_t path
= DI_PATH_NIL
;
505 int num_active_paths
, found
= 0;
506 char *vhci_path_ptr
, *pathname_ptr
, pathname
[MAXPATHLEN
];
507 char *phci_path
, *node_path
;
508 char phci_addr
[MAXPATHLEN
];
509 char *xport_phys
, *vhci_path
, *dyncomp
;
510 luninfo_list_t
*lunlistp
, *temp
;
511 int non_operational_path_count
;
514 if ((apidt
->dyncomp
== NULL
) || (*apidt
->dyncomp
== '\0')) {
515 return (FPCFGA_LIB_ERR
);
518 xport_phys
= apidt
->xport_phys
;
519 dyncomp
= apidt
->dyncomp
;
521 lunlistp
= apidt
->lunlist
;
522 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
523 lunlistp
= lunlistp
->next
) {
525 if (strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
526 strlen(SCSI_VHCI_ROOT
)) != 0) {
527 lunlistp
->lun_flag
|= FLAG_SKIP_ONLINEOTHERS
;
531 vhci_path
= lunlistp
->path
;
533 num_active_paths
= 0; /* # of paths in ONLINE/STANDBY */
534 non_operational_path_count
= 0;
536 if (xport_phys
== NULL
|| vhci_path
== NULL
) {
537 cfga_err(errstring
, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST
,
539 return (FPCFGA_LIB_ERR
);
542 (void) strlcpy(pathname
, xport_phys
, MAXPATHLEN
);
543 if ((pathname_ptr
= strrchr(pathname
, ':')) != NULL
) {
544 *pathname_ptr
= '\0';
546 /* strip off the /devices/from the path */
547 pathname_ptr
= pathname
+ strlen(DEVICES_DIR
);
549 root
= di_init("/", DINFOCPYALL
|DINFOPATH
);
551 if (root
== DI_NODE_NIL
) {
552 return (FPCFGA_LIB_ERR
);
555 vhci_path_ptr
= vhci_path
+ strlen(DEVICES_DIR
);
556 if ((vhci
= di_drv_first_node(SCSI_VHCI_DRVR
, root
)) ==
558 return (FPCFGA_LIB_ERR
);
561 for (node
= di_child_node(vhci
); node
!= DI_NODE_NIL
;
562 node
= di_sibling_node(node
)) {
563 if ((node_path
= di_devfs_path(node
)) != NULL
) {
564 if (strncmp(vhci_path_ptr
, node_path
,
565 strlen(node_path
)) != 0) {
566 di_devfs_path_free(node_path
);
574 cfga_err(errstring
, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST
,
577 return (FPCFGA_LIB_ERR
);
579 /* found vhci_path we are looking for */
580 di_devfs_path_free(node_path
);
582 for (path
= di_path_next_phci(node
, DI_PATH_NIL
);
584 path
= di_path_next_phci(node
, path
)) {
585 if ((phci
= di_path_phci_node(path
)) == DI_NODE_NIL
) {
586 cfga_err(errstring
, 0,
587 ERRARG_XPORT_NOT_IN_PHCI_LIST
,
590 return (FPCFGA_LIB_ERR
);
592 if ((phci_path
= di_devfs_path(phci
)) == NULL
) {
593 cfga_err(errstring
, 0,
594 ERRARG_XPORT_NOT_IN_PHCI_LIST
,
597 return (FPCFGA_LIB_ERR
);
599 (void) di_path_addr(path
, (char *)phci_addr
);
600 if ((phci_addr
== NULL
) || (*phci_addr
== '\0')) {
601 cfga_err(errstring
, 0,
602 ERRARG_XPORT_NOT_IN_PHCI_LIST
,
604 di_devfs_path_free(phci_path
);
606 return (FPCFGA_LIB_ERR
);
609 * Check if the phci path has the same
610 * xport addr and the target addr with current lun
612 if ((strncmp(phci_path
, pathname_ptr
,
613 strlen(pathname_ptr
)) == 0) &&
614 (strstr(phci_addr
, dyncomp
) != NULL
)) {
615 /* SUCCESS Found xport_phys */
617 } else if ((di_path_state(path
) ==
618 DI_PATH_STATE_ONLINE
) ||
619 (di_path_state(path
) == DI_PATH_STATE_STANDBY
)) {
623 * We have another path not in ONLINE/STANDBY
624 * state now, so should do a RCM online after
625 * the unconfiguration of current path.
627 non_operational_path_count
++;
629 di_devfs_path_free(phci_path
);
633 if (num_active_paths
!= 0) {
635 * There are other ONLINE/STANDBY paths,
636 * so no need to do the RCM
638 lunlistp
->lun_flag
|= FLAG_SKIP_RCMREMOVE
;
639 lunlistp
->lun_flag
|= FLAG_SKIP_RCMOFFLINE
;
641 if (non_operational_path_count
== 0) {
642 lunlistp
->lun_flag
|= FLAG_SKIP_ONLINEOTHERS
;
646 * Fail all operations here
648 cfga_err(errstring
, 0, ERRARG_XPORT_NOT_IN_PHCI_LIST
,
650 return (FPCFGA_APID_NOEXIST
);
654 /* Mark duplicated paths for same vhci in the list */
655 for (lunlistp
= apidt
->lunlist
; lunlistp
!= NULL
;
656 lunlistp
= lunlistp
->next
) {
657 if (strncmp(lunlistp
->path
, SCSI_VHCI_ROOT
,
658 strlen(SCSI_VHCI_ROOT
)) != 0) {
661 for (temp
= lunlistp
->next
; temp
!= NULL
;
663 if (strcmp(lunlistp
->path
, temp
->path
) == 0) {
665 * don't do RCM for dup
667 lunlistp
->lun_flag
|= FLAG_SKIP_RCMREMOVE
;
668 lunlistp
->lun_flag
|= FLAG_SKIP_RCMOFFLINE
;
669 lunlistp
->lun_flag
|= FLAG_SKIP_ONLINEOTHERS
;
676 * apidt->dyncomp has to be non-NULL by the time this routine is called
679 dev_change_state(cfga_cmd_t state_change_cmd
, apid_t
*apidt
, la_wwn_t
*pwwn
,
680 cfga_flags_t flags
, char **errstring
, HBA_HANDLE handle
,
681 HBA_PORTATTRIBUTES portAttrs
)
683 char dev_path
[MAXPATHLEN
];
684 char *update_str
, *t_apid
;
685 int optflag
= apidt
->flags
;
686 int no_config_attempt
= 0;
689 uchar_t unconf_flag
= 0, peri_qual
;
691 HBA_PORTATTRIBUTES discPortAttrs
;
693 struct scsi_inquiry inq
;
694 struct scsi_extended_sense sense
;
695 HBA_UINT8 scsiStatus
;
696 uint32_t inquirySize
= sizeof (inq
),
697 senseSize
= sizeof (sense
);
698 report_lun_resp_t
*resp_buf
;
699 int i
, l_errno
, num_luns
= 0;
702 if ((apidt
->dyncomp
== NULL
) || (*apidt
->dyncomp
== '\0')) {
704 * No dynamic component specified. Just return success.
705 * Should not see this case. Just a safety check.
710 /* Now construct the string we are going to put in the repository */
711 if ((update_str
= calloc(1, (strlen(apidt
->xport_phys
) +
712 strlen(DYN_SEP
) + strlen(apidt
->dyncomp
) + 1))) == NULL
) {
713 cfga_err(errstring
, errno
, ERR_MEM_ALLOC
, 0);
714 return (FPCFGA_LIB_ERR
);
716 strcpy(update_str
, apidt
->xport_phys
);
717 strcat(update_str
, DYN_SEP
);
718 strcat(update_str
, apidt
->dyncomp
);
720 /* If force update of repository is sought, do it first */
721 if (optflag
& FLAG_FORCE_UPDATE_REP
) {
722 /* Ignore any failure in rep update */
723 (void) update_fabric_wwn_list(
724 ((state_change_cmd
== CFGA_CMD_CONFIGURE
) ?
725 ADD_ENTRY
: REMOVE_ENTRY
),
726 update_str
, errstring
);
729 memset(&sense
, 0, sizeof (sense
));
730 if ((ret
= get_report_lun_data(apidt
->xport_phys
, apidt
->dyncomp
,
731 &num_luns
, &resp_buf
, &sense
, &l_errno
)) != FPCFGA_OK
) {
733 * Checking the sense key data as well as the additional
734 * sense key. The SES Node is not required to repond
735 * to Report LUN. In the case of Minnow, the SES node
736 * returns with KEY_ILLEGAL_REQUEST and the additional
737 * sense key of 0x20. In this case we will blindly
738 * send the SCSI Inquiry call to lun 0
740 * if we get any other error we will set the inq_type
743 if ((sense
.es_key
== KEY_ILLEGAL_REQUEST
) &&
744 (sense
.es_add_code
== 0x20)) {
747 if (ret
== FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT
) {
748 inq
.inq_dtype
= DTYPE_UNKNOWN
;
751 * Failed to get the LUN data for the device
752 * If we find that there is a lunlist for this
753 * device it could mean that there are dangling
754 * devinfo nodes. So, we will go ahead and try
755 * to unconfigure them.
757 if ((apidt
->lunlist
== NULL
) ||
758 (state_change_cmd
== CFGA_CMD_CONFIGURE
)) {
760 status
= getPortAttrsByWWN(handle
,
761 *((HBA_WWN
*)(pwwn
)),
764 HBA_STATUS_ERROR_ILLEGAL_WWN
) {
765 return (FPCFGA_APID_NOEXIST
);
767 cfga_err(errstring
, 0,
770 return (FPCFGA_LIB_ERR
);
773 /* unconfig with lunlist not empty */
779 for (i
= 0; i
< num_luns
; i
++) {
781 * issue the inquiry to the first valid lun found
784 lun_string
= (uchar_t
*)&(resp_buf
->lun_string
[i
]);
785 memcpy(&lun
, lun_string
, sizeof (lun
));
787 memset(&sense
, 0, sizeof (sense
));
788 status
= HBA_ScsiInquiryV2(handle
, portAttrs
.PortWWN
,
789 *(HBA_WWN
*)(pwwn
), lun
, 0, 0, &inq
, &inquirySize
,
790 &scsiStatus
, &sense
, &senseSize
);
792 * if Inquiry is returned correctly, check the
793 * peripheral qualifier for the lun. if it is non-zero
794 * then try the SCSI Inquiry on the next lun
796 if (status
== HBA_STATUS_OK
) {
797 peri_qual
= inq
.inq_dtype
& FP_PERI_QUAL_MASK
;
798 if (peri_qual
== DPQ_POSSIBLE
) {
804 if (ret
== FPCFGA_OK
)
808 * If there are no luns on this target, we will attempt to send
809 * the SCSI Inquiry to lun 0
813 status
= HBA_ScsiInquiryV2(handle
, portAttrs
.PortWWN
,
814 *(HBA_WWN
*)(pwwn
), lun
, 0, 0, &inq
, &inquirySize
,
815 &scsiStatus
, &sense
, &senseSize
);
818 if (status
!= HBA_STATUS_OK
) {
819 if (status
== HBA_STATUS_ERROR_NOT_A_TARGET
) {
820 inq
.inq_dtype
= DTYPE_UNKNOWN
;
821 } else if (status
== HBA_STATUS_ERROR_ILLEGAL_WWN
) {
823 return (FPCFGA_APID_NOEXIST
);
826 * Failed to get the inq_dtype of device
827 * If we find that there is a lunlist for this
828 * device it could mean that there dangling
829 * devinfo nodes. So, we will go ahead and try
830 * to unconfigure them. We'll just set the
831 * inq_dtype to some invalid value (0xFF)
833 if ((apidt
->lunlist
== NULL
) ||
834 (state_change_cmd
== CFGA_CMD_CONFIGURE
)) {
835 cfga_err(errstring
, 0,
839 return (FPCFGA_LIB_ERR
);
841 /* unconfig with lunlist not empty */
846 switch (state_change_cmd
) {
847 case CFGA_CMD_CONFIGURE
:
848 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
849 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
854 if (((inq
.inq_dtype
& DTYPE_MASK
) == DTYPE_UNKNOWN
) &&
855 ((flags
& CFGA_FLAG_FORCE
) == 0)) {
857 * We assume all DTYPE_UNKNOWNs are HBAs and we wont
858 * waste time trying to config them. If they are not
859 * HBAs, then there is something wrong since they should
860 * have had a valid dtype.
862 * However, if the force flag is set (cfgadm -f), we
863 * go ahead and try to configure.
865 * In this path, however, the force flag is not set.
873 * We'll issue the devctl_bus_dev_create() call even if the
874 * path exists in the devinfo tree. This is to take care of
875 * the situation where the device may be in a state other
876 * than the online and attached state.
878 if ((ret
= do_devctl_dev_create(apidt
, dev_path
, MAXPATHLEN
,
879 inq
.inq_dtype
, errstring
)) != FPCFGA_OK
) {
881 * Could not configure device. To provide a more
882 * meaningful error message, first see if the supplied port
883 * WWN is there on the fabric. Otherwise print the error
884 * message using the information received from the driver
886 status
= getPortAttrsByWWN(handle
, *((HBA_WWN
*)(pwwn
)),
889 if (status
== HBA_STATUS_ERROR_ILLEGAL_WWN
) {
890 return (FPCFGA_APID_NOEXIST
);
892 return (FPCFGA_LIB_ERR
);
896 if (!(optflag
& (FLAG_FORCE_UPDATE_REP
|FLAG_NO_UPDATE_REP
)) &&
897 update_fabric_wwn_list(ADD_ENTRY
, update_str
, errstring
)) {
898 cfga_err(errstring
, 0, ERR_CONF_OK_UPD_REP
, 0);
903 if ((apidt
->flags
& FLAG_DISABLE_RCM
) == 0) {
905 * There may be multiple LUNs associated with the
906 * WWN we created nodes for. So, we'll call
907 * apidt_create() again and let it build a list of
908 * all the LUNs for this WWN using the devinfo tree.
909 * We will then online all those devices in RCM
911 if ((t_apid
= calloc(1, strlen(apidt
->xport_phys
) +
913 strlen(apidt
->dyncomp
) + 1)) == NULL
) {
914 cfga_err(errstring
, errno
, ERR_MEM_ALLOC
, 0);
915 return (FPCFGA_LIB_ERR
);
917 sprintf(t_apid
, "%s%s%s", apidt
->xport_phys
, DYN_SEP
,
919 if ((ret
= apidt_create(t_apid
, &my_apidt
,
920 errstring
)) != FPCFGA_OK
) {
925 my_apidt
.flags
= apidt
->flags
;
926 if ((ret
= dev_rcm_online(&my_apidt
, -1, flags
,
927 NULL
)) != FPCFGA_OK
) {
928 cfga_err(errstring
, 0, ERRARG_RCM_ONLINE
,
929 apidt
->lunlist
->path
, 0);
930 apidt_free(&my_apidt
);
935 apidt_free(&my_apidt
);
939 case CFGA_CMD_UNCONFIGURE
:
940 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
941 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
943 return (FPCFGA_OPNOTSUPP
);
946 status
= getPortAttrsByWWN(handle
, *((HBA_WWN
*)(pwwn
)),
948 if (apidt
->lunlist
== NULL
) {
950 * But first, remove entry from the repository if it is
951 * there ... provided the force update flag is not set
952 * (in which case the update is already done) or if
953 * the no-update flag is not set.
956 (FLAG_FORCE_UPDATE_REP
|FLAG_NO_UPDATE_REP
)) == 0) {
957 if (update_fabric_wwn_list(REMOVE_ENTRY
,
958 update_str
, errstring
)) {
960 cfga_err(errstring
, 0,
961 ERR_UNCONF_OK_UPD_REP
, 0);
963 (FPCFGA_UNCONF_OK_UPD_REP_FAILED
);
967 if (status
== HBA_STATUS_ERROR_ILLEGAL_WWN
) {
968 return (FPCFGA_APID_NOEXIST
);
973 * If there are multiple paths to the mpxio
974 * device, we will not check in RCM ONLY when there
975 * is atleast one other ONLINE/STANDBY path
977 if (is_xport_phys_in_pathlist(apidt
, errstring
) !=
980 return (FPCFGA_XPORT_NOT_IN_PHCI_LIST
);
984 * dev_rcm_offline() updates errstring
986 if ((ret
= dev_rcm_offline(apidt
, flags
, errstring
)) !=
991 if ((ret
= dev_unconf(apidt
, errstring
, &unconf_flag
)) !=
993 /* when inq failed don't attempt to reconfigure */
994 if (!no_config_attempt
) {
995 (void) do_devctl_dev_create(apidt
, dev_path
,
996 MAXPATHLEN
, inq
.inq_dtype
, NULL
);
997 (void) dev_rcm_online(apidt
, -1, flags
, NULL
);
1002 if ((ret
= dev_rcm_remove(apidt
, flags
, errstring
)) !=
1004 (void) do_devctl_dev_create(apidt
, dev_path
, MAXPATHLEN
,
1005 inq
.inq_dtype
, NULL
);
1006 (void) dev_rcm_online(apidt
, -1, flags
, NULL
);
1011 * If we offlined a lun in RCM when there are multiple paths but
1012 * none of them are ONLINE/STANDBY, we have to online it back
1013 * in RCM now. This is a try best, will not fail for it.
1015 dev_rcm_online_nonoperationalpath(apidt
, flags
, NULL
);
1017 /* Update the repository if we havent already done it */
1019 (FLAG_FORCE_UPDATE_REP
|FLAG_NO_UPDATE_REP
)) == 0) {
1020 if (((optflag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) !=
1021 FLAG_REMOVE_UNUSABLE_FCP_DEV
) ||
1022 (((optflag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
1023 FLAG_REMOVE_UNUSABLE_FCP_DEV
) &&
1024 (unconf_flag
== ALL_APID_LUNS_UNUSABLE
))) {
1025 if (update_fabric_wwn_list(REMOVE_ENTRY
,
1026 update_str
, errstring
)) {
1028 cfga_err(errstring
, errno
,
1029 ERR_UNCONF_OK_UPD_REP
, 0);
1031 (FPCFGA_UNCONF_OK_UPD_REP_FAILED
);
1040 return (FPCFGA_OPNOTSUPP
);
1045 * This function copies a port_wwn got by reading the property on a device
1046 * node (from_ptr in the function below) on to an array (to_ptr) so that it is
1049 * Caller responsible to allocate enough memory in "to_ptr"
1052 copy_pwwn_data_to_str(char *to_ptr
, const uchar_t
*from_ptr
)
1054 if ((to_ptr
== NULL
) || (from_ptr
== NULL
))
1057 (void) sprintf(to_ptr
, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1058 from_ptr
[0], from_ptr
[1], from_ptr
[2], from_ptr
[3],
1059 from_ptr
[4], from_ptr
[5], from_ptr
[6], from_ptr
[7]);
1063 unconf_vhci_nodes(di_path_t pnode
, di_node_t fp_node
, char *xport_phys
,
1064 char *dyncomp
, int unusable_flag
,
1065 int *num_devs
, int *failure_count
, char **errstring
,
1068 int iret1
, iret2
, *lunnump
;
1069 char *ptr
; /* scratch pad */
1070 char *node_path
, *vhci_path
, *update_str
;
1071 char port_wwn
[WWN_SIZE
*2+1], pathname
[MAXPATHLEN
];
1072 uchar_t
*port_wwn_data
= NULL
;
1073 di_node_t client_node
;
1075 while (pnode
!= DI_PATH_NIL
) {
1080 if ((node_path
= di_devfs_path(fp_node
)) == NULL
) {
1081 cfga_err(errstring
, 0, ERRARG_DEVINFO
,
1084 pnode
= di_path_next_client(fp_node
, pnode
);
1088 iret1
= di_path_prop_lookup_bytes(pnode
, PORT_WWN_PROP
,
1091 iret2
= di_path_prop_lookup_ints(pnode
, LUN_PROP
, &lunnump
);
1093 if ((iret1
== -1) || (iret2
== -1)) {
1094 cfga_err(errstring
, 0, ERRARG_DI_GET_PROP
,
1096 di_devfs_path_free(node_path
);
1099 pnode
= di_path_next_client(fp_node
, pnode
);
1103 copy_pwwn_data_to_str(port_wwn
, port_wwn_data
);
1105 if ((client_node
= di_path_client_node(pnode
)) == DI_NODE_NIL
) {
1107 di_devfs_path_free(node_path
);
1109 pnode
= di_path_next_client(fp_node
, pnode
);
1113 if ((vhci_path
= di_devfs_path(client_node
)) == NULL
) {
1115 di_devfs_path_free(node_path
);
1117 pnode
= di_path_next_client(fp_node
, pnode
);
1121 if ((ptr
= strrchr(vhci_path
, '@')) != NULL
) {
1125 if ((ptr
= strrchr(vhci_path
, '/')) == NULL
) {
1127 di_devfs_path_free(node_path
);
1129 pnode
= di_path_next_client(fp_node
, pnode
);
1133 sprintf(pathname
, "%s%s/%s@w%s,%x", DEVICES_DIR
, node_path
,
1134 ++ptr
, port_wwn
, *lunnump
);
1136 di_devfs_path_free(node_path
);
1137 di_devfs_path_free(vhci_path
);
1138 node_path
= vhci_path
= NULL
;
1141 * Try to offline in RCM first and if that is successful,
1142 * unconfigure the LUN. If offlining in RCM fails, then
1143 * update the failure_count which gets passed back to caller
1145 * Here we got to check if unusable_flag is set or not.
1146 * If set, then unconfigure only those luns which are in
1147 * node_state DI_PATH_STATE_OFFLINE. If not set, unconfigure
1150 if ((unusable_flag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
1151 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
1152 if (pnode
->path_state
== DI_PATH_STATE_OFFLINE
) {
1153 if (fp_rcm_offline(pathname
, errstring
,
1156 pnode
= di_path_next_client(fp_node
,
1159 } else if (lun_unconf(pathname
, *lunnump
,
1160 xport_phys
, dyncomp
, errstring
)
1162 (void) fp_rcm_online(pathname
,
1165 pnode
= di_path_next_client(fp_node
,
1168 } else if (fp_rcm_remove(pathname
, errstring
,
1171 * Bring everything back online
1172 * in rcm and continue
1174 (void) fp_rcm_online(pathname
,
1177 pnode
= di_path_next_client(fp_node
,
1182 pnode
= di_path_next(fp_node
, pnode
);
1186 if (fp_rcm_offline(pathname
, errstring
, flags
) != 0) {
1188 pnode
= di_path_next_client(fp_node
, pnode
);
1190 } else if (lun_unconf(pathname
, *lunnump
, xport_phys
,
1191 dyncomp
, errstring
) != FPCFGA_OK
) {
1192 (void) fp_rcm_online(pathname
, NULL
, flags
);
1194 pnode
= di_path_next_client(fp_node
, pnode
);
1196 } else if (fp_rcm_remove(pathname
, errstring
,
1199 * Bring everything back online
1200 * in rcm and continue
1202 (void) fp_rcm_online(pathname
, NULL
, flags
);
1204 pnode
= di_path_next_client(fp_node
, pnode
);
1209 /* Update the repository only on a successful unconfigure */
1210 if ((update_str
= calloc(1, strlen(xport_phys
) +
1211 strlen(DYN_SEP
) + strlen(port_wwn
) + 1)) == NULL
) {
1212 cfga_err(errstring
, errno
, ERR_UNCONF_OK_UPD_REP
, 0);
1214 pnode
= di_path_next_client(fp_node
, pnode
);
1218 /* Init the string to be removed from repository */
1219 sprintf(update_str
, "%s%s%s", xport_phys
, DYN_SEP
, port_wwn
);
1221 if (update_fabric_wwn_list(REMOVE_ENTRY
, update_str
,
1224 cfga_err(errstring
, errno
,
1225 ERR_UNCONF_OK_UPD_REP
, 0);
1227 /* Cleanup and continue from here just for clarity */
1228 pnode
= di_path_next_client(fp_node
, pnode
);
1233 pnode
= di_path_next_client(fp_node
, pnode
);
1240 unconf_non_vhci_nodes(di_node_t dnode
, char *xport_phys
, char *dyncomp
,
1241 int unusable_flag
, int *num_devs
, int *failure_count
,
1242 char **errstring
, cfga_flags_t flags
)
1244 int ret1
, ret2
, *lunnump
;
1245 char pathname
[MAXPATHLEN
];
1246 char *node_path
, *update_str
;
1247 char port_wwn
[WWN_SIZE
*2+1];
1248 uchar_t
*port_wwn_data
= NULL
;
1250 while (dnode
!= DI_NODE_NIL
) {
1254 /* Get the physical path for this node */
1255 if ((node_path
= di_devfs_path(dnode
)) == NULL
) {
1257 * We don't try to offline in RCM here because we
1258 * don't know the path to offline. Just continue to
1261 cfga_err(errstring
, 0, ERRARG_DEVINFO
, xport_phys
, 0);
1263 dnode
= di_sibling_node(dnode
);
1267 /* Now get the LUN # of this device thru the property */
1268 ret1
= di_prop_lookup_ints(DDI_DEV_T_ANY
, dnode
,
1269 LUN_PROP
, &lunnump
);
1271 /* Next get the port WWN of the device */
1272 ret2
= di_prop_lookup_bytes(DDI_DEV_T_ANY
, dnode
,
1273 PORT_WWN_PROP
, &port_wwn_data
);
1275 /* A failure in any of the above is not good */
1276 if ((ret1
== -1) || (ret2
== -1)) {
1278 * We don't try to offline in RCM here because we
1279 * don't know the path to offline. Just continue to
1282 cfga_err(errstring
, 0,
1283 ERRARG_DI_GET_PROP
, node_path
, 0);
1284 di_devfs_path_free(node_path
);
1287 dnode
= di_sibling_node(dnode
);
1291 /* Prepend the "/devices" prefix to the path and copy it */
1292 sprintf(pathname
, "%s%s", DEVICES_DIR
, node_path
);
1293 di_devfs_path_free(node_path
);
1296 copy_pwwn_data_to_str(port_wwn
, port_wwn_data
);
1298 if (strstr(pathname
, "@w") == NULL
) {
1300 * If the driver is detached, some part of the path
1301 * may be missing and so we'll manually construct it
1303 sprintf(&pathname
[strlen(pathname
)], "@w%s,%x",
1304 port_wwn
, *lunnump
);
1308 * Try to offline in RCM first and if that is successful,
1309 * unconfigure the LUN. If offlining in RCM fails, then
1310 * update the failure count
1312 * Here we got to check if unusable_flag is set or not.
1313 * If set, then unconfigure only those luns which are in
1314 * node_state DI_DEVICE_OFFLINE or DI_DEVICE_DOWN.
1315 * If not set, unconfigure all luns.
1317 if ((unusable_flag
& FLAG_REMOVE_UNUSABLE_FCP_DEV
) ==
1318 FLAG_REMOVE_UNUSABLE_FCP_DEV
) {
1319 if ((dnode
->node_state
== DI_DEVICE_OFFLINE
) ||
1320 (dnode
->node_state
== DI_DEVICE_DOWN
)) {
1321 if (fp_rcm_offline(pathname
, errstring
,
1324 dnode
= di_sibling_node(dnode
);
1326 } else if (lun_unconf(pathname
, *lunnump
,
1327 xport_phys
, dyncomp
, errstring
)
1329 (void) fp_rcm_online(pathname
,
1332 dnode
= di_sibling_node(dnode
);
1334 } else if (fp_rcm_remove(pathname
, errstring
,
1337 * Bring everything back online
1338 * in rcm and continue
1340 (void) fp_rcm_online(pathname
,
1343 dnode
= di_sibling_node(dnode
);
1347 dnode
= di_sibling_node(dnode
);
1351 if (fp_rcm_offline(pathname
, errstring
, flags
) != 0) {
1353 dnode
= di_sibling_node(dnode
);
1355 } else if (lun_unconf(pathname
, *lunnump
, xport_phys
,
1356 dyncomp
, errstring
) != FPCFGA_OK
) {
1357 (void) fp_rcm_online(pathname
, NULL
, flags
);
1359 dnode
= di_sibling_node(dnode
);
1361 } else if (fp_rcm_remove(pathname
, errstring
,
1364 * Bring everything back online
1365 * in rcm and continue
1367 (void) fp_rcm_online(pathname
, NULL
, flags
);
1369 dnode
= di_sibling_node(dnode
);
1374 /* Update the repository only on a successful unconfigure */
1375 if ((update_str
= calloc(1, strlen(xport_phys
) +
1377 strlen(port_wwn
) + 1)) == NULL
) {
1378 cfga_err(errstring
, errno
, ERR_UNCONF_OK_UPD_REP
, 0);
1380 dnode
= di_sibling_node(dnode
);
1384 /* Init the string to be removed from repository */
1385 sprintf(update_str
, "%s%s%s", xport_phys
, DYN_SEP
, port_wwn
);
1387 if (update_fabric_wwn_list(REMOVE_ENTRY
, update_str
,
1390 cfga_err(errstring
, errno
, ERR_UNCONF_OK_UPD_REP
, 0);
1392 dnode
= di_sibling_node(dnode
);
1397 dnode
= di_sibling_node(dnode
);
1405 * apidt - Pointer to apid_t structure with data filled in
1406 * flags - Flags for special handling
1409 * errstring - Applicable only on a failure from plugin
1410 * num_devs - Incremented per lun
1411 * failure_count - Incremented on any failed operation on lun
1414 * non-FPCFGA_OK on any validation check error. If this value is returned, no
1415 * devices were handled. Consequently num_devs and failure_count
1416 * will not be incremented.
1417 * FPCFGA_OK This return value doesn't mean that all devices were successfully
1418 * unconfigured, you have to check failure_count.
1421 unconf_any_devinfo_nodes(apid_t
*apidt
, cfga_flags_t flags
, char **errstring
,
1422 int *num_devs
, int *failure_count
)
1424 char *node_path
= NULL
;
1425 char pathname
[MAXPATHLEN
], *ptr
; /* scratch pad */
1426 di_node_t root_node
, direct_node
, fp_node
;
1427 di_path_t path_node
= DI_PATH_NIL
;
1430 * apidt->xport_phys is something like :
1431 * /devices/pci@.../SUNW,qlc@../fp@0,0:fc
1432 * Make sure we copy both the devinfo and pathinfo nodes
1434 (void) strlcpy(pathname
, apidt
->xport_phys
, MAXPATHLEN
);
1436 /* Now get rid of the ':' at the end */
1437 if ((ptr
= strstr(pathname
, MINOR_SEP
)) != NULL
)
1440 if (strncmp(pathname
, DEVICES_DIR
, strlen(DEVICES_DIR
))) {
1441 cfga_err(errstring
, 0, ERRARG_INVALID_PATH
, pathname
, 0);
1442 return (FPCFGA_INVALID_PATH
);
1445 if ((root_node
= di_init("/", DINFOCPYALL
| DINFOPATH
)) ==
1447 cfga_err(errstring
, errno
, ERRARG_DEVINFO
,
1448 apidt
->xport_phys
, 0);
1449 return (FPCFGA_LIB_ERR
);
1452 if ((fp_node
= di_drv_first_node("fp", root_node
)) == DI_NODE_NIL
) {
1453 cfga_err(errstring
, errno
, ERRARG_DEVINFO
,
1454 apidt
->xport_phys
, 0);
1456 return (FPCFGA_LIB_ERR
);
1460 * Search all the fp nodes to see if any match the one we are trying
1464 /* Skip the "/devices" prefix */
1465 ptr
= pathname
+ strlen(DEVICES_DIR
);
1467 while (fp_node
!= DI_NODE_NIL
) {
1468 node_path
= di_devfs_path(fp_node
);
1469 if (strcmp(node_path
, ptr
) == 0) {
1470 /* Found the fp node. 'pathname' has the full path */
1471 di_devfs_path_free(node_path
);
1475 fp_node
= di_drv_next_node(fp_node
);
1476 di_devfs_path_free(node_path
);
1479 if (fp_node
== DI_NODE_NIL
) {
1480 cfga_err(errstring
, 0, ERRARG_NOT_IN_DEVINFO
,
1481 apidt
->xport_phys
, 0);
1483 return (FPCFGA_LIB_ERR
);
1486 direct_node
= di_child_node(fp_node
);
1487 path_node
= di_path_next_client(fp_node
, path_node
);
1489 if ((direct_node
== DI_NODE_NIL
) && (path_node
== DI_PATH_NIL
)) {
1490 /* No devinfo or pathinfo nodes. Great ! Just return success */
1495 /* First unconfigure any non-MPXIO nodes */
1496 unconf_non_vhci_nodes(direct_node
, apidt
->xport_phys
, apidt
->dyncomp
,
1497 apidt
->flags
, num_devs
, failure_count
, errstring
, flags
);
1500 * Now we will traverse any path info nodes that are there
1502 * Only MPXIO devices have pathinfo nodes
1504 unconf_vhci_nodes(path_node
, fp_node
, apidt
->xport_phys
, apidt
->dyncomp
,
1505 apidt
->flags
, num_devs
, failure_count
, errstring
, flags
);
1510 * We don't want to check the return value of unconf_non_vhci_nodes()
1511 * and unconf_vhci_nodes(). But instead, we are interested only in
1512 * consistently incrementing num_devs and failure_count so that we can
1519 * This function handles configuring/unconfiguring all the devices w.r.t
1520 * the FCA port specified by apidt.
1522 * In the unconfigure case, it first unconfigures all the devices that are
1523 * seen through the given port at that moment and then unconfigures all the
1524 * devices that still (somehow) have devinfo nodes on the system for that FCA
1528 * cmd - CFGA_CMD_CONFIGURE or CFGA_CMD_UNCONFIGURE
1529 * apidt - Pointer to apid_t structure with data filled in
1530 * flags - Flags for special handling
1533 * errstring - Applicable only on a failure from plugin
1536 * FPCFGA_OK on success
1537 * non-FPCFGA_OK otherwise
1540 handle_devs(cfga_cmd_t cmd
, apid_t
*apidt
, cfga_flags_t flags
,
1541 char **errstring
, HBA_HANDLE handle
, int portIndex
,
1542 HBA_PORTATTRIBUTES portAttrs
)
1544 int num_devs
= 0, dev_cs_failed
= 0;
1545 char port_wwn
[WWN_S_LEN
];
1547 apid_t my_apidt
= {NULL
};
1549 HBA_PORTATTRIBUTES discPortAttrs
;
1551 fpcfga_ret_t rval
= FPCFGA_OK
;
1553 if ((my_apid
= calloc(
1554 1, strlen(apidt
->xport_phys
) + strlen(DYN_SEP
) +
1555 (2 * FC_WWN_SIZE
) + 1)) == NULL
) {
1556 cfga_err(errstring
, errno
, ERR_MEM_ALLOC
, 0);
1557 return (FPCFGA_LIB_ERR
);
1560 num_devs
= portAttrs
.NumberofDiscoveredPorts
;
1561 for (discIndex
= 0; discIndex
< portAttrs
.NumberofDiscoveredPorts
;
1563 if (getDiscPortAttrs(handle
, portIndex
,
1564 discIndex
, &discPortAttrs
)) {
1566 /* Move on to the next target */
1569 (void) sprintf(port_wwn
, "%016llx",
1570 wwnConversion(discPortAttrs
.PortWWN
.wwn
));
1572 * Construct a fake apid string similar to the one the
1573 * plugin gets from the framework and have apidt_create()
1574 * fill in the apid_t structure.
1576 strcpy(my_apid
, apidt
->xport_phys
);
1577 strcat(my_apid
, DYN_SEP
);
1578 strcat(my_apid
, port_wwn
);
1579 if (apidt_create(my_apid
, &my_apidt
, errstring
) != FPCFGA_OK
) {
1583 my_apidt
.flags
= apidt
->flags
;
1585 memcpy(&pwwn
, &(discPortAttrs
.PortWWN
), sizeof (la_wwn_t
));
1586 if (dev_change_state(cmd
, &my_apidt
, &pwwn
,
1587 flags
, errstring
, handle
, portAttrs
) != FPCFGA_OK
) {
1590 apidt_free(&my_apidt
);
1596 * We have now handled all the devices that are currently visible
1597 * through the given FCA port. But, it is possible that there are
1598 * some devinfo nodes hanging around. For the unconfigure operation,
1599 * this has to be looked into too.
1601 if (cmd
== CFGA_CMD_UNCONFIGURE
) {
1602 /* dev_cs_failed will be updated to indicate any failures */
1603 rval
= unconf_any_devinfo_nodes(apidt
, flags
, errstring
,
1604 &num_devs
, &dev_cs_failed
);
1607 if (rval
== FPCFGA_OK
) {
1608 if (dev_cs_failed
== 0)
1612 * For the discovered ports, num_devs is counted on target
1613 * basis, but for invisible targets, num_devs is counted on
1616 * But if dev_cs_failed and num_devs are incremented
1617 * consistently, comparation of these two counters is still
1620 if (dev_cs_failed
== num_devs
) {
1621 /* Failed on all devices seen through this FCA port */
1622 cfga_err(errstring
, 0,
1623 ((cmd
== CFGA_CMD_CONFIGURE
) ?
1624 ERR_FCA_CONFIGURE
: ERR_FCA_UNCONFIGURE
), 0);
1625 return (FPCFGA_LIB_ERR
);
1627 /* Failed only on some of the devices */
1628 cfga_err(errstring
, 0, ERR_PARTIAL_SUCCESS
, 0);
1629 return (FPCFGA_LIB_ERR
);
1632 if (dev_cs_failed
== num_devs
) {
1633 /* Failed on all devices seen through this FCA port */
1634 cfga_err(errstring
, 0,
1635 ((cmd
== CFGA_CMD_CONFIGURE
) ?
1636 ERR_FCA_CONFIGURE
: ERR_FCA_UNCONFIGURE
), 0);
1637 return (FPCFGA_LIB_ERR
);
1639 /* Failed only on some of the devices */
1640 cfga_err(errstring
, 0, ERR_PARTIAL_SUCCESS
, 0);
1641 return (FPCFGA_LIB_ERR
);
1646 * Should never get here
1651 fca_change_state(cfga_cmd_t state_change_cmd
, apid_t
*apidt
,
1652 cfga_flags_t flags
, char **errstring
)
1656 HBA_PORTATTRIBUTES portAttrs
;
1659 if ((ret
= findMatchingAdapterPort(apidt
->xport_phys
, &handle
,
1660 &portIndex
, &portAttrs
, errstring
)) != FPCFGA_OK
) {
1665 * Bail out if not fabric/public loop
1667 switch (state_change_cmd
) {
1668 case CFGA_CMD_CONFIGURE
:
1669 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
1670 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
1671 HBA_CloseAdapter(handle
);
1677 case CFGA_CMD_UNCONFIGURE
:
1678 if (portAttrs
.PortType
!= HBA_PORTTYPE_NLPORT
&&
1679 portAttrs
.PortType
!= HBA_PORTTYPE_NPORT
) {
1680 HBA_CloseAdapter(handle
);
1682 return (FPCFGA_OPNOTSUPP
);
1686 HBA_CloseAdapter(handle
);
1688 return (FPCFGA_LIB_ERR
);
1690 ret
= (handle_devs(state_change_cmd
, apidt
, flags
, errstring
,
1691 handle
, portIndex
, portAttrs
));
1692 HBA_CloseAdapter(handle
);