xref: /illumos-gate/usr/src/cmd/stmsboot/stmsboot.sh (revision 8a8d276f)
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
463USERID=`id | $EGREP "uid=0"`
464if [ -z "$USERID" ]; then
465	gettext "You must be super-user to run this script.\n" 1>&2
466	exit 1
467fi
468
469# just a sanity check
470if [ ! -f $STMSBOOTUTIL -o ! -f $STMSMETHODSCRIPT ]; then
471	fmt=`gettext "Can't find %s and/or %s"`
472	printf "$fmt\n" "$STMSBOOTUTIL" "$STMSMETHODSCRIPT" 1>&2
473	exit 1
474fi
475
476# If the old sun4u-specific SMF method is found, remove it
477$SVCCFG -s "platform/sun4u/mpxio-upgrade:default" < /dev/null > /dev/null 2>&1
478if [ $? -eq 0 ]; then
479	$SVCCFG delete "platform/sun4u/mpxio-upgrade:default" > /dev/null 2>&1
480fi
481
482# now import the new service, if necessary
483$SVCPROP -q $STMSINSTANCE < /dev/null > /dev/null 2>&1
484if [ $? -ne 0 ]; then
485	if [ -f /var/svc/manifest/system/device/mpxio-upgrade.xml ]; then
486		$SVCCFG import /var/svc/manifest/system/device/mpxio-upgrade.xml
487		if [ $? -ne 0 ]; then
488			fmt=`gettext "Unable to import %s service"`
489			printf "$fmt\n" "$STMSINSTANCE" 1>&2
490			exit 1
491		else
492			fmt=`gettext "Service %s imported successfully, continuing"`
493			printf "$fmt\n" "$STMSINSTANCE" 1>&2
494		fi
495	else
496		fmt=`gettext "Service %s does not exist on this host"`
497 		printf "$fmt\n" "$STMSINSTANCE" 1>&2
498		exit 1
499	fi
500fi
501
502if [ "x$cmd" = xenable -o "x$cmd" = xdisable -o "x$cmd" = xupdate ]; then
503	#
504	# The bootup script doesn't work on cache-only-clients as the script
505	# is executed before the plumbing for cachefs mounting of root is done.
506	#
507	if $MOUNT -v | $EGREP -s " on / type (nfs|cachefs) "; then
508		gettext "This command option is not supported on systems with nfs or cachefs mounted root filesystem.\n" 1>&2
509		exit 1
510	fi
511
512	# if the user has left the system with the mpxio-upgrade service
513	# in a temporarily disabled state (ie, service is armed for the next
514	# reboot), then let them know. We need to ensure that the system is
515	# is in a sane state before allowing any further invocations, so
516	# try to get the system admin to do so
517
518	ISARMED=`$SVCS -l $STMSINSTANCE |$GREP "enabled.*temporary"`
519	if [ $? -eq 0 ]; then
520		echo ""
521		echo "You need the reboot the system in order to complete"
522		echo "the previous invocation of stmsboot."
523		echo ""
524		echo "Do you wish to reboot the system now? (y/n, default y) \c"
525		read response
526
527		if [ "x$response" = "x" -o "x$response" = "xY" -o \
528		    "x$response" = "xy" ]; then
529			/usr/sbin/reboot
530		else
531			/bin/echo ""
532			/bin/echo "Please reboot this system before continuing"
533			/bin/echo ""
534			exit 1
535		fi
536	fi
537
538	if [ -d $SAVEDIR ]; then
539		#
540		# keep a copy of the last saved files, useful for manual
541		# recovery in case of a problem.
542		#
543		for d in $DRVLIST; do
544			DRVCONF=$d.conf
545			KDRVCONF=/kernel/drv/$d.conf
546			TMPDRVCONF=/var/run/tmp.$d.conf.$$
547			TMPDRVCONF_MPXIO_ENTRY=/var/run/tmp.$d.conf.mpxioentry.$$;
548
549			if [ "x$MACH" = "xsparc" ]; then
550				backup_lastsaved $KDRVCONF $VFSTAB
551			else
552				backup_lastsaved $KDRVCONF $VFSTAB $BOOTENV_FILE
553			fi
554		done
555	else
556		mkdir $SAVEDIR
557	fi
558
559fi
560
561if [ "x$cmd" = xenable -o "x$cmd" = xdisable ]; then
562
563	msgneeded=`echo "$DRVLIST" |grep " "`
564	if [ -n "$msgneeded" ]; then
565		emit_driver_warning_msg
566	fi
567	for d in $DRVLIST; do
568		configure_mpxio $cmd $d
569	done
570
571	if [ $reboot_needed -ne 0 ]; then
572
573		# Need to update bootpath on x86 if our boot device is
574		# now accessed through mpxio.
575		# Only update bootpath before reboot when mpxio is enabled
576		# If mpxio is currently disabled, we will update bootpath
577		# on reboot in the mpxio-upgrade service
578
579		if [ "x$MACH" = "xi386" -a "x$cmd" = "xdisable" ]; then
580			get_newbootpath_for_stmsdev
581			if [ $? -ne 0 ]; then
582				rm -f $TMPDRVCONF > /dev/null 2>&1
583				gettext "failed to update bootpath.\n" 1>&2
584				gettext "No changes were made to your STMS configuration.\n" 1>&2
585				return 1
586			fi
587		fi
588		update_sysfiles
589	else
590		echo "STMS is already ${cmd}d. No changes or reboots needed"
591	fi
592
593
594elif [ "x$cmd" = xupdate ]; then
595	if [ "x$MACH" = "xi386" ]; then
596	# In this case we always change the bootpath to phci-based
597	# path first. bootpath will later be modified in mpxio-upgrade
598	# to the vhci-based path if mpxio is enabled on root.
599		get_newbootpath_for_stmsdev
600		if [ $? -ne 0 ]; then
601			gettext "failed to update bootpath.\n" 1>&2
602			return 1
603		fi
604	fi
605	update_sysfiles
606
607elif [ "x$cmd" = xlist ]; then
608		$STMSBOOTUTIL $GUID -l $controller
609else
610		$STMSBOOTUTIL $GUID -L
611fi
612
613exit $?
614