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