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