xref: /illumos-gate/usr/src/lib/cfgadm_plugins/scsi/common/cfga_ctl.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "cfga_scsi.h"
28 
29 struct larg {
30 	int ndevs;
31 	int nelem;
32 	char *dev;
33 	char **dev_list;
34 };
35 
36 #define	ETC_VFSTAB	"/etc/vfstab"
37 #define	SCFGA_LOCK	"/var/run/cfgadm_scsi"
38 
39 /* Function prototypes */
40 
41 static scfga_ret_t quiesce_confirm(apid_t *apidp,
42     msgid_t cmd_msg, prompt_t *pt, int *okp, int *quiesce, int *l_errnop);
43 static scfga_ret_t dev_hotplug(apid_t *apidp,
44     prompt_t *pt, cfga_flags_t flags, int quiesce, char **errstring);
45 static int disconnect(struct cfga_confirm *confp);
46 static int critical_ctrlr(const char *hba_phys);
47 static cfga_stat_t bus_devctl_to_recep_state(uint_t bus_dc_state);
48 static int get_hba_children(char *bus_path, char *dev_excl, char ***dev_list);
49 static char *get_node_path(char *minor_path);
50 static void free_dev_list_elements(char **dev_list);
51 static void free_dev_list(char **dev_list);
52 static int alloc_dev_list(struct larg *largp);
53 
54 /*
55  * Single thread all implicit quiesce operations
56  */
57 static mutex_t	quiesce_mutex = DEFAULTMUTEX;
58 
59 /*ARGSUSED*/
60 scfga_ret_t
61 bus_change_state(
62 	cfga_cmd_t state_change_cmd,
63 	apid_t *apidp,
64 	struct cfga_confirm *confp,
65 	cfga_flags_t flags,
66 	char **errstring)
67 {
68 	int l_errno = 0, force;
69 	uint_t state = 0;
70 	cfga_stat_t bus_state;
71 	scfga_cmd_t cmd;
72 	msgid_t errid;
73 	cfga_stat_t prereq;
74 	scfga_ret_t ret;
75 	char **dev_list = NULL;
76 
77 	assert(apidp->path != NULL);
78 	assert(apidp->hba_phys != NULL);
79 
80 	/*
81 	 * No dynamic components allowed
82 	 */
83 	if (apidp->dyncomp != NULL) {
84 		cfga_err(errstring, 0, ERR_NOT_BUSAPID, 0);
85 		return (SCFGA_ERR);
86 	}
87 
88 	/* Get bus state */
89 	if (devctl_cmd(apidp->path, SCFGA_BUS_GETSTATE, &state,
90 	    &l_errno) != SCFGA_OK) {
91 		cfga_err(errstring, l_errno, ERR_BUS_GETSTATE, 0);
92 		return (SCFGA_ERR);
93 	}
94 
95 	bus_state = bus_devctl_to_recep_state(state);
96 	force = ((flags & CFGA_FLAG_FORCE) == CFGA_FLAG_FORCE) ? 1 : 0;
97 	assert(confp->confirm != NULL);
98 
99 	switch (state_change_cmd) {
100 	case CFGA_CMD_DISCONNECT:	/* quiesce bus */
101 		/*
102 		 * If force flag not specified, check if controller is
103 		 * critical.
104 		 */
105 		if (!force) {
106 			/*
107 			 * This check is not foolproof, get user confirmation
108 			 * if test passes.
109 			 */
110 			if (critical_ctrlr(apidp->path)) {
111 				cfga_err(errstring, 0, ERR_CTRLR_CRIT, 0);
112 				ret = SCFGA_ERR;
113 				break;
114 			} else if (!disconnect(confp)) {
115 				ret = SCFGA_NACK;
116 				break;
117 			}
118 		}
119 
120 		cmd = SCFGA_BUS_QUIESCE;
121 		errid = ERR_BUS_QUIESCE;
122 		prereq = CFGA_STAT_CONNECTED;
123 
124 		goto common;
125 
126 	case CFGA_CMD_CONNECT:		/* unquiesce bus */
127 		cmd = SCFGA_BUS_UNQUIESCE;
128 		errid = ERR_BUS_UNQUIESCE;
129 		prereq = CFGA_STAT_DISCONNECTED;
130 
131 		goto common;
132 
133 	case CFGA_CMD_CONFIGURE:
134 		cmd = SCFGA_BUS_CONFIGURE;
135 		errid = ERR_BUS_CONFIGURE;
136 		prereq = CFGA_STAT_CONNECTED;
137 
138 		goto common;
139 
140 	case CFGA_CMD_UNCONFIGURE:
141 		cmd = SCFGA_BUS_UNCONFIGURE;
142 		errid = ERR_BUS_UNCONFIGURE;
143 		prereq = CFGA_STAT_CONNECTED;
144 
145 		/* FALLTHROUGH */
146 	common:
147 		if (bus_state != prereq) {
148 			cfga_err(errstring, 0,
149 			    (prereq == CFGA_STAT_CONNECTED)
150 			    ? ERR_BUS_NOTCONNECTED
151 			    : ERR_BUS_CONNECTED, 0);
152 			ret = SCFGA_ERR;
153 			break;
154 		}
155 
156 		/*
157 		 * When quiescing or unconfiguring a bus, first suspend or
158 		 * offline it through RCM.
159 		 * For unquiescing, we simple build the dev_list for
160 		 * resume notification.
161 		 */
162 		if (((apidp->flags & FLAG_DISABLE_RCM) == 0) &&
163 		    ((cmd == SCFGA_BUS_QUIESCE) ||
164 		    (cmd == SCFGA_BUS_UNQUIESCE) ||
165 		    (cmd == SCFGA_BUS_UNCONFIGURE))) {
166 			ret = get_hba_children(apidp->path, NULL, &dev_list);
167 			if (ret != SCFGA_OK) {
168 				break;
169 			}
170 			if (cmd == SCFGA_BUS_QUIESCE) {
171 				if ((ret = scsi_rcm_suspend(dev_list,
172 				    errstring, flags, 1)) != SCFGA_OK) {
173 					break;
174 				}
175 			} else if (cmd == SCFGA_BUS_UNCONFIGURE) {
176 				if ((ret = scsi_rcm_offline(dev_list,
177 				    errstring, flags)) != SCFGA_OK) {
178 					break;
179 				}
180 			}
181 		}
182 
183 		ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno);
184 		if (ret != SCFGA_OK) {
185 			/*
186 			 * EIO when child devices are busy may confuse user.
187 			 * So explain it.
188 			 */
189 			if (cmd == SCFGA_BUS_UNCONFIGURE && l_errno == EIO)
190 				errid = ERR_MAYBE_BUSY;
191 
192 			cfga_err(errstring, l_errno, errid, 0);
193 
194 			/*
195 			 * If the bus was suspended in RCM, then cancel the RCM
196 			 * operation.  Discard RCM failures here because the
197 			 * devctl's failure is what is most relevant.
198 			 */
199 			if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
200 				if (cmd == SCFGA_BUS_QUIESCE)
201 					(void) scsi_rcm_resume(dev_list,
202 					    errstring,
203 					    (flags & (~CFGA_FLAG_FORCE)), 1);
204 				else if (cmd == SCFGA_BUS_UNCONFIGURE) {
205 					(void) devctl_cmd(apidp->path,
206 					    SCFGA_BUS_CONFIGURE, NULL,
207 					    &l_errno);
208 					(void) scsi_rcm_online(dev_list,
209 					    errstring,
210 					    (flags & (~CFGA_FLAG_FORCE)));
211 				}
212 			}
213 
214 			break;
215 		}
216 
217 		/*
218 		 * When unquiescing or configuring a bus, resume or online it
219 		 * in RCM when the devctl command is complete.
220 		 * When unconfiguring a bus, notify removal of devices.
221 		 */
222 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
223 			if (cmd == SCFGA_BUS_UNQUIESCE) {
224 				ret = scsi_rcm_resume(dev_list, errstring,
225 				    (flags & (~CFGA_FLAG_FORCE)), 1);
226 			} else if (cmd == SCFGA_BUS_UNCONFIGURE) {
227 				ret = scsi_rcm_remove(dev_list, errstring,
228 				    (flags & (~CFGA_FLAG_FORCE)));
229 			}
230 		}
231 		break;
232 
233 	case CFGA_CMD_LOAD:
234 	case CFGA_CMD_UNLOAD:
235 		ret = SCFGA_OPNOTSUPP;
236 		break;
237 
238 	default:
239 		cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
240 		ret = SCFGA_ERR;
241 		break;
242 	}
243 
244 	free_dev_list(dev_list);
245 	return (ret);
246 }
247 
248 scfga_ret_t
249 dev_change_state(
250 	cfga_cmd_t state_change_cmd,
251 	apid_t *apidp,
252 	cfga_flags_t flags,
253 	char **errstring)
254 {
255 	uint_t state = 0;
256 	int l_errno = 0;
257 	cfga_stat_t bus_state;
258 	scfga_cmd_t cmd;
259 	msgid_t errid;
260 	scfga_ret_t ret;
261 	char *dev_list[2] = {NULL};
262 
263 	assert(apidp->path != NULL);
264 	assert(apidp->hba_phys != NULL);
265 
266 	/*
267 	 * For a device, dynamic component must be present
268 	 */
269 	if (apidp->dyncomp == NULL) {
270 		cfga_err(errstring, 0, ERR_APID_INVAL, 0);
271 		return (SCFGA_ERR);
272 	}
273 
274 	/* Get bus state */
275 	if (devctl_cmd(apidp->hba_phys, SCFGA_BUS_GETSTATE, &state,
276 	    &l_errno) != SCFGA_OK) {
277 		cfga_err(errstring, l_errno, ERR_BUS_GETSTATE, 0);
278 		return (SCFGA_ERR);
279 	}
280 
281 	bus_state = bus_devctl_to_recep_state(state);
282 
283 	switch (state_change_cmd) {
284 	case CFGA_CMD_CONFIGURE:		/* online device */
285 		cmd = SCFGA_DEV_CONFIGURE;
286 		errid = ERR_DEV_CONFIGURE;
287 		goto common;
288 
289 	case CFGA_CMD_UNCONFIGURE:		/* offline device */
290 		cmd = SCFGA_DEV_UNCONFIGURE;
291 		errid = ERR_DEV_UNCONFIGURE;
292 		/* FALLTHROUGH */
293 	common:
294 		if (bus_state != CFGA_STAT_CONNECTED) {
295 			cfga_err(errstring, 0, ERR_BUS_NOTCONNECTED, 0);
296 			ret = SCFGA_ERR;
297 			break;
298 		}
299 
300 		if (apidp->dyntype == PATH_APID) {
301 			/* call a scsi_vhci ioctl to do online/offline path. */
302 			ret = path_apid_state_change(apidp, cmd,
303 			    flags, errstring, &l_errno, errid);
304 		} else {
305 			/*
306 			 * When unconfiguring a device, first offline it
307 			 * through RCM.
308 			 */
309 			if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
310 				if (cmd == SCFGA_DEV_UNCONFIGURE) {
311 					dev_list[0] =
312 					    get_node_path(apidp->path);
313 					if (dev_list[0] == NULL) {
314 						ret = SCFGA_ERR;
315 						break;
316 					}
317 					if ((ret = scsi_rcm_offline(dev_list,
318 					    errstring, flags)) != SCFGA_OK) {
319 						break;
320 					}
321 				}
322 			}
323 
324 			ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno);
325 			if (ret != SCFGA_OK) {
326 				cfga_err(errstring, l_errno, errid, 0);
327 
328 			/*
329 			 * If an unconfigure fails, cancel the RCM offline.
330 			 * Discard any RCM failures so that the devctl
331 			 * failure will still be reported.
332 			 */
333 				if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
334 					if (cmd == SCFGA_DEV_UNCONFIGURE)
335 						(void) scsi_rcm_online(dev_list,
336 						    errstring, flags);
337 				}
338 				break;
339 			}
340 			if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
341 			/*
342 			 * Unconfigure succeeded, call the RCM notify_remove.
343 			 */
344 				if (cmd == SCFGA_DEV_UNCONFIGURE)
345 					(void) scsi_rcm_remove(dev_list,
346 					    errstring, flags);
347 			}
348 		}
349 		break;
350 
351 	/*
352 	 * Cannot disconnect/connect individual devices without affecting
353 	 * other devices on the bus. So we don't support these ops.
354 	 */
355 	case CFGA_CMD_DISCONNECT:
356 	case CFGA_CMD_CONNECT:
357 		cfga_err(errstring, 0, ERR_NOT_DEVOP, 0);
358 		ret = SCFGA_ERR;
359 		break;
360 	case CFGA_CMD_LOAD:
361 	case CFGA_CMD_UNLOAD:
362 		ret = SCFGA_OPNOTSUPP;
363 		break;
364 	default:
365 		cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
366 		ret = SCFGA_ERR;
367 		break;
368 	}
369 
370 	free_dev_list_elements(dev_list);
371 	return (ret);
372 }
373 
374 /*ARGSUSED*/
375 scfga_ret_t
376 dev_remove(
377 	const char *func,
378 	scfga_cmd_t cmd,
379 	apid_t *apidp,
380 	prompt_t *prp,
381 	cfga_flags_t flags,
382 	char **errstring)
383 {
384 	int proceed, l_errno = 0;
385 	scfga_ret_t ret;
386 	int do_quiesce;
387 	char *dev_list[2] = {NULL};
388 
389 	assert(apidp->hba_phys != NULL);
390 	assert(apidp->path != NULL);
391 
392 	/* device operation only */
393 	if (apidp->dyncomp == NULL) {
394 		cfga_err(errstring, 0, ERR_NOT_BUSOP, 0);
395 		return (SCFGA_ERR);
396 	}
397 
398 	proceed = 1;
399 	ret = quiesce_confirm(apidp, MSG_RMDEV, prp, &proceed, &do_quiesce,
400 	    &l_errno);
401 	if (ret != SCFGA_OK) {
402 		cfga_err(errstring, l_errno, ERR_DEV_REMOVE, 0);
403 		return (ret);
404 	}
405 
406 	if (!proceed) {
407 		return (SCFGA_NACK);
408 	}
409 
410 	/*
411 	 * Offline the device in RCM
412 	 */
413 	if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
414 		dev_list[0] = get_node_path(apidp->path);
415 		if (dev_list[0] == NULL)
416 			return (SCFGA_ERR);
417 		if ((ret = scsi_rcm_offline(dev_list, errstring, flags))
418 		    != SCFGA_OK) {
419 			free_dev_list_elements(dev_list);
420 			return (ret);
421 		}
422 	}
423 
424 	/*
425 	 * Offline the device
426 	 */
427 	ret = devctl_cmd(apidp->path, SCFGA_DEV_UNCONFIGURE, NULL, &l_errno);
428 	if (ret != SCFGA_OK) {
429 
430 		cfga_err(errstring, l_errno, ERR_DEV_REMOVE, 0);
431 
432 		/*
433 		 * Cancel the RCM offline.  Discard the RCM failures so that
434 		 * the above devctl failure is still reported.
435 		 */
436 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0)
437 			(void) scsi_rcm_online(dev_list, errstring, flags);
438 		free_dev_list_elements(dev_list);
439 		return (ret);
440 	}
441 
442 	/* Do the physical removal */
443 	ret = dev_hotplug(apidp, prp, flags, do_quiesce, errstring);
444 
445 	if (ret == SCFGA_OK) {
446 		/*
447 		 * Complete the remove.
448 		 * Since the device is already offlined, remove shouldn't
449 		 * fail. Even if remove fails, there is no side effect.
450 		 */
451 		(void) devctl_cmd(apidp->path, SCFGA_DEV_REMOVE,
452 		    NULL, &l_errno);
453 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0)
454 			ret = scsi_rcm_remove(dev_list, errstring, flags);
455 	} else {
456 		/*
457 		 * Reconfigure the device and restore the device's RCM state.
458 		 * If reconfigure succeeds, restore the state to online.
459 		 * If reconfigure fails (e.g. a typo from user), we treat
460 		 * the device as removed.
461 		 */
462 		if (devctl_cmd(apidp->path, SCFGA_DEV_CONFIGURE, NULL, &l_errno)
463 		    == SCFGA_OK) {
464 			if ((apidp->flags & FLAG_DISABLE_RCM) == 0)
465 				(void) scsi_rcm_online(dev_list, errstring,
466 				    flags);
467 		} else {
468 			char *cp = strrchr(apidp->path, ':');
469 			if (cp)
470 				*cp = '\0';
471 			cfga_err(errstring, l_errno, ERR_DEV_RECONFIGURE,
472 			    apidp->path, 0);
473 			if (cp)
474 				*cp = ':';
475 			if ((apidp->flags & FLAG_DISABLE_RCM) == 0)
476 				(void) scsi_rcm_remove(dev_list, errstring,
477 				    flags);
478 		}
479 	}
480 
481 	free_dev_list_elements(dev_list);
482 	return (ret);
483 }
484 
485 /*ARGSUSED*/
486 scfga_ret_t
487 dev_insert(
488 	const char *func,
489 	scfga_cmd_t cmd,
490 	apid_t *apidp,
491 	prompt_t *prp,
492 	cfga_flags_t flags,
493 	char **errstring)
494 {
495 	int proceed, l_errno = 0;
496 	scfga_ret_t ret;
497 	int do_quiesce;
498 
499 	assert(apidp->hba_phys != NULL);
500 	assert(apidp->path != NULL);
501 
502 	/* Currently, insert operation only allowed for bus */
503 	if (apidp->dyncomp != NULL) {
504 		cfga_err(errstring, 0, ERR_NOT_DEVOP, 0);
505 		return (SCFGA_ERR);
506 	}
507 
508 	proceed = 1;
509 	ret = quiesce_confirm(apidp, MSG_INSDEV, prp, &proceed, &do_quiesce,
510 	    &l_errno);
511 	if (ret != SCFGA_OK) {
512 		cfga_err(errstring, l_errno, ERR_DEV_INSERT, 0);
513 		return (ret);
514 	}
515 
516 	if (!proceed) {
517 		return (SCFGA_NACK);
518 	}
519 
520 	/* Do the physical addition */
521 	ret = dev_hotplug(apidp, prp, flags, do_quiesce, errstring);
522 	if (ret != SCFGA_OK) {
523 		return (ret);
524 	}
525 
526 	/*
527 	 * Configure bus to online new device(s).
528 	 * Previously offlined devices will not be onlined.
529 	 */
530 	ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_CONFIGURE, NULL, &l_errno);
531 	if (ret != SCFGA_OK) {
532 		cfga_err(errstring, l_errno, ERR_DEV_INSERT, 0);
533 		return (SCFGA_ERR);
534 	}
535 
536 	return (SCFGA_OK);
537 }
538 
539 /*ARGSUSED*/
540 scfga_ret_t
541 dev_replace(
542 	const char *func,
543 	scfga_cmd_t cmd,
544 	apid_t *apidp,
545 	prompt_t *prp,
546 	cfga_flags_t flags,
547 	char **errstring)
548 {
549 	int proceed, l_errno = 0;
550 	scfga_ret_t ret, ret2;
551 	int do_quiesce;
552 	char *dev_list[2] = {NULL};
553 
554 	assert(apidp->hba_phys != NULL);
555 	assert(apidp->path != NULL);
556 
557 	/* device operation only */
558 	if (apidp->dyncomp == NULL) {
559 		cfga_err(errstring, 0, ERR_NOT_BUSOP, 0);
560 		return (SCFGA_ERR);
561 	}
562 
563 	proceed = 1;
564 	ret = quiesce_confirm(apidp, MSG_REPLDEV, prp, &proceed, &do_quiesce,
565 	    &l_errno);
566 	if (ret != SCFGA_OK) {
567 		cfga_err(errstring, l_errno, ERR_DEV_REPLACE, 0);
568 		return (ret);
569 	}
570 
571 	if (!proceed) {
572 		return (SCFGA_NACK);
573 	}
574 
575 	/* Offline the device in RCM */
576 	if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
577 		dev_list[0] = get_node_path(apidp->path);
578 		if (dev_list[0] == NULL)
579 			return (SCFGA_ERR);
580 		if ((ret = scsi_rcm_offline(dev_list, errstring, flags))
581 		    != SCFGA_OK) {
582 			free_dev_list_elements(dev_list);
583 			return (ret);
584 		}
585 	}
586 
587 	ret = devctl_cmd(apidp->path, SCFGA_DEV_REMOVE, NULL, &l_errno);
588 	if (ret != SCFGA_OK) {
589 
590 		/*
591 		 * Cancel the RCM offline.  Discard any RCM failures so that
592 		 * the devctl failure can still be reported.
593 		 */
594 		if ((apidp->flags & FLAG_DISABLE_RCM) == 0)
595 			(void) scsi_rcm_online(dev_list, errstring, flags);
596 
597 		cfga_err(errstring, l_errno, ERR_DEV_REPLACE, 0);
598 		free_dev_list_elements(dev_list);
599 		return (ret);
600 	}
601 
602 	/* do the physical replace */
603 	ret = dev_hotplug(apidp, prp, flags, do_quiesce, errstring);
604 
605 	/* Online the replacement, or restore state on error */
606 	ret2 = devctl_cmd(apidp->path, SCFGA_DEV_CONFIGURE, NULL, &l_errno);
607 
608 	if (ret2 != SCFGA_OK) {
609 		cfga_err(errstring, l_errno, ERR_DEV_REPLACE, 0);
610 	}
611 
612 	/*
613 	 * Remove the replaced device in RCM, or online the device in RCM
614 	 * to recover.
615 	 */
616 	if ((apidp->flags & FLAG_DISABLE_RCM) == 0) {
617 		if (ret == SCFGA_OK)
618 			ret = scsi_rcm_remove(dev_list, errstring, flags);
619 		else if (ret2 == SCFGA_OK)
620 			ret2 = scsi_rcm_online(dev_list, errstring, flags);
621 	}
622 	free_dev_list_elements(dev_list);
623 
624 	return (ret == SCFGA_OK ? ret2 : ret);
625 }
626 
627 #pragma weak plat_dev_led
628 /*ARGSUSED*/
629 scfga_ret_t
630 dev_led(
631 	const char *func,
632 	scfga_cmd_t cmd,
633 	apid_t *apidp,
634 	prompt_t *prp,
635 	cfga_flags_t flags,
636 	char **errstring)
637 {
638 
639 	/*
640 	 * The implementation of the led command is platform-specific, so
641 	 * the default behavior is to say that the functionality is not
642 	 * available for this device.
643 	 */
644 	if (plat_dev_led) {
645 		return (plat_dev_led(func, cmd, apidp, prp, flags, errstring));
646 	}
647 	cfga_err(errstring, 0, ERR_UNAVAILABLE, 0);
648 	return (SCFGA_ERR);
649 }
650 
651 /*ARGSUSED*/
652 scfga_ret_t
653 reset_common(
654 	const char *func,
655 	scfga_cmd_t cmd,
656 	apid_t *apidp,
657 	prompt_t *prp,
658 	cfga_flags_t flags,
659 	char **errstring)
660 {
661 	int l_errno = 0;
662 	scfga_ret_t ret;
663 
664 
665 	assert(apidp->path != NULL);
666 	assert(apidp->hba_phys != NULL);
667 
668 	switch (cmd) {
669 	case SCFGA_RESET_DEV:
670 		if (apidp->dyncomp == NULL) {
671 			cfga_err(errstring, 0, ERR_NOT_BUSOP, 0);
672 			return (SCFGA_ERR);
673 		}
674 		break;
675 
676 	case SCFGA_RESET_BUS:
677 	case SCFGA_RESET_ALL:
678 		if (apidp->dyncomp != NULL) {
679 			cfga_err(errstring, 0, ERR_NOT_DEVOP, 0);
680 			return (SCFGA_ERR);
681 		}
682 		break;
683 	default:
684 		cfga_err(errstring, 0, ERR_CMD_INVAL, 0);
685 		return (SCFGA_ERR);
686 	}
687 
688 	ret = devctl_cmd(apidp->path, cmd, NULL, &l_errno);
689 	if (ret != SCFGA_OK) {
690 		cfga_err(errstring, l_errno, ERR_RESET, 0);
691 	}
692 
693 	return (ret);
694 }
695 
696 static int
697 disconnect(struct cfga_confirm *confp)
698 {
699 	int ans, append_newline;
700 	char *cq;
701 
702 	append_newline = 0;
703 	cq = cfga_str(append_newline, WARN_DISCONNECT, 0);
704 
705 	ans = confp->confirm(confp->appdata_ptr, cq);
706 
707 	S_FREE(cq);
708 
709 	return (ans == 1);
710 }
711 
712 /*
713  * Check for "scsi-no-quiesce" property
714  * Return code: -1 error, 0 quiesce not required, 1 quiesce required
715  */
716 static int
717 quiesce_required(apid_t *apidp, int *l_errnop)
718 {
719 	di_node_t bus_node, dev_node;
720 	char *bus_path, *bus_end;
721 	char *dev_path, *dev_end;
722 	int *propval;
723 
724 	/* take libdevinfo snapshot of subtree at hba */
725 	bus_path = apidp->hba_phys + strlen(DEVICES_DIR);
726 	bus_end = strrchr(bus_path, ':');
727 	if (bus_end)
728 		*bus_end = '\0';
729 
730 	bus_node = di_init(bus_path, DINFOSUBTREE|DINFOPROP);
731 	if (bus_end)
732 		*bus_end = ':';
733 	if (bus_node == DI_NODE_NIL) {
734 		*l_errnop = errno;
735 		return (-1);	/* error */
736 	}
737 
738 	/* check bus node for property */
739 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, bus_node, SCSI_NO_QUIESCE,
740 	    &propval) == 1) {
741 		di_fini(bus_node);
742 		return (0);	/* quiesce not required */
743 	}
744 
745 	/* if this ap is HBA, return with quiesce required */
746 	if (apidp->dyncomp == NULL) {
747 		di_fini(bus_node);
748 		return (1);
749 	}
750 
751 	/* check device node for property */
752 	dev_path = apidp->path + strlen(DEVICES_DIR);
753 	dev_end = strrchr(dev_path, ':');
754 	if (dev_end)
755 		*dev_end = '\0';
756 
757 	dev_node = di_child_node(bus_node);
758 	while (dev_node != DI_NODE_NIL) {
759 		char *child_path;
760 		child_path = di_devfs_path(dev_node);
761 		if (strcmp(child_path, dev_path) == 0) {
762 			di_devfs_path_free(child_path);
763 			break;
764 		}
765 		di_devfs_path_free(child_path);
766 		dev_node = di_sibling_node(dev_node);
767 	}
768 
769 	if (dev_end)
770 		*dev_end = ':';
771 	if (dev_node == DI_NODE_NIL) {
772 		di_fini(bus_node);
773 		return (1);	/* dev not found (insert case) */
774 	}
775 
776 	/* check child node for property */
777 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, dev_node, "scsi-no-quiesce",
778 	    &propval) == 1) {
779 		di_fini(bus_node);
780 		return (0);	/* quiesce not required */
781 	}
782 	return (1);	/* quiesce required */
783 }
784 
785 static scfga_ret_t
786 quiesce_confirm(
787 	apid_t *apidp,
788 	msgid_t cmd_msg,
789 	prompt_t *prp,
790 	int *okp,
791 	int *quiesce,
792 	int *l_errnop)
793 {
794 	char *buf = NULL, *hbap = NULL, *cq1 = NULL, *cq2 = NULL;
795 	char *cp;
796 	size_t len = 0;
797 	int i = 0, append_newline;
798 	scfga_ret_t ret;
799 
800 	assert(apidp->path != NULL);
801 	assert(apidp->hba_phys != NULL);
802 
803 	*quiesce = quiesce_required(apidp, l_errnop);
804 	if (*quiesce == -1)
805 		return (SCFGA_ERR);
806 	else if (*quiesce == 0)
807 		return (SCFGA_OK);
808 
809 	/*
810 	 * Try to create HBA logical ap_id.
811 	 * If that fails use physical path
812 	 */
813 	ret = make_hba_logid(apidp->hba_phys, &hbap, &i);
814 	if (ret != SCFGA_OK) {
815 		if ((hbap = get_node_path(apidp->hba_phys)) == NULL) {
816 			*l_errnop = errno;
817 			return (SCFGA_LIB_ERR);
818 		}
819 	}
820 
821 	assert(hbap != NULL);
822 
823 	append_newline = 0;
824 	cq1 = cfga_str(append_newline, CONF_QUIESCE_1, hbap, 0);
825 	cq2 = cfga_str(append_newline, CONF_QUIESCE_2, 0);
826 	len = strlen(cq1) + strlen(cq2) + 1; /* Includes term. NULL */
827 
828 	if ((buf = calloc(1, len)) == NULL) {
829 		*l_errnop = errno;
830 		ret = SCFGA_LIB_ERR;
831 		S_FREE(cq1);
832 		S_FREE(cq2);
833 		goto out;
834 	}
835 	(void) strcpy(buf, cq1);
836 	(void) strcat(buf, cq2);
837 
838 	S_FREE(cq1);
839 	S_FREE(cq2);
840 
841 
842 	/* Remove minor name (if any) from phys path */
843 	if ((cp = strrchr(apidp->path, ':')) != NULL) {
844 		*cp = '\0';
845 	}
846 
847 	/* describe operation being attempted */
848 	cfga_msg(prp->msgp, cmd_msg, apidp->path, 0);
849 
850 	/* Restore minor name */
851 	if (cp != NULL) {
852 		*cp = ':';
853 	}
854 
855 	/* request permission to quiesce */
856 	assert(prp->confp != NULL && prp->confp->confirm != NULL);
857 	*okp = prp->confp->confirm(prp->confp->appdata_ptr, buf);
858 
859 	ret = SCFGA_OK;
860 	/*FALLTHRU*/
861 out:
862 	S_FREE(buf);
863 	S_FREE(hbap);
864 	return (ret);
865 }
866 
867 static scfga_ret_t
868 suspend_in_rcm(
869 	apid_t		*apidp,
870 	char		***suspend_list_ptr,
871 	char		**errstring,
872 	cfga_flags_t	flags)
873 {
874 	scfga_ret_t	ret;
875 	char		*bus_path = NULL;
876 	char		*dev_path = NULL;
877 	char		**suspend_list = NULL;
878 
879 	*suspend_list_ptr = NULL;
880 
881 	/* Suspend the bus through RCM */
882 	if (apidp->flags & FLAG_DISABLE_RCM)
883 		return (SCFGA_OK);
884 
885 	/* The bus_path is the HBA path without its minor */
886 	if ((bus_path = get_node_path(apidp->hba_phys)) == NULL)
887 		return (SCFGA_ERR);
888 
889 	/*
890 	 * The dev_path is already initialized to NULL.  If the AP Id
891 	 * path differs from the HBA path, then the dev_path should
892 	 * instead be set to the AP Id path without its minor.
893 	 */
894 	if (strcmp(apidp->hba_phys, apidp->path) != 0) {
895 		if ((dev_path = get_node_path(apidp->path)) == NULL) {
896 			ret = SCFGA_ERR;
897 			goto out;
898 		}
899 	}
900 
901 	if ((ret = get_hba_children(bus_path, dev_path, &suspend_list))
902 	    != SCFGA_OK) {
903 		free_dev_list(suspend_list);
904 		goto out;
905 	}
906 
907 	if (scsi_rcm_suspend(suspend_list, errstring, flags, 0) != SCFGA_OK) {
908 		ret = SCFGA_ERR;
909 		free_dev_list(suspend_list);
910 	} else {
911 		ret = SCFGA_OK;
912 		*suspend_list_ptr = suspend_list;
913 	}
914 	/*FALLTHROUGH*/
915 out:
916 	S_FREE(bus_path);
917 	S_FREE(dev_path);
918 	return (ret);
919 }
920 
921 /*
922  * Resume the bus through RCM if it successfully
923  * unquiesced.
924  */
925 static void
926 resume_in_rcm(
927 	apid_t		*apidp,
928 	char		**suspend_list,
929 	char		**errstring,
930 	cfga_flags_t	flags)
931 {
932 	if (apidp->flags & FLAG_DISABLE_RCM)
933 		return;
934 
935 	(void) scsi_rcm_resume(suspend_list, errstring, flags, 0);
936 
937 	free_dev_list(suspend_list);
938 }
939 
940 static scfga_ret_t
941 wait_for_hotplug(prompt_t *pt, int msg)
942 {
943 	char		*cu = NULL;
944 	int		append_newline = 0;
945 	scfga_ret_t	ret;
946 
947 	cu = cfga_str(append_newline, msg, 0);
948 	if (pt->confp->confirm(pt->confp->appdata_ptr, cu) != 1) {
949 		ret = SCFGA_NACK;
950 	} else {
951 		ret = SCFGA_OK;
952 	}
953 	S_FREE(cu);
954 	return (ret);
955 }
956 
957 static scfga_ret_t
958 bus_quiesce(apid_t *apidp, prompt_t *pt, char **errstring, cfga_flags_t flags)
959 {
960 	int		l_errno;
961 	scfga_ret_t	ret;
962 	scfga_ret_t	hpret;
963 	char		**suspend_list = NULL;
964 
965 	ret = suspend_in_rcm(apidp, &suspend_list, errstring, flags);
966 	if (ret != SCFGA_OK) {
967 		return (ret);
968 	}
969 
970 	/*
971 	 * If the quiesce fails, then cancel the RCM suspend.
972 	 * Discard any RCM failures so that the devctl failure
973 	 * can still be reported.
974 	 */
975 	l_errno = 0;
976 	ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_QUIESCE, NULL, &l_errno);
977 	if (ret != SCFGA_OK) {
978 		resume_in_rcm(apidp, suspend_list, errstring, flags);
979 		cfga_err(errstring, l_errno, ERR_BUS_QUIESCE, 0);
980 		return (ret);
981 	}
982 
983 	/*
984 	 * Prompt user to proceed with physical hotplug
985 	 * and wait until they are done.
986 	 */
987 	hpret = wait_for_hotplug(pt, CONF_UNQUIESCE);
988 
989 	/*
990 	 * The unquiesce may fail with EALREADY (which is ok)
991 	 * or some other error (which is not ok).
992 	 */
993 	l_errno = 0;
994 	ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_UNQUIESCE, NULL, &l_errno);
995 	if (ret != SCFGA_OK && l_errno != EALREADY) {
996 		free_dev_list(suspend_list);
997 		cfga_err(errstring, l_errno, ERR_BUS_UNQUIESCE, 0);
998 		return (SCFGA_ERR);
999 	}
1000 
1001 	resume_in_rcm(apidp, suspend_list, errstring, flags);
1002 
1003 	return (hpret);
1004 }
1005 
1006 #define	MAX_LOCK_TRIES		20
1007 #define	MAX_UNLINK_TRIES	60
1008 #define	s_getpid		(int)getpid	/* else lint causes problems */
1009 
1010 static void
1011 s_unlink(char *file)
1012 {
1013 	int	count = 0;
1014 
1015 retry:
1016 	if (unlink(file) == -1) {
1017 		if (errno != EINTR && errno != EAGAIN) {
1018 			CFGA_TRACE1((stdout, "s_unlink[%d]: unlink failed: "
1019 			    "%s: %s\n", s_getpid(), file, strerror(errno)));
1020 			return;
1021 		}
1022 
1023 		if (++count < MAX_UNLINK_TRIES) {
1024 			(void) sleep(1);
1025 			goto retry;
1026 		}
1027 		CFGA_TRACE1((stdout, "s_unlink[%d]: retry limit: %s\n",
1028 		    s_getpid(), file));
1029 	} else {
1030 		CFGA_TRACE3((stdout, "s_unlink[%d]: unlinked: %s\n",
1031 		    s_getpid(), file));
1032 	}
1033 }
1034 
1035 static scfga_ret_t
1036 create_lock(int *fdp, struct cfga_msg *msgp, char **errstring)
1037 {
1038 	FILE			*fp;
1039 	int			count;
1040 	struct extmnttab	ent;
1041 	int			mnted;
1042 
1043 
1044 	*fdp = -1;
1045 
1046 	/*
1047 	 * Check that /var/run is mounted. In the unlikely event
1048 	 * that the lock file is left behind, we want it
1049 	 * cleared on the next reboot.
1050 	 */
1051 	errno = 0;
1052 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
1053 		cfga_err(errstring, errno, ERRARG_OPEN, MNTTAB, 0);
1054 		return (SCFGA_LIB_ERR);
1055 	}
1056 
1057 	resetmnttab(fp);
1058 
1059 	mnted = 0;
1060 	while (getextmntent(fp, &ent, sizeof (ent)) == 0) {
1061 		if (strcmp(ent.mnt_mountp, "/var/run") == 0) {
1062 			mnted = 1;
1063 			break;
1064 		}
1065 	}
1066 
1067 	(void) fclose(fp);
1068 
1069 	if (!mnted) {
1070 		cfga_err(errstring, 0, ERR_VAR_RUN, 0);
1071 		return (SCFGA_LIB_ERR);
1072 	}
1073 
1074 	/*
1075 	 * Wait for a short period of time if we cannot O_EXCL create
1076 	 * lock file. If some other cfgadm process is finishing up, we
1077 	 * can get in. If the wait required is long however, just
1078 	 * return SYSTEM_BUSY to the user - a hotplug operation is
1079 	 * probably in progress.
1080 	 */
1081 	count = 0;
1082 retry:
1083 	*fdp = open(SCFGA_LOCK, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
1084 	if (*fdp == -1 && errno == EEXIST) {
1085 		if (++count < MAX_LOCK_TRIES) {
1086 			if (count == 1)
1087 				cfga_msg(msgp, MSG_WAIT_LOCK, 0);
1088 			(void) sleep(1);
1089 			goto retry;
1090 		}
1091 	}
1092 
1093 	if (*fdp == -1 && errno == EEXIST) {
1094 		cfga_err(errstring, 0, ERRARG_QUIESCE_LOCK, SCFGA_LOCK, 0);
1095 		return (SCFGA_SYSTEM_BUSY);
1096 	} else if (*fdp == -1) {
1097 		cfga_err(errstring, errno, ERRARG_QUIESCE_LOCK, SCFGA_LOCK, 0);
1098 		return (SCFGA_LIB_ERR);
1099 	}
1100 
1101 	CFGA_TRACE3((stdout, "create_lock[%d]: created lockfile: %s\n",
1102 	    s_getpid(), SCFGA_LOCK));
1103 
1104 	return (SCFGA_OK);
1105 }
1106 
1107 static scfga_ret_t
1108 syslock(int fd, char **errstring)
1109 {
1110 	struct flock	lock;
1111 	int		count;
1112 	int		rval;
1113 
1114 	assert(fd != -1);
1115 
1116 	CFGA_TRACE3((stdout, "syslock[%d]: trying lock: %s\n",
1117 	    s_getpid(), SCFGA_LOCK));
1118 
1119 	lock.l_type = F_WRLCK;
1120 	lock.l_whence = SEEK_SET;
1121 	lock.l_start = 0;
1122 	lock.l_len = 0;
1123 
1124 	count = 0;
1125 	while ((rval = fcntl(fd, F_SETLKW, &lock)) == -1 && errno == EINTR) {
1126 		if (++count >= MAX_LOCK_TRIES) {
1127 			CFGA_TRACE1((stdout, "syslock[%d]: retry limit: %s\n",
1128 			    s_getpid(), SCFGA_LOCK));
1129 			goto badlock;
1130 		}
1131 		(void) sleep(1);
1132 	}
1133 
1134 	if (rval != -1) {
1135 		CFGA_TRACE3((stdout, "syslock[%d]: locked file: %s\n",
1136 		    s_getpid(), SCFGA_LOCK));
1137 		return (SCFGA_OK);
1138 	}
1139 
1140 	/*FALLTHROUGH*/
1141 badlock:
1142 	cfga_err(errstring, errno, ERRARG_LOCK, SCFGA_LOCK, 0);
1143 	/* trace message to display pid */
1144 	CFGA_TRACE1((stdout, "syslock[%d]: cannot lock %s\n",
1145 	    s_getpid(), SCFGA_LOCK));
1146 	return (SCFGA_LIB_ERR);
1147 }
1148 
1149 static void
1150 wait_for_child(pid_t cpid)
1151 {
1152 	int	status;
1153 	pid_t	rval;
1154 
1155 	CFGA_TRACE2((stdout, "wait_for_child[%d]: child[%d]\n",
1156 	    s_getpid(), (int)cpid));
1157 
1158 	for (;;) {
1159 		while ((rval = waitpid(cpid, &status, 0)) != cpid) {
1160 			if (errno == ECHILD) {
1161 				CFGA_TRACE1((stdout, "waitpid[%d]: child[%d] "
1162 				    "doesn't exist\n", s_getpid(), (int)cpid));
1163 				return;
1164 			}
1165 
1166 			CFGA_TRACE3((stdout, "waitpid[%d]: returned: %d"
1167 			    ": errno: %s\n", s_getpid(), (int)rval,
1168 			    strerror(errno)));
1169 		}
1170 
1171 		if (WIFEXITED(status)) {
1172 			CFGA_TRACE2((stdout, "waitpid[%d]: child[%d]: "
1173 			    "normal exit\n", s_getpid(), (int)cpid));
1174 			return;
1175 		}
1176 
1177 		if (WIFSIGNALED(status)) {
1178 			CFGA_TRACE2((stdout, "waitpid[%d]: child[%d]: "
1179 			    "signal exit\n", s_getpid(), (int)cpid));
1180 			return;
1181 		}
1182 
1183 		/*
1184 		 * The child has not terminated. We received status
1185 		 * because the child was either stopped or continued.
1186 		 * Wait for child termination by calling waitpid() again.
1187 		 */
1188 	}
1189 }
1190 
1191 static void
1192 wait_and_cleanup(int fd, apid_t *apidp)
1193 {
1194 	int		l_errno;
1195 	scfga_ret_t	ret;
1196 
1197 	/* This is the child */
1198 	CFGA_TRACE2((stdout, "child[%d]: Entering wait_cleanup\n", s_getpid()));
1199 
1200 	if (syslock(fd, NULL) != SCFGA_OK) {
1201 		CFGA_TRACE1((stdout, "child[%d]: lock failure "
1202 		    " - _exit(1)\n", s_getpid()));
1203 		/*
1204 		 * As a last resort, unlink the lock file. This is relatively
1205 		 * safe as the child doesn't unquiesce the bus in this case.
1206 		 */
1207 		s_unlink(SCFGA_LOCK);
1208 		_exit(1);
1209 	}
1210 
1211 	l_errno = 0;
1212 	ret = devctl_cmd(apidp->hba_phys, SCFGA_BUS_UNQUIESCE, NULL, &l_errno);
1213 	if (ret != SCFGA_OK) {
1214 		if (l_errno == EALREADY)
1215 			CFGA_TRACE3((stdout, "child[%d]: bus already "
1216 			    "unquiesced: %s\n", s_getpid(), apidp->hba_phys));
1217 		else
1218 			CFGA_TRACE1((stdout, "child[%d]: unquiesce failed: "
1219 			    "%s\n", s_getpid(), strerror(l_errno)));
1220 	} else {
1221 		CFGA_TRACE1((stdout, "child[%d]: unquiesced bus: %s\n",
1222 		    s_getpid(), apidp->hba_phys));
1223 	}
1224 
1225 	s_unlink(SCFGA_LOCK);
1226 
1227 	CFGA_TRACE2((stdout, "child[%d]: _exit(0)\n", s_getpid()));
1228 
1229 	_exit(0);
1230 }
1231 
1232 static void
1233 sigblk(sigset_t *osp)
1234 {
1235 	sigset_t set;
1236 
1237 	(void) sigemptyset(&set);
1238 	(void) sigemptyset(osp);
1239 	(void) sigaddset(&set, SIGHUP);
1240 	(void) sigaddset(&set, SIGINT);
1241 	(void) sigaddset(&set, SIGQUIT);
1242 	(void) sigaddset(&set, SIGTERM);
1243 	(void) sigaddset(&set, SIGUSR1);
1244 	(void) sigaddset(&set, SIGUSR2);
1245 	(void) sigprocmask(SIG_BLOCK, &set, osp);
1246 }
1247 
1248 static void
1249 sigunblk(sigset_t *osp)
1250 {
1251 	(void) sigprocmask(SIG_SETMASK, osp, NULL);
1252 }
1253 
1254 /*
1255  * Here is the algorithm used to ensure that a SCSI bus is not
1256  * left in the quiesced state:
1257  *
1258  *	lock quiesce mutex	// single threads this code
1259  *	open(O_CREAT|O_EXCL) lock file	// only 1 process at a time
1260  *	exclusive record lock on lock file
1261  *	fork1()
1262  *	quiesce bus
1263  *	do the physical hotplug operation
1264  *	unquiesce bus
1265  *	unlock record lock
1266  *		-> *child*
1267  *		-> wait for record lock
1268  *		-> unconditionally unquiesce bus
1269  *		-> unlink lock file
1270  *		-> exit
1271  *	wait for child to exit
1272  *	unlock quiesce mutex
1273  *
1274  * NOTE1: since record locks are per-process and a close() can
1275  * release a lock, to keep things MT-safe we need a quiesce mutex.
1276  *
1277  * NOTE2: To ensure that the child does not unquiesce a bus quiesced
1278  * by an unrelated cfgadm_scsi operation, exactly 1 process in the
1279  * system can be doing an implicit quiesce operation  The exclusive
1280  * creation of the lock file guarantees this.
1281  *
1282  * NOTE3: This works even if the parent process dumps core and/or is
1283  * abnormally terminated. If the parent dies before the child is
1284  * forked, the bus is not quiesced. If the parent dies after the
1285  * bus is quiesced, the child process will ensure that the bus is
1286  * unquiesced.
1287  */
1288 static scfga_ret_t
1289 dev_hotplug(
1290 	apid_t *apidp,
1291 	prompt_t *pt,
1292 	cfga_flags_t flags,
1293 	int do_quiesce,
1294 	char **errstring)
1295 {
1296 	scfga_ret_t	ret;
1297 	pid_t		cpid;
1298 	int		fd;
1299 	sigset_t	oset;
1300 
1301 	assert(apidp->hba_phys != NULL);
1302 	assert(apidp->path != NULL);
1303 
1304 	/* If no quiesce required, prompt the user to do the operation */
1305 	if (!do_quiesce)
1306 		return (wait_for_hotplug(pt, CONF_NO_QUIESCE));
1307 
1308 	(void) mutex_lock(&quiesce_mutex);
1309 
1310 	ret = create_lock(&fd, pt->msgp, errstring);
1311 	if (ret != SCFGA_OK) {
1312 		(void) mutex_unlock(&quiesce_mutex);
1313 		return (ret);
1314 	}
1315 
1316 	ret = syslock(fd, errstring);
1317 	if (ret != SCFGA_OK) {
1318 		goto bad;
1319 	}
1320 
1321 	/*
1322 	 * block signals in the child. Parent may
1323 	 * exit, causing signal to be sent to child.
1324 	 */
1325 	sigblk(&oset);
1326 
1327 	switch (cpid = fork1()) {
1328 		case 0:
1329 			/* child */
1330 			wait_and_cleanup(fd, apidp);
1331 			_exit(0); /* paranoia */
1332 			/*NOTREACHED*/
1333 		case -1:
1334 			cfga_err(errstring, errno, ERR_FORK, 0);
1335 			sigunblk(&oset);
1336 			ret = SCFGA_LIB_ERR;
1337 			goto bad;
1338 		default:
1339 			/* parent */
1340 			break;
1341 	}
1342 
1343 	sigunblk(&oset);
1344 
1345 	/* We have forked successfully - this is the parent */
1346 	ret = bus_quiesce(apidp, pt, errstring, flags);
1347 
1348 	(void) close(fd);	/* also unlocks */
1349 
1350 	wait_for_child(cpid);
1351 
1352 	(void) mutex_unlock(&quiesce_mutex);
1353 
1354 	return (ret);
1355 bad:
1356 	(void) close(fd);
1357 	s_unlink(SCFGA_LOCK);
1358 	(void) mutex_unlock(&quiesce_mutex);
1359 	return (ret);
1360 }
1361 
1362 /*
1363  * Checks if HBA controls a critical file-system (/, /usr or swap)
1364  * This routine reads /etc/vfstab and is NOT foolproof.
1365  * If an error occurs, assumes that controller is NOT critical.
1366  */
1367 static int
1368 critical_ctrlr(const char *hba_phys)
1369 {
1370 	FILE *fp;
1371 	struct vfstab vfst;
1372 	int vfsret = 1, rv = -1;
1373 	char *bufp;
1374 	const size_t buflen = PATH_MAX;
1375 	char mount[MAXPATHLEN], fstype[MAXPATHLEN], spec[MAXPATHLEN];
1376 
1377 
1378 	if ((bufp = calloc(1, buflen)) == NULL) {
1379 		return (0);
1380 	}
1381 
1382 	fp = NULL;
1383 	if ((fp = fopen(ETC_VFSTAB, "r")) == NULL) {
1384 		rv = 0;
1385 		goto out;
1386 	}
1387 
1388 	while ((vfsret = getvfsent(fp, &vfst)) == 0) {
1389 
1390 		(void) strcpy(mount, S_STR(vfst.vfs_mountp));
1391 		(void) strcpy(fstype, S_STR(vfst.vfs_fstype));
1392 		(void) strcpy(spec, S_STR(vfst.vfs_special));
1393 
1394 		/* Ignore non-critical entries */
1395 		if (strcmp(mount, "/") && strcmp(mount, "/usr") &&
1396 		    strcmp(fstype, "swap")) {
1397 			continue;
1398 		}
1399 
1400 		/* get physical path */
1401 		if (realpath(spec, bufp) == NULL) {
1402 			continue;
1403 		}
1404 
1405 		/* Check if critical partition is on the HBA */
1406 		if (!(rv = hba_dev_cmp(hba_phys, bufp))) {
1407 			break;
1408 		}
1409 	}
1410 
1411 	rv = !vfsret;
1412 
1413 	/*FALLTHRU*/
1414 out:
1415 	S_FREE(bufp);
1416 	if (fp != NULL) {
1417 		(void) fclose(fp);
1418 	}
1419 	return (rv);
1420 }
1421 
1422 /*
1423  * Convert bus state to receptacle state
1424  */
1425 static cfga_stat_t
1426 bus_devctl_to_recep_state(uint_t bus_dc_state)
1427 {
1428 	cfga_stat_t rs;
1429 
1430 	switch (bus_dc_state) {
1431 	case BUS_ACTIVE:
1432 		rs = CFGA_STAT_CONNECTED;
1433 		break;
1434 	case BUS_QUIESCED:
1435 	case BUS_SHUTDOWN:
1436 		rs = CFGA_STAT_DISCONNECTED;
1437 		break;
1438 	default:
1439 		rs = CFGA_STAT_NONE;
1440 		break;
1441 	}
1442 
1443 	return (rs);
1444 }
1445 
1446 static int
1447 add_dev(di_node_t node, void *arg)
1448 {
1449 	int ndevs, len;
1450 	char *path, *p;
1451 	struct larg *largp = (struct larg *)arg;
1452 
1453 	/* ignore hba itself and all detached nodes */
1454 	if (di_parent_node(node) == DI_NODE_NIL ||
1455 	    di_node_state(node) < DS_ATTACHED)
1456 		return (DI_WALK_CONTINUE);
1457 
1458 	if ((path = di_devfs_path(node)) == NULL) {
1459 		largp->ndevs = -1;
1460 		return (DI_WALK_TERMINATE);
1461 	}
1462 
1463 	/* sizeof (DEVICES_DIR) includes the null terminator */
1464 	len = strlen(path) + sizeof (DEVICES_DIR);
1465 	if ((p = malloc(len)) == NULL) {
1466 		di_devfs_path_free(path);
1467 		largp->ndevs = -1;
1468 		return (DI_WALK_TERMINATE);
1469 	}
1470 	(void) snprintf(p, len, "%s%s", DEVICES_DIR, path);
1471 	di_devfs_path_free(path);
1472 
1473 	/* ignore device to be excluded */
1474 	if (largp->dev && strcmp(largp->dev, p) == 0) {
1475 		free(p);
1476 		return (DI_WALK_CONTINUE);
1477 	}
1478 
1479 	/* grow dev_list to allow room for one more device */
1480 	if (alloc_dev_list(largp) != 0) {
1481 		free(p);
1482 		return (DI_WALK_TERMINATE);
1483 	}
1484 	ndevs = largp->ndevs;
1485 	largp->ndevs++;
1486 	largp->dev_list[ndevs] = p;
1487 	largp->dev_list[ndevs + 1] = NULL;
1488 	return (DI_WALK_CONTINUE);
1489 }
1490 
1491 /*
1492  * Get list of children excluding dev_excl (if not null).
1493  */
1494 static int
1495 get_hba_children(char *bus_path, char *dev_excl, char ***dev_listp)
1496 {
1497 	int err, ret;
1498 	walkarg_t u;
1499 	struct larg larg;
1500 
1501 	*dev_listp = NULL;
1502 
1503 	u.node_args.flags = DI_WALK_CLDFIRST;
1504 	u.node_args.fcn = add_dev;
1505 
1506 	larg.ndevs = 0;
1507 	larg.nelem = 0;
1508 	larg.dev = dev_excl;
1509 	larg.dev_list = NULL;
1510 
1511 	ret = walk_tree(bus_path, &larg, DINFOSUBTREE, &u, SCFGA_WALK_NODE,
1512 	    &err);
1513 	if (larg.ndevs == -1) {
1514 		free_dev_list(larg.dev_list);
1515 		return (SCFGA_ERR);
1516 	}
1517 	*dev_listp = larg.dev_list;
1518 	return (ret);
1519 }
1520 
1521 static char *
1522 get_node_path(char *minor_path)
1523 {
1524 	char *path, *cp;
1525 
1526 	if ((path = strdup(minor_path)) == NULL)
1527 		return (NULL);
1528 	if ((cp = strrchr(path, ':')) != NULL)
1529 		*cp = '\0';
1530 	return (path);
1531 }
1532 
1533 /*
1534  * Ensure largp->dev_list has room for one more device.
1535  * Returns 0 on success, -1 on failure.
1536  */
1537 static int
1538 alloc_dev_list(struct larg *largp)
1539 {
1540 	int nelem;
1541 	char **p;
1542 
1543 	if (largp->nelem > largp->ndevs + 2)	/* +1 for NULL termination */
1544 		return (0);
1545 
1546 	nelem =  largp->nelem + 16;
1547 	p = realloc(largp->dev_list, nelem * sizeof (char *));
1548 	if (p == NULL)
1549 		return (-1);
1550 
1551 	largp->dev_list = p;
1552 	largp->nelem = nelem;
1553 	return (0);
1554 }
1555 
1556 static void
1557 free_dev_list_elements(char **dev_list)
1558 {
1559 	while (*dev_list) {
1560 		free(*dev_list);
1561 		dev_list++;
1562 	}
1563 }
1564 
1565 static void
1566 free_dev_list(char **dev_list)
1567 {
1568 	if (dev_list == NULL)
1569 		return;
1570 
1571 	free_dev_list_elements(dev_list);
1572 	free(dev_list);
1573 }
1574