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