xref: /illumos-gate/usr/src/cmd/stmsboot/stmsboot.sh (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
1#!/sbin/sh -p
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26#
27PATH=/usr/bin:/usr/sbin:$PATH; export PATH
28STMSBOOTUTIL=/lib/mpxio/stmsboot_util
29STMSMETHODSCRIPT=/lib/svc/method/mpxio-upgrade
30KDRVCONF=
31DRVCONF=
32TMPDRVCONF=
33TMPDRVCONF_MPXIO_ENTRY=
34TMPDRVCONF_SATA_ENTRY=
35DRVLIST=
36GUID=
37VFSTAB=/etc/vfstab
38SAVEDIR=/etc/mpxio
39RECOVERFILE=$SAVEDIR/recover_instructions
40SVCCFG_RECOVERY=$SAVEDIR/svccfg_recover
41SUPPORTED_DRIVERS="fp|mpt"
42USAGE=`gettext "Usage: stmsboot [-D $SUPPORTED_DRIVERS] -e | -d | -u | -L | -l controller_number"`
43TEXTDOMAIN=SUNW_OST_OSCMD
44export TEXTDOMAIN
45STMSINSTANCE=svc:system/device/mpxio-upgrade:default
46STMSBOOT=/usr/sbin/stmsboot
47BOOTADM=/sbin/bootadm
48MOUNT=/usr/sbin/mount
49EEPROM=/usr/sbin/eeprom
50EGREP=/usr/bin/egrep
51GREP=/usr/bin/grep
52AWK=/usr/bin/awk
53CP=/usr/bin/cp
54LS=/usr/bin/ls
55MV=/usr/bin/mv
56RM=/usr/bin/rm
57SORT=/usr/bin/sort
58UNIQ=/usr/bin/uniq
59EXPR=/usr/bin/expr
60MKDIR=/usr/bin/mkdir
61REBOOT=/usr/sbin/reboot
62SED=/usr/bin/sed
63SVCPROP=/usr/bin/svcprop
64SVCCFG=/usr/sbin/svccfg
65SVCS=/usr/bin/svcs
66SVCADM=/usr/sbin/svcadm
67
68NOW=`/usr/bin/date +%G%m%d_%H%M`
69MACH=`/usr/bin/uname -p`
70BOOTENV_FILE=bootenv.rc
71reboot_needed=0
72new_bootpath=""
73CLIENT_TYPE_PHCI=""
74CLIENT_TYPE_VHCI="/scsi_vhci"
75
76#
77# Copy all entries (including comments) from source driver.conf
78# to destination driver.conf except those entries which contain
79# the mpxio-disable property.
80# Take into consideration entries that spawn more than one line.
81#
82# $1	source driver.conf file
83# $2	destination driver.conf file
84#
85# Returns 0 on success, non zero on failure.
86#
87delete_mpxio_disable_entries()
88{
89	# be careful here, we've got embedded \t characters
90	# in sed's pattern space.
91	$SED '
92		/^[ 	]*#/{ p
93			      d
94			    }
95		s/[ 	]*$//
96		/^$/{ p
97		      d
98		    }
99		/mpxio-disable[ 	]*=.*;$/{ w '$3'
100						  d
101						}
102		/disable-sata-mpxio[ 	]*=.*;$/{ w '$4'
103						  d
104						}
105		/;$/{ p
106		      d
107		    }
108		:rdnext
109		N
110		s/[ 	]*$//
111		/[^;]$/b rdnext
112		/mpxio-disable[ 	]*=/{ s/\n/ /g
113					      w '$3'
114					      d
115					    }
116		' $1 > $2
117
118	return $?
119}
120
121#
122# backup the last saved copy of the specified files.
123# $*	files to backup
124#
125backup_lastsaved()
126{
127	for file in $*
128	do
129		newfile=`basename $file`
130		$CP $file $SAVEDIR/$newfile.$cmd.$NOW
131	done
132}
133
134#
135# build recover instructions
136#
137# $1	1 to include boot script in the instructions
138#	0 otherwise
139#
140build_recover()
141{
142	gettext "Instructions to recover your previous STMS configuration (if in case the system does not boot):\n\n" > $RECOVERFILE
143	echo "\tboot net \c"  >> $RECOVERFILE
144	gettext "(or from a cd/dvd/another disk)\n" >> $RECOVERFILE
145	echo "\tfsck <your-root-device>" >> $RECOVERFILE
146	echo "\tmount <your-root-device> /mnt" >> $RECOVERFILE
147
148	if [ "x$cmd" = xupdate ]; then
149		gettext "\tUndo the modifications you made to STMS configuration.\n\tFor example undo any changes you made to " >> $RECOVERFILE
150		echo "/mnt$KDRVCONF." >> $RECOVERFILE
151	else
152		echo "\tcp /mnt${SAVEDIR}/$DRVCONF.$cmd.$NOW /mnt$KDRVCONF" >> $RECOVERFILE
153	fi
154
155	if [ $1 -eq 1 ]; then
156		echo "\tcp /mnt${SAVEDIR}/vfstab.$cmd.$NOW /mnt$VFSTAB" >> $RECOVERFILE
157
158		echo "repository /mnt/etc/svc/repository.db" > $SVCCFG_RECOVERY
159		echo "select $STMSINSTANCE" >> $SVCCFG_RECOVERY
160		echo "setprop general/enabled=false" >> $SVCCFG_RECOVERY
161		echo "exit" >> $SVCCFG_RECOVERY
162
163		echo "\t$SVCCFG -f /mnt$SVCCFG_RECOVERY" >> $RECOVERFILE
164
165		if [ "x$MACH" = "xi386" -a "x$new_bootpath" != "x" ]; then
166			echo "\tcp /mnt${SAVEDIR}/bootenv.rc.$cmd.$NOW /mnt/boot/solaris/$BOOTENV_FILE" >> $RECOVERFILE
167		fi
168	fi
169
170	rootdisk=`$MOUNT | $GREP "/ on " | cut -f 3 -d " "`
171	echo "\tumount /mnt\n\treboot\n\n${rootdisk} \c" >> $RECOVERFILE
172	gettext "was your root device,\nbut it could be named differently after you boot net.\n" >> $RECOVERFILE
173}
174
175
176#
177# Arrange for /etc/vfstab and dump configuration to be updated
178# during the next reboot. If the cmd is "enable" or "disable", copy
179# $TMPDRVCONF to $KDRVCONF.
180#
181# Returns 0 on success, 1 on failure.
182#
183update_sysfiles()
184{
185
186	gettext "WARNING: This operation will require a reboot.\n"
187	gettext "Do you want to continue ? [y/n] (default: y) "
188	read response
189
190	if [ "x$response" != x -a "x$response" != xy -a \
191	    "x$response" != xY ]; then
192		for d in $DRVLIST; do
193			TMPDRVCONF=/var/run/tmp.$d.conf.$$
194			$RM -f $TMPDRVCONF > /dev/null 2>&1
195		done;
196		return 0;
197	fi
198
199	# set need_bootscript to the number of drivers that
200	# we support.
201	need_bootscript=`echo $SUPPORTED_DRIVERS|$AWK -F"|" '{print NF}'`
202
203	if [ "x$cmd" = xenable -o "x$cmd" = xdisable ]; then
204
205		for d in $DRVLIST; do
206			DRVCONF=$d.conf
207			KDRVCONF=/kernel/drv/$d.conf
208			TMPDRVCONF=/var/run/tmp.$d.conf.$$
209
210			$CP $KDRVCONF $SAVEDIR/`basename $KDRVCONF`.$cmd.$NOW
211			if [ -f $TMPDRVCONF ]; then
212				$CP $TMPDRVCONF $KDRVCONF
213				$RM -f $TMPDRVCONF
214			else
215				# if $TMPDRVCONF doesn't exist, then we
216				# haven't made any changes to it
217				continue;
218			fi
219
220			#
221			# there is no need to update the system files in the following
222			# cases:
223			# - we are enabling mpxio and the system has no configured
224			#   disks accessible by phci paths.
225			# - we are disabling mpxio and the system has no configured
226			#   disks accessible by vhci paths.
227			#
228
229			# Function to setup the CLIENT_TYPE_PHCI string based on
230			# the list of drivers that we're operating on. The variable
231			# depends upon the pathname of the parent node in the
232			# device tree, which can be different on x86/x64 and sparc.
233
234			CLIENT_TYPE_PHCI=`$STMSBOOTUTIL -D $d -N`;
235
236			if [ "x$CLIENT_TYPE_PHCI" = "x" ]; then
237				continue;
238			fi
239
240			if [ "x$cmd" = "xenable" ]; then
241				$LS -l /dev/dsk/*s2 2> /dev/null | \
242				    $EGREP -s "$CLIENT_TYPE_PHCI"
243			else
244				$LS -l /dev/dsk/*s2 2> /dev/null | \
245				    $EGREP -s "$CLIENT_TYPE_VHCI"
246			fi
247
248			if [ $? -ne 0 ]; then
249				need_bootscript=`$EXPR $need_bootscript - 1`
250			fi
251		done
252	fi
253
254	if [ $need_bootscript -gt 0 ]; then
255		need_bootscript=1
256		if [ "x$MACH" = "xi386" -a "x$new_bootpath" != "x" ]; then
257			#only update bootpath for x86.
258			$CP /boot/solaris/$BOOTENV_FILE $SAVEDIR/$BOOTENV_FILE.$cmd.$NOW
259			$EEPROM bootpath="$new_bootpath"
260		fi
261		# Enable the mpxio-upgrade service for the reboot
262		$SVCADM disable -t $STMSINSTANCE
263		$SVCCFG -s $STMSINSTANCE "setprop general/enabled=true"
264	else
265		need_bootscript=0
266	fi
267
268	build_recover $need_bootscript
269
270	if [ "x$MACH" = "xi386" ]; then
271		$BOOTADM update-archive
272	fi
273
274	gettext "The changes will come into effect after rebooting the system.\nReboot the system now ? [y/n] (default: y) "
275	read response
276
277	if [ "x$response" = x -o "x$response" = xy -o \
278	    "x$response" = xY ]; then
279		$REBOOT
280	fi
281
282	return 0
283}
284
285
286#
287# Enable or disable mpxio as specified by the cmd.
288# Returns 0 on success, 1 on failure.
289#
290# Args: $cmd = {enable | disable}
291#	$d = {fp | mpt}
292#
293# the global variable $DRVLIST is used
294#
295configure_mpxio()
296{
297	# be careful here, we've got embedded \t characters
298	# in sed's pattern space.
299	mpxiodisableno='mpxio-disable[ 	]*=[ 	]*"no"[ 	]*;'
300	mpxiodisableyes='mpxio-disable[ 	]*=[ 	]*"yes"[ 	]*;'
301	satadisableno='disable-sata-mpxio[ 	]*=[ 	]*"no"[ 	]*;'
302	satadisableyes='disable-sata-mpxio[ 	]*=[ 	]*"yes"[ 	]*;'
303
304	if [ "x$cmd" = xenable ]; then
305		mpxiodisable_cur_entry=$mpxiodisableyes
306		satadisable_cur_entry=$satadisableyes
307		propval=no
308		msg=`gettext "STMS already enabled"`
309	else
310		mpxiodisable_cur_entry=$mpxiodisableno
311		satadisable_cur_entry=$satadisableno
312		propval=yes
313		msg=`gettext "STMS already disabled"`
314	fi
315
316	DRVCONF=$d.conf
317	KDRVCONF=/kernel/drv/$d.conf
318	TMPDRVCONF=/var/run/tmp.$d.conf.$$
319	TMPDRVCONF_MPXIO_ENTRY=/var/run/tmp.$d.conf.mpxioentry.$$;
320	TMPDRVCONF_SATA_ENTRY=/var/run/tmp.$d.conf.sataentry.$$;
321
322	if delete_mpxio_disable_entries $KDRVCONF $TMPDRVCONF $TMPDRVCONF_MPXIO_ENTRY $TMPDRVCONF_SATA_ENTRY; then
323
324		if [ -s $TMPDRVCONF_MPXIO_ENTRY ]; then
325			# $DRVCONF does have mpxiodisable entries
326			$EGREP -s "$mpxiodisable_cur_entry" $TMPDRVCONF_MPXIO_ENTRY
327			if [ $? -eq 0 ]; then
328				reboot_needed=`$EXPR $reboot_needed + 1`
329			else
330				# if all mpxiodisable entries are no/yes for
331				# enable/disable mpxio, notify the user
332				$EGREP -s "$satadisable_cur_entry" $TMPDRVCONF_SATA_ENTRY
333				if [ $? -eq 0 ]; then
334					reboot_needed=`$EXPR $reboot_needed + 1`
335				else
336					$RM -f $TMPDRVCONF $TMPDRVCONF_MPXIO_ENTRY $TMPDRVCONF_SATA_ENTRY > /dev/null 2>&1
337				fi
338			fi
339
340			# If mpxiodisable entries do not exist, always continue update
341		fi
342	else
343		$RM -f $TMPDRVCONF $TMPDRVCONF_MPXIO_ENTRY $TMPDRVCONF_SATA_ENTRY > /dev/null 2>&1
344		gettext "failed to update " 1>&2
345		echo "$KDRVCONF." 1>&2
346		gettext "No changes were made to your STMS configuration.\n" 1>&2
347		return 1
348	fi
349
350	rm $TMPDRVCONF_MPXIO_ENTRY > /dev/null 2>&1
351	echo "mpxio-disable=\"${propval}\";" >> $TMPDRVCONF
352	echo "disable-sata-mpxio=\"${propval}\";" >> $TMPDRVCONF
353
354}
355
356setcmd()
357{
358	if [ "x$cmd" = xnone ]; then
359		cmd=$1
360	else
361		echo "$USAGE" 1>&2
362		exit 2
363	fi
364}
365
366#
367# Need to update bootpath on x86 if boot system from FC disk
368# Only update bootpath here when mpxio is enabled
369# If mpxio is currently disabled, then we'll update bootpath in the
370# mpxio-upgrade service method on reboot.
371#
372
373get_newbootpath_for_stmsdev() {
374	if [ "x$cmd" = "xenable" ]; then
375		return 0
376	fi
377
378	cur_bootpath=`$STMSBOOTUTIL -b`
379	if [ $? != 0 ]; then
380		return 1
381	fi
382
383	# Since on x64 platforms the eeprom command doesn't update the
384	# kernel, the file /boot/solaris/bootenv.rc and the kernel's
385	# bootpath variable have a good chance of differing. We do some
386	# extra handwaving to get the correct bootpath variable setting.
387
388	ONDISKVER=`$AWK '/bootpath/ {print $3}' /boot/solaris/bootenv.rc|\
389		$SED -e"s,',,g"`
390	if [ "x$ONDISKVER" != "x$cur_bootpath" ]; then
391		cur_bootpath="$ONDISKVER"
392	fi
393
394	NEWBOOTPATH=""
395	for path in $cur_bootpath; do
396		mapped=`$STMSBOOTUTIL -p $path`
397		if [ "$mapped" != "NOT_MAPPED" ]; then
398			if [ "$mapped" != "$path" ]; then
399				NEWBOOTPATH=`echo "$path " | \
400				   $SED -e"s|$path|$mapped|"`" $NEWBOOTPATH"
401			else
402				NEWBOOTPATH="$NEWBOOTPATH $path"
403			fi
404		fi
405	done
406	# now strip off leading and trailing space chars
407	new_bootpath=`echo $NEWBOOTPATH`
408	return 0
409}
410
411#
412# Emit a warning message to the user that by default we
413# operate on all multipath-capable controllers that are
414# attached to the system, and that if they want to operate
415# on only a specific controller type (fp|mpt|....) then
416# they need to re-invoke stmsboot with "-D $driver" in
417# their argument list
418#
419
420emit_driver_warning_msg() {
421
422	# for each driver that we support, grab the list
423	# of controllers attached to the system.
424
425	echo ""
426	gettext "WARNING: stmsboot operates on each supported multipath-capable controller\n"
427	gettext "         detected in a host. In your system, these controllers are\n\n"
428
429	for WARNDRV in `echo $SUPPORTED_DRIVERS| $SED -e"s,|, ,g"`; do
430		$STMSBOOTUTIL -D $WARNDRV -n
431	done;
432
433	echo ""
434	gettext "If you do NOT wish to operate on these controllers, please quit stmsboot\n"
435	gettext "and re-invoke with -D { fp | mpt } to specify which controllers you wish\n"
436	gettext "to modify your multipathing configuration for.\n"
437
438	echo ""
439	gettext "Do you wish to continue? [y/n] (default: y) "
440	read response
441
442	if [ "x$response" != "x" -a "x$response" != "xY" -a \
443	    "x$response" != "xy" ]; then
444		exit
445	fi
446}
447
448
449#
450#
451# main starts here
452#
453
454cmd=none
455# process options
456while getopts D:geduLl: c
457do
458	case $c in
459	e)	setcmd enable;;
460	d)	setcmd disable;;
461	u)	setcmd update;;
462	L)	setcmd listall;;
463	l)	setcmd list
464		controller=$OPTARG;;
465	D)	DRV=$OPTARG;;
466	g)	GUID="-g";;
467	\?)	echo "$USAGE" 1>&2
468		exit 2;;
469	esac
470done
471
472if [ "x$cmd" = xnone ]; then
473	echo "$USAGE" 1>&2
474	exit 2
475fi
476
477if [ "x$DRV" = "x" ]; then
478	DRVLIST="fp mpt"
479else
480	DRVLIST=$DRV
481fi
482
483USERID=`id | $EGREP "uid=0"`
484if [ -z "$USERID" ]; then
485	gettext "You must be super-user to run this script.\n" 1>&2
486	exit 1
487fi
488
489# just a sanity check
490if [ ! -f $STMSBOOTUTIL -o ! -f $STMSMETHODSCRIPT ]; then
491	fmt=`gettext "Can't find %s and/or %s"`
492	printf "$fmt\n" "$STMSBOOTUTIL" "$STMSMETHODSCRIPT" 1>&2
493	exit 1
494fi
495
496# If the old sun4u-specific SMF method is found, remove it
497$SVCCFG -s "platform/sun4u/mpxio-upgrade:default" < /dev/null > /dev/null 2>&1
498if [ $? -eq 0 ]; then
499	$SVCCFG delete "platform/sun4u/mpxio-upgrade:default" > /dev/null 2>&1
500fi
501
502# now import the new service, if necessary
503$SVCPROP -q $STMSINSTANCE < /dev/null > /dev/null 2>&1
504if [ $? -ne 0 ]; then
505	if [ -f /var/svc/manifest/system/device/mpxio-upgrade.xml ]; then
506		$SVCCFG import /var/svc/manifest/system/device/mpxio-upgrade.xml
507		if [ $? -ne 0 ]; then
508			fmt=`gettext "Unable to import the %s service"`
509			printf "$fmt\n" "$STMSINSTANCE" 1>&2
510			exit 1
511		else
512			fmt=`gettext "Service %s imported successfully, continuing"`
513			printf "$fmt\n" "$STMSINSTANCE" 1>&2
514		fi
515	else
516		fmt=`gettext "Service %s does not exist on this host"`
517 		printf "$fmt\n" "$STMSINSTANCE" 1>&2
518		exit 1
519	fi
520fi
521
522
523# make sure we can stash our data somewhere private
524if [ ! -d $SAVEDIR ]; then
525	$MKDIR -p $SAVEDIR
526fi
527# prime the cache
528$STMSBOOTUTIL -i
529
530
531if [ "x$cmd" = xenable -o "x$cmd" = xdisable -o "x$cmd" = xupdate ]; then
532	#
533	# The bootup script doesn't work on cache-only-clients as the script
534	# is executed before the plumbing for cachefs mounting of root is done.
535	#
536	if $MOUNT -v | $EGREP -s " on / type (nfs|cachefs) "; then
537		gettext "This command option is not supported on systems with an nfs or cachefs mounted root filesystem.\n" 1>&2
538		exit 1
539	fi
540
541	# if the user has left the system with the mpxio-upgrade service
542	# in a temporarily disabled state (ie, service is armed for the next
543	# reboot), then let them know. We need to ensure that the system is
544	# is in a sane state before allowing any further invocations, so
545	# try to get the system admin to do so
546
547	ISARMED=`$SVCS -l $STMSINSTANCE|$GREP "enabled.*false.*temporary"`
548	if [ ! $? ]; then
549		echo ""
550		gettext "You need to reboot the system in order to complete\n"
551		gettext "the previous invocation of stmsboot.\n"
552		echo ""
553		gettext "Do you wish to reboot the system now? (y/n, default y) "
554		read response
555
556		if [ "x$response" = "x" -o "x$response" = "xY" -o \
557		    "x$response" = "xy" ]; then
558			$REBOOT
559		else
560			echo ""
561			gettext "Please reboot this system before continuing\n"
562			echo ""
563			exit 1
564		fi
565	fi
566
567	#
568	# keep a copy of the last saved files, useful for manual
569	# recovery in case of a problem.
570	#
571	for d in $DRVLIST; do
572		DRVCONF=$d.conf
573		KDRVCONF=/kernel/drv/$d.conf
574		TMPDRVCONF=/var/run/tmp.$d.conf.$$
575		TMPDRVCONF_MPXIO_ENTRY=/var/run/tmp.$d.conf.mpxioentry.$$;
576		if [ "x$MACH" = "xsparc" ]; then
577			backup_lastsaved $KDRVCONF $VFSTAB
578		else
579			backup_lastsaved $KDRVCONF $VFSTAB /boot/solaris/$BOOTENV_FILE
580		fi
581	done
582fi
583
584if [ "x$cmd" = xenable -o "x$cmd" = xdisable ]; then
585
586	msgneeded=`echo "$DRVLIST" |grep " "`
587	if [ -n "$msgneeded" ]; then
588		emit_driver_warning_msg
589	fi
590	for d in $DRVLIST; do
591		configure_mpxio $cmd $d
592	done
593
594	if [ $reboot_needed -ne 0 ]; then
595		# Need to update bootpath on x86 if our boot device is
596		# now accessed through mpxio.
597		# Only update bootpath before reboot when mpxio is enabled
598		# If mpxio is currently disabled, we will update bootpath
599		# on reboot in the mpxio-upgrade service
600
601		if [ "x$MACH" = "xi386" -a "x$cmd" = "xdisable" ]; then
602			get_newbootpath_for_stmsdev
603			if [ $? -ne 0 ]; then
604				$RM -f $TMPDRVCONF > /dev/null 2>&1
605				gettext "failed to update bootpath.\n" 1>&2
606				gettext "No changes were made to your STMS configuration.\n" 1>&2
607				return 1
608			fi
609		fi
610		update_sysfiles
611	else
612		echo "STMS is already ${cmd}d. No changes or reboots needed"
613	fi
614
615
616elif [ "x$cmd" = xupdate ]; then
617	if [ "x$MACH" = "xi386" ]; then
618	# In this case we always change the bootpath to phci-based
619	# path first. bootpath will later be modified in mpxio-upgrade
620	# to the vhci-based path if mpxio is enabled on root.
621		get_newbootpath_for_stmsdev
622		if [ $? -ne 0 ]; then
623			gettext "failed to update bootpath.\n" 1>&2
624			return 1
625		fi
626	fi
627	update_sysfiles
628
629elif [ "x$cmd" = xlist ]; then
630		$STMSBOOTUTIL $GUID -l $controller
631else
632		$STMSBOOTUTIL $GUID -L
633fi
634
635exit $?
636