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