xref: /titanic_51/usr/src/cmd/stmsboot/stmsboot.sh (revision dfb96a4f56fb431b915bc67e5d9d5c8d4f4f6679)
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 [ $need_bootscript -gt 0 ]; then
246		need_bootscript=1
247		if [ "x$MACH" = "xi386" -a "x$new_bootpath" != "x" ]; then
248			#only update bootpath for x86.
249			cp $BOOTENV_FILE $SAVEDIR
250			/usr/sbin/eeprom bootpath=$new_bootpath
251		fi
252		#
253		# Enable the mpxio-upgrade service, but don't run it now.
254		# The service will run during the next reboot and will do
255		# the actual job of modifying the system files.
256		#
257		$SVCADM disable -t $STMSINSTANCE
258		$SVCCFG -f - << EOF
259select $STMSINSTANCE
260setprop general/enabled = true
261EOF
262	else
263		need_bootscript=0
264	fi
265
266	build_recover $need_bootscript
267
268	if [ "x$MACH" = "xi386" ]; then
269		$BOOTADM update-archive
270	fi
271
272	gettext "The changes will come into effect after rebooting the system.\nReboot the system now ? [y/n] (default: y) "
273	read response
274
275	if [ "x$response" = x -o "x$response" = xy -o \
276	    "x$response" = xY ]; then
277		/usr/sbin/reboot
278	fi
279
280	return 0
281}
282
283#
284# Enable or disable mpxio as specified by the cmd.
285# Returns 0 on success, 1 on failure.
286#
287# Args: $cmd = {enable | disable}
288#	$d = {fp | mpt}
289#
290# the global variable $DRVLIST is used
291#
292configure_mpxio()
293{
294	mpxiodisableno='mpxio-disable[ 	]*=[ 	]*"no"[ 	]*;'
295	mpxiodisableyes='mpxio-disable[ 	]*=[ 	]*"yes"[ 	]*;'
296
297	if [ "x$cmd" = xenable ]; then
298		mpxiodisable_cur_entry=$mpxiodisableyes
299		propval=no
300		msg=`gettext "STMS already enabled"`
301	else
302		mpxiodisable_cur_entry=$mpxiodisableno
303		propval=yes
304		msg=`gettext "STMS already disabled"`
305	fi
306
307	DRVCONF=$d.conf
308	KDRVCONF=/kernel/drv/$d.conf
309	TMPDRVCONF=/var/run/tmp.$d.conf.$$
310	TMPDRVCONF_MPXIO_ENTRY=/var/run/tmp.$d.conf.mpxioentry.$$;
311
312	echo "Checking mpxio status for driver $d"
313	if delete_mpxio_disable_entries $KDRVCONF $TMPDRVCONF $TMPDRVCONF_MPXIO_ENTRY; then
314
315		if [ -s $TMPDRVCONF_MPXIO_ENTRY ]; then
316			# $DRVCONF does have mpxiodisable entries
317			$EGREP -s "$mpxiodisable_cur_entry" $TMPDRVCONF_MPXIO_ENTRY
318			if [ $? -ne 0 ]; then
319				# if all mpxiodisable entries are no/yes for
320				# enable/disable mpxio, notify the user
321				rm -f $TMPDRVCONF $TMPDRVCONF_MPXIO_ENTRY > /dev/null 2>&1
322				continue;
323			else
324				reboot_needed=`$EXPR $reboot_needed + 1`
325			fi
326
327			# If mpxiodisable entries do not exist, always continue update
328		fi
329	else
330		rm -f $TMPDRVCONF $TMPDRVCONF_MPXIO_ENTRY > /dev/null 2>&1
331		gettext "failed to update " 1>&2
332		echo "$KDRVCONF." 1>&2
333		gettext "No changes were made to your STMS configuration.\n" 1>&2
334		return 1
335	fi
336
337	rm $TMPDRVCONF_MPXIO_ENTRY > /dev/null 2>&1
338	echo "mpxio-disable=\"${propval}\";" >> $TMPDRVCONF
339
340}
341
342setcmd()
343{
344	if [ "x$cmd" = xnone ]; then
345		cmd=$1
346	else
347		echo "$USAGE" 1>&2
348		exit 2
349	fi
350}
351
352#
353#Need to update bootpath on x86 if boot system from FC disk
354#Only update bootpath here when mpxio is enabled
355#If mpxio is disabled currently, will update bootpath in mpxio-upgrade
356#
357
358get_newbootpath_for_stmsdev() {
359	if [ "x$cmd" = "xenable" ]; then
360		return 0
361	fi
362
363	cur_bootpath=`eeprom bootpath | \
364	    sed 's/bootpath=[ 	]*//g' | sed 's/[ 	]*$//'`
365	if [ "x$cur_bootpath" = "x" ]; then
366		gettext "failed to get bootpath by eeprom\n" 1>&2
367		return 1
368	fi
369
370	#only update bootpath for STMS path
371	echo $cur_bootpath|$EGREP $CLIENT_TYPE_VHCI > /dev/null 2>&1
372	if [ $? -eq 1 ]; then
373		return 0
374	fi
375
376	new_bootpath=`$STMSBOOTUTIL -p /devices$cur_bootpath`
377	if [ $? -ne 0 ]; then
378		new_bootpath=""
379		return 1
380	fi
381
382	# we replace "sd" with "disk" if we need to work on the eeprom
383	# bootpath setting, since fibre-channel devices will report as
384	# being attached via "disk" and not "sd". One day we'll have a
385	# truly unified and architecture-independent view of the device
386	# tree, and this block will be redundant
387	fp_bootpath=`echo $new_bootpath|grep fp.*sd`
388	if [ "x$fp_bootpath" != "x" ]; then
389		new_bootpath=`echo $fp_bootpath |sed -e"s,sd,disk,g"`
390	fi
391}
392
393#
394# Emit a warning message to the user that by default we
395# operate on all multipath-capable controllers that are
396# attached to the system, and that if they want to operate
397# on only a specific controller type (fp|mpt|....) then
398# they need to re-invoke stmsboot with "-D $driver" in
399# their argument list
400#
401
402emit_driver_warning_msg() {
403
404	# for each driver that we support, grab the list
405	# of controllers attached to the system.
406
407	echo ""
408	echo "WARNING: stmsboot operates on each supported multipath-capable controller"
409	echo "         detected in a host. In your system, these controllers are"
410
411	for WARNDRV in `echo $SUPPORTED_DRIVERS| $SED -e"s,|, ,g"`; do
412		for i in `$STMSBOOTUTIL -D $WARNDRV -n | $SED -e"s,|, ,g"`; do
413			$GREP "$i.*$WARNDRV.$" /etc/path_to_inst | $AWK -F"\"" '{print "/devices"$2}'
414		done;
415	done;
416
417	echo ""
418	echo "If you do NOT wish to operate on these controllers, please quit stmsboot"
419	echo "and re-invoke with -D { fp | mpt } to specify which controllers you wish"
420	echo "to modify your multipathing configuration for."
421
422	echo ""
423	gettext "Do you wish to continue? [y/n] (default: y) " 1>&2
424	read response
425
426	if [ "x$response" != "x" -a "x$response" != "xY" -a \
427	    "x$response" != "xy" ]; then
428		exit
429	fi
430
431}
432
433cmd=none
434
435# process options
436while getopts D:geduLl: c
437do
438	case $c in
439	e)	setcmd enable;;
440	d)	setcmd disable;;
441	u)	setcmd update;;
442	L)	setcmd listall;;
443	l)	setcmd list
444		controller=$OPTARG;;
445	D)	DRV=$OPTARG;;
446	g)	GUID="-g";;
447	\?)	echo "$USAGE" 1>&2
448		exit 2;;
449	esac
450done
451
452if [ "x$cmd" = xnone ]; then
453	echo "$USAGE" 1>&2
454	exit 2
455fi
456
457if [ "x$DRV" = "x" ]; then
458	DRVLIST="fp mpt"
459else
460	DRVLIST=$DRV
461fi
462
463
464STMSPRIVS=`/usr/bin/ppriv $$ | $EGREP "E:.*all|E:.*sys_devices"`
465USERID=`id`
466if [ "$USERID" != "uid=0(root) gid=0(root)" ] -o [ "x$STMSPRIVS" == "x" ]; then
467	gettext "You must be super-user to run this script.\n" 1>&2
468	exit 1
469fi
470
471# just a sanity check
472if [ ! -f $STMSBOOTUTIL -o ! -f $STMSMETHODSCRIPT ]; then
473	fmt=`gettext "Can't find %s and/or %s"`
474	printf "$fmt\n" "$STMSBOOTUTIL" "$STMSMETHODSCRIPT" 1>&2
475	exit 1
476fi
477
478# If the old sun4u-specific SMF method is found, remove it
479$SVCCFG -s "platform/sun4u/mpxio-upgrade:default" < /dev/null > /dev/null 2>&1
480if [ $? -eq 0 ]; then
481	$SVCCFG delete "platform/sun4u/mpxio-upgrade:default" > /dev/null 2>&1
482fi
483
484# now import the new service, if necessary
485$SVCPROP -q $STMSINSTANCE < /dev/null > /dev/null 2>&1
486if [ $? -ne 0 ]; then
487	if [ -f /var/svc/manifest/system/device/mpxio-upgrade.xml ]; then
488		$SVCCFG import /var/svc/manifest/system/device/mpxio-upgrade.xml
489		if [ $? -ne 0 ]; then
490			fmt=`gettext "Unable to import %s service"`
491			printf "$fmt\n" "$STMSINSTANCE" 1>&2
492			exit 1
493		else
494			fmt=`gettext "Service %s imported successfully, continuing"`
495			printf "$fmt\n" "$STMSINSTANCE" 1>&2
496		fi
497	else
498		fmt=`gettext "Service %s does not exist on this host"`
499 		printf "$fmt\n" "$STMSINSTANCE" 1>&2
500		exit 1
501	fi
502fi
503
504if [ "x$cmd" = xenable -o "x$cmd" = xdisable -o "x$cmd" = xupdate ]; then
505	#
506	# The bootup script doesn't work on cache-only-clients as the script
507	# is executed before the plumbing for cachefs mounting of root is done.
508	#
509	if $MOUNT -v | $EGREP -s " on / type (nfs|cachefs) "; then
510		gettext "This command option is not supported on systems with nfs or cachefs mounted root filesystem.\n" 1>&2
511		exit 1
512	fi
513
514	# if the user has left the system with the mpxio-upgrade service
515	# in a temporarily disabled state (ie, service is armed for the next
516	# reboot), then let them know. We need to ensure that the system is
517	# is in a sane state before allowing any further invocations, so
518	# try to get the system admin to do so
519
520	ISARMED=`$SVCS -l $STMSINSTANCE |$GREP "enabled.*temporary"`
521	if [ $? -eq 0 ]; then
522		echo ""
523		echo "You need the reboot the system in order to complete"
524		echo "the previous invocation of stmsboot."
525		echo ""
526		echo "Do you wish to reboot the system now? (y/n, default y) \c"
527		read response
528
529		if [ "x$response" = "x" -o "x$response" = "xY" -o \
530		    "x$response" = "xy" ]; then
531			/usr/sbin/reboot
532		else
533			/bin/echo ""
534			/bin/echo "Please reboot this system before continuing"
535			/bin/echo ""
536			exit 1
537		fi
538	fi
539
540	if [ -d $SAVEDIR ]; then
541		#
542		# keep a copy of the last saved files, useful for manual
543		# recovery in case of a problem.
544		#
545		for d in $DRVLIST; do
546			DRVCONF=$d.conf
547			KDRVCONF=/kernel/drv/$d.conf
548			TMPDRVCONF=/var/run/tmp.$d.conf.$$
549			TMPDRVCONF_MPXIO_ENTRY=/var/run/tmp.$d.conf.mpxioentry.$$;
550
551			if [ "x$MACH" = "xsparc" ]; then
552				backup_lastsaved $KDRVCONF $VFSTAB
553			else
554				backup_lastsaved $KDRVCONF $VFSTAB $BOOTENV_FILE
555			fi
556		done
557	else
558		mkdir $SAVEDIR
559	fi
560
561fi
562
563if [ "x$cmd" = xenable -o "x$cmd" = xdisable ]; then
564
565	msgneeded=`echo "$DRVLIST" |grep " "`
566	if [ -n "$msgneeded" ]; then
567		emit_driver_warning_msg
568	fi
569	for d in $DRVLIST; do
570		configure_mpxio $cmd $d
571	done
572
573	if [ $reboot_needed -ne 0 ]; then
574
575		# Need to update bootpath on x86 if our boot device is
576		# now accessed through mpxio.
577		# Only update bootpath before reboot when mpxio is enabled
578		# If mpxio is currently disabled, we will update bootpath
579		# on reboot in the mpxio-upgrade service
580
581		if [ "x$MACH" = "xi386" -a "x$cmd" = "xdisable" ]; then
582			get_newbootpath_for_stmsdev
583			if [ $? -ne 0 ]; then
584				rm -f $TMPDRVCONF > /dev/null 2>&1
585				gettext "failed to update bootpath.\n" 1>&2
586				gettext "No changes were made to your STMS configuration.\n" 1>&2
587				return 1
588			fi
589		fi
590		update_sysfiles
591	else
592		echo "STMS is already ${cmd}d. No changes or reboots needed"
593	fi
594
595
596elif [ "x$cmd" = xupdate ]; then
597	if [ "x$MACH" = "xi386" ]; then
598	# In this case we always change the bootpath to phci-based
599	# path first. bootpath will later be modified in mpxio-upgrade
600	# to the vhci-based path if mpxio is enabled on root.
601		get_newbootpath_for_stmsdev
602		if [ $? -ne 0 ]; then
603			gettext "failed to update bootpath.\n" 1>&2
604			return 1
605		fi
606	fi
607	update_sysfiles
608
609elif [ "x$cmd" = xlist ]; then
610		$STMSBOOTUTIL $GUID -l $controller
611else
612		$STMSBOOTUTIL $GUID -L
613fi
614
615exit $?
616