xref: /freebsd-src/sys/contrib/openzfs/udev/vdev_id (revision 87bf66d4a7488c496af110d4d05cc0273d49f82e)
1716fd348SMartin Matuska#!/bin/sh
2716fd348SMartin Matuska#
3716fd348SMartin Matuska# vdev_id: udev helper to generate user-friendly names for JBOD disks
4716fd348SMartin Matuska#
5716fd348SMartin Matuska# This script parses the file /etc/zfs/vdev_id.conf to map a
6716fd348SMartin Matuska# physical path in a storage topology to a channel name.  The
7716fd348SMartin Matuska# channel name is combined with a disk enclosure slot number to
8716fd348SMartin Matuska# create an alias that reflects the physical location of the drive.
9716fd348SMartin Matuska# This is particularly helpful when it comes to tasks like replacing
10716fd348SMartin Matuska# failed drives.  Slot numbers may also be re-mapped in case the
11716fd348SMartin Matuska# default numbering is unsatisfactory.  The drive aliases will be
12716fd348SMartin Matuska# created as symbolic links in /dev/disk/by-vdev.
13716fd348SMartin Matuska#
14716fd348SMartin Matuska# The currently supported topologies are sas_direct and sas_switch.
15716fd348SMartin Matuska# A multipath mode is supported in which dm-mpath devices are
16716fd348SMartin Matuska# handled by examining the first-listed running component disk.  In
17716fd348SMartin Matuska# multipath mode the configuration file should contain a channel
18716fd348SMartin Matuska# definition with the same name for each path to a given enclosure.
19716fd348SMartin Matuska#
20716fd348SMartin Matuska# The alias keyword provides a simple way to map already-existing
21716fd348SMartin Matuska# device symlinks to more convenient names.  It is suitable for
22716fd348SMartin Matuska# small, static configurations or for sites that have some automated
23716fd348SMartin Matuska# way to generate the mapping file.
24716fd348SMartin Matuska#
25716fd348SMartin Matuska#
26716fd348SMartin Matuska# Some example configuration files are given below.
27716fd348SMartin Matuska
28716fd348SMartin Matuska# #
29716fd348SMartin Matuska# # Example vdev_id.conf - sas_direct.
30716fd348SMartin Matuska# #
31716fd348SMartin Matuska#
32716fd348SMartin Matuska# multipath     no
33716fd348SMartin Matuska# topology      sas_direct
34716fd348SMartin Matuska# phys_per_port 4
35716fd348SMartin Matuska# slot          bay
36716fd348SMartin Matuska#
37716fd348SMartin Matuska# #       PCI_ID  HBA PORT  CHANNEL NAME
38716fd348SMartin Matuska# channel 85:00.0 1         A
39716fd348SMartin Matuska# channel 85:00.0 0         B
40716fd348SMartin Matuska# channel 86:00.0 1         C
41716fd348SMartin Matuska# channel 86:00.0 0         D
42716fd348SMartin Matuska#
43716fd348SMartin Matuska# # Custom mapping for Channel A
44716fd348SMartin Matuska#
45716fd348SMartin Matuska# #    Linux      Mapped
46716fd348SMartin Matuska# #    Slot       Slot      Channel
47716fd348SMartin Matuska# slot 1          7         A
48716fd348SMartin Matuska# slot 2          10        A
49716fd348SMartin Matuska# slot 3          3         A
50716fd348SMartin Matuska# slot 4          6         A
51716fd348SMartin Matuska#
52716fd348SMartin Matuska# # Default mapping for B, C, and D
53716fd348SMartin Matuska# slot 1          4
54716fd348SMartin Matuska# slot 2          2
55716fd348SMartin Matuska# slot 3          1
56716fd348SMartin Matuska# slot 4          3
57716fd348SMartin Matuska
58716fd348SMartin Matuska# #
59716fd348SMartin Matuska# # Example vdev_id.conf - sas_switch
60716fd348SMartin Matuska# #
61716fd348SMartin Matuska#
62716fd348SMartin Matuska# topology      sas_switch
63716fd348SMartin Matuska#
64716fd348SMartin Matuska# #       SWITCH PORT  CHANNEL NAME
65716fd348SMartin Matuska# channel 1            A
66716fd348SMartin Matuska# channel 2            B
67716fd348SMartin Matuska# channel 3            C
68716fd348SMartin Matuska# channel 4            D
69716fd348SMartin Matuska
70716fd348SMartin Matuska# #
71716fd348SMartin Matuska# # Example vdev_id.conf - multipath
72716fd348SMartin Matuska# #
73716fd348SMartin Matuska#
74716fd348SMartin Matuska# multipath yes
75716fd348SMartin Matuska#
76716fd348SMartin Matuska# #       PCI_ID  HBA PORT  CHANNEL NAME
77716fd348SMartin Matuska# channel 85:00.0 1         A
78716fd348SMartin Matuska# channel 85:00.0 0         B
79716fd348SMartin Matuska# channel 86:00.0 1         A
80716fd348SMartin Matuska# channel 86:00.0 0         B
81716fd348SMartin Matuska
82716fd348SMartin Matuska# #
83716fd348SMartin Matuska# # Example vdev_id.conf - multipath / multijbod-daisychaining
84716fd348SMartin Matuska# #
85716fd348SMartin Matuska#
86716fd348SMartin Matuska# multipath yes
87716fd348SMartin Matuska# multijbod yes
88716fd348SMartin Matuska#
89716fd348SMartin Matuska# #       PCI_ID  HBA PORT  CHANNEL NAME
90716fd348SMartin Matuska# channel 85:00.0 1         A
91716fd348SMartin Matuska# channel 85:00.0 0         B
92716fd348SMartin Matuska# channel 86:00.0 1         A
93716fd348SMartin Matuska# channel 86:00.0 0         B
94716fd348SMartin Matuska
95716fd348SMartin Matuska# #
96716fd348SMartin Matuska# # Example vdev_id.conf - multipath / mixed
97716fd348SMartin Matuska# #
98716fd348SMartin Matuska#
99716fd348SMartin Matuska# multipath yes
100716fd348SMartin Matuska# slot mix
101716fd348SMartin Matuska#
102716fd348SMartin Matuska# #       PCI_ID  HBA PORT  CHANNEL NAME
103716fd348SMartin Matuska# channel 85:00.0 3         A
104716fd348SMartin Matuska# channel 85:00.0 2         B
105716fd348SMartin Matuska# channel 86:00.0 3         A
106716fd348SMartin Matuska# channel 86:00.0 2         B
107716fd348SMartin Matuska# channel af:00.0 0         C
108716fd348SMartin Matuska# channel af:00.0 1         C
109716fd348SMartin Matuska
110716fd348SMartin Matuska# #
111716fd348SMartin Matuska# # Example vdev_id.conf - alias
112716fd348SMartin Matuska# #
113716fd348SMartin Matuska#
114716fd348SMartin Matuska# #     by-vdev
115716fd348SMartin Matuska# #     name     fully qualified or base name of device link
116716fd348SMartin Matuska# alias d1       /dev/disk/by-id/wwn-0x5000c5002de3b9ca
117716fd348SMartin Matuska# alias d2       wwn-0x5000c5002def789e
118716fd348SMartin Matuska
119716fd348SMartin MatuskaPATH=/bin:/sbin:/usr/bin:/usr/sbin
120716fd348SMartin MatuskaCONFIG=/etc/zfs/vdev_id.conf
121716fd348SMartin MatuskaPHYS_PER_PORT=
122716fd348SMartin MatuskaDEV=
123716fd348SMartin MatuskaTOPOLOGY=
124716fd348SMartin MatuskaBAY=
125716fd348SMartin MatuskaENCL_ID=""
126716fd348SMartin MatuskaUNIQ_ENCL_ID=""
127*87bf66d4SMartin MatuskaZPAD=1
128716fd348SMartin Matuska
129716fd348SMartin Matuskausage() {
130716fd348SMartin Matuska	cat << EOF
131716fd348SMartin MatuskaUsage: vdev_id [-h]
132716fd348SMartin Matuska       vdev_id <-d device> [-c config_file] [-p phys_per_port]
133716fd348SMartin Matuska               [-g sas_direct|sas_switch|scsi] [-m]
134716fd348SMartin Matuska
135716fd348SMartin Matuska  -c    specify name of an alternative config file [default=$CONFIG]
136716fd348SMartin Matuska  -d    specify basename of device (i.e. sda)
137716fd348SMartin Matuska  -e    Create enclose device symlinks only (/dev/by-enclosure)
138716fd348SMartin Matuska  -g    Storage network topology [default="$TOPOLOGY"]
139716fd348SMartin Matuska  -m    Run in multipath mode
140716fd348SMartin Matuska  -j    Run in multijbod mode
141716fd348SMartin Matuska  -p    number of phy's per switch port [default=$PHYS_PER_PORT]
142716fd348SMartin Matuska  -h    show this summary
143716fd348SMartin MatuskaEOF
144716fd348SMartin Matuska	exit 1
145716fd348SMartin Matuska	# exit with error to avoid processing usage message by a udev rule
146716fd348SMartin Matuska}
147716fd348SMartin Matuska
148716fd348SMartin Matuskamap_slot() {
149716fd348SMartin Matuska	LINUX_SLOT=$1
150716fd348SMartin Matuska	CHANNEL=$2
151716fd348SMartin Matuska
152716fd348SMartin Matuska	MAPPED_SLOT=$(awk -v linux_slot="$LINUX_SLOT" -v channel="$CHANNEL" \
153716fd348SMartin Matuska			'$1 == "slot" && $2 == linux_slot && \
154716fd348SMartin Matuska			($4 ~ "^"channel"$" || $4 ~ /^$/) { print $3; exit}' $CONFIG)
155716fd348SMartin Matuska	if [ -z "$MAPPED_SLOT" ] ; then
156716fd348SMartin Matuska		MAPPED_SLOT=$LINUX_SLOT
157716fd348SMartin Matuska	fi
158*87bf66d4SMartin Matuska	printf "%0${ZPAD}d" "${MAPPED_SLOT}"
159716fd348SMartin Matuska}
160716fd348SMartin Matuska
161716fd348SMartin Matuskamap_channel() {
162716fd348SMartin Matuska	MAPPED_CHAN=
163716fd348SMartin Matuska	PCI_ID=$1
164716fd348SMartin Matuska	PORT=$2
165716fd348SMartin Matuska
166716fd348SMartin Matuska	case $TOPOLOGY in
167716fd348SMartin Matuska		"sas_switch")
168716fd348SMartin Matuska		MAPPED_CHAN=$(awk -v port="$PORT" \
169716fd348SMartin Matuska			'$1 == "channel" && $2 == port \
170716fd348SMartin Matuska			{ print $3; exit }' $CONFIG)
171716fd348SMartin Matuska		;;
172716fd348SMartin Matuska		"sas_direct"|"scsi")
173716fd348SMartin Matuska		MAPPED_CHAN=$(awk -v pciID="$PCI_ID" -v port="$PORT" \
174716fd348SMartin Matuska			'$1 == "channel" && $2 == pciID && $3 == port \
175716fd348SMartin Matuska			{print $4}' $CONFIG)
176716fd348SMartin Matuska		;;
177716fd348SMartin Matuska	esac
178716fd348SMartin Matuska	printf "%s" "${MAPPED_CHAN}"
179716fd348SMartin Matuska}
180716fd348SMartin Matuska
181716fd348SMartin Matuskaget_encl_id() {
182716fd348SMartin Matuska	set -- $(echo $1)
183716fd348SMartin Matuska	count=$#
184716fd348SMartin Matuska
185716fd348SMartin Matuska	i=1
186716fd348SMartin Matuska	while [ $i -le $count ] ; do
187716fd348SMartin Matuska		d=$(eval echo '$'{$i})
188716fd348SMartin Matuska		id=$(cat "/sys/class/enclosure/${d}/id")
189716fd348SMartin Matuska		ENCL_ID="${ENCL_ID} $id"
190716fd348SMartin Matuska		i=$((i + 1))
191716fd348SMartin Matuska	done
192716fd348SMartin Matuska}
193716fd348SMartin Matuska
194716fd348SMartin Matuskaget_uniq_encl_id() {
195716fd348SMartin Matuska	for uuid in ${ENCL_ID}; do
196716fd348SMartin Matuska		found=0
197716fd348SMartin Matuska
198716fd348SMartin Matuska		for count in ${UNIQ_ENCL_ID}; do
199716fd348SMartin Matuska			if [ $count = $uuid ]; then
200716fd348SMartin Matuska				found=1
201716fd348SMartin Matuska				break
202716fd348SMartin Matuska			fi
203716fd348SMartin Matuska		done
204716fd348SMartin Matuska
205716fd348SMartin Matuska		if [ $found -eq 0 ]; then
206716fd348SMartin Matuska			UNIQ_ENCL_ID="${UNIQ_ENCL_ID} $uuid"
207716fd348SMartin Matuska		fi
208716fd348SMartin Matuska	done
209716fd348SMartin Matuska}
210716fd348SMartin Matuska
211716fd348SMartin Matuska# map_jbod explainer: The bsg driver knows the difference between a SAS
212716fd348SMartin Matuska# expander and fanout expander. Use hostX instance along with top-level
213716fd348SMartin Matuska# (whole enclosure) expander instances in /sys/class/enclosure and
214716fd348SMartin Matuska# matching a field in an array of expanders, using the index of the
215716fd348SMartin Matuska# matched array field as the enclosure instance, thereby making jbod IDs
216716fd348SMartin Matuska# dynamic. Avoids reliance on high overhead userspace commands like
217716fd348SMartin Matuska# multipath and lsscsi and instead uses existing sysfs data.  $HOSTCHAN
218716fd348SMartin Matuska# variable derived from devpath gymnastics in sas_handler() function.
219716fd348SMartin Matuskamap_jbod() {
220716fd348SMartin Matuska	DEVEXP=$(ls -l "/sys/block/$DEV/device/" | grep enclos | awk -F/ '{print $(NF-1) }')
221716fd348SMartin Matuska	DEV=$1
222716fd348SMartin Matuska
223716fd348SMartin Matuska	# Use "set --" to create index values (Arrays)
224716fd348SMartin Matuska	set -- $(ls -l /sys/class/enclosure | grep -v "^total" | awk '{print $9}')
225716fd348SMartin Matuska	# Get count of total elements
226716fd348SMartin Matuska	JBOD_COUNT=$#
227716fd348SMartin Matuska	JBOD_ITEM=$*
228716fd348SMartin Matuska
229716fd348SMartin Matuska	# Build JBODs (enclosure)  id from sys/class/enclosure/<dev>/id
230716fd348SMartin Matuska	get_encl_id "$JBOD_ITEM"
231716fd348SMartin Matuska	# Different expander instances for each paths.
232716fd348SMartin Matuska	# Filter out and keep only unique id.
233716fd348SMartin Matuska	get_uniq_encl_id
234716fd348SMartin Matuska
235716fd348SMartin Matuska	# Identify final 'mapped jbod'
236716fd348SMartin Matuska	j=0
237716fd348SMartin Matuska	for count in ${UNIQ_ENCL_ID}; do
238716fd348SMartin Matuska		i=1
239716fd348SMartin Matuska		j=$((j + 1))
240716fd348SMartin Matuska		while [ $i -le $JBOD_COUNT ] ; do
241716fd348SMartin Matuska			d=$(eval echo '$'{$i})
242716fd348SMartin Matuska			id=$(cat "/sys/class/enclosure/${d}/id")
243716fd348SMartin Matuska			if [ "$d" = "$DEVEXP" ] && [ $id = $count ] ; then
244716fd348SMartin Matuska				MAPPED_JBOD=$j
245716fd348SMartin Matuska				break
246716fd348SMartin Matuska			fi
247716fd348SMartin Matuska			i=$((i + 1))
248716fd348SMartin Matuska		done
249716fd348SMartin Matuska	done
250716fd348SMartin Matuska
251716fd348SMartin Matuska	printf "%d" "${MAPPED_JBOD}"
252716fd348SMartin Matuska}
253716fd348SMartin Matuska
254716fd348SMartin Matuskasas_handler() {
255716fd348SMartin Matuska	if [ -z "$PHYS_PER_PORT" ] ; then
256716fd348SMartin Matuska		PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
257716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
258716fd348SMartin Matuska	fi
259716fd348SMartin Matuska	PHYS_PER_PORT=${PHYS_PER_PORT:-4}
260716fd348SMartin Matuska
261716fd348SMartin Matuska	if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
262716fd348SMartin Matuska		echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
263716fd348SMartin Matuska		exit 1
264716fd348SMartin Matuska	fi
265716fd348SMartin Matuska
266716fd348SMartin Matuska	if [ -z "$MULTIPATH_MODE" ] ; then
267716fd348SMartin Matuska		MULTIPATH_MODE=$(awk '$1 == "multipath" \
268716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
269716fd348SMartin Matuska	fi
270716fd348SMartin Matuska
271716fd348SMartin Matuska	if [ -z "$MULTIJBOD_MODE" ] ; then
272716fd348SMartin Matuska		MULTIJBOD_MODE=$(awk '$1 == "multijbod" \
273716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
274716fd348SMartin Matuska	fi
275716fd348SMartin Matuska
276716fd348SMartin Matuska	# Use first running component device if we're handling a dm-mpath device
277716fd348SMartin Matuska	if [ "$MULTIPATH_MODE" = "yes" ] ; then
278716fd348SMartin Matuska		# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
279716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
280716fd348SMartin Matuska			DM_NAME=$(ls -l --full-time /dev/mapper |
281716fd348SMartin Matuska				grep "$DEV"$ | awk '{print $9}')
282716fd348SMartin Matuska		fi
283716fd348SMartin Matuska
284716fd348SMartin Matuska		# For raw disks udev exports DEVTYPE=partition when
285716fd348SMartin Matuska		# handling partitions, and the rules can be written to
286716fd348SMartin Matuska		# take advantage of this to append a -part suffix.  For
287716fd348SMartin Matuska		# dm devices we get DEVTYPE=disk even for partitions so
288716fd348SMartin Matuska		# we have to append the -part suffix directly in the
289716fd348SMartin Matuska		# helper.
290716fd348SMartin Matuska		if [ "$DEVTYPE" != "partition" ] ; then
291716fd348SMartin Matuska			# Match p[number], remove the 'p' and prepend "-part"
292716fd348SMartin Matuska			PART=$(echo "$DM_NAME" |
293716fd348SMartin Matuska				awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
294716fd348SMartin Matuska		fi
295716fd348SMartin Matuska
296716fd348SMartin Matuska		# Strip off partition information.
297716fd348SMartin Matuska		DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
298716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
299716fd348SMartin Matuska			return
300716fd348SMartin Matuska		fi
301716fd348SMartin Matuska
302716fd348SMartin Matuska		# Utilize DM device name to gather subordinate block devices
303716fd348SMartin Matuska		# using sysfs to avoid userspace utilities
304716fd348SMartin Matuska
305716fd348SMartin Matuska		# If our DEVNAME is something like /dev/dm-177, then we may be
306716fd348SMartin Matuska		# able to get our DMDEV from it.
307716fd348SMartin Matuska		DMDEV=$(echo $DEVNAME | sed 's;/dev/;;g')
308716fd348SMartin Matuska		if [ ! -e /sys/block/$DMDEV/slaves/* ] ; then
309716fd348SMartin Matuska			# It's not there, try looking in /dev/mapper
310716fd348SMartin Matuska			DMDEV=$(ls -l --full-time /dev/mapper | grep $DM_NAME |
311716fd348SMartin Matuska			awk '{gsub("../", " "); print $NF}')
312716fd348SMartin Matuska		fi
313716fd348SMartin Matuska
314716fd348SMartin Matuska		# Use sysfs pointers in /sys/block/dm-X/slaves because using
315716fd348SMartin Matuska		# userspace tools creates lots of overhead and should be avoided
316716fd348SMartin Matuska		# whenever possible. Use awk to isolate lowest instance of
317716fd348SMartin Matuska		# sd device member in dm device group regardless of string
318716fd348SMartin Matuska		# length.
319716fd348SMartin Matuska		DEV=$(ls "/sys/block/$DMDEV/slaves" | awk '
320716fd348SMartin Matuska			{ len=sprintf ("%20s",length($0)); gsub(/ /,0,str); a[NR]=len "_" $0; }
321716fd348SMartin Matuska			END {
322716fd348SMartin Matuska				asort(a)
323716fd348SMartin Matuska				print substr(a[1],22)
324716fd348SMartin Matuska			}')
325716fd348SMartin Matuska
326716fd348SMartin Matuska		if [ -z "$DEV" ] ; then
327716fd348SMartin Matuska			return
328716fd348SMartin Matuska		fi
329716fd348SMartin Matuska	fi
330716fd348SMartin Matuska
331716fd348SMartin Matuska	if echo "$DEV" | grep -q ^/devices/ ; then
332716fd348SMartin Matuska		sys_path=$DEV
333716fd348SMartin Matuska	else
334716fd348SMartin Matuska		sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
335716fd348SMartin Matuska	fi
336716fd348SMartin Matuska
337716fd348SMartin Matuska	# Use positional parameters as an ad-hoc array
338716fd348SMartin Matuska	set -- $(echo "$sys_path" | tr / ' ')
339716fd348SMartin Matuska	num_dirs=$#
340716fd348SMartin Matuska	scsi_host_dir="/sys"
341716fd348SMartin Matuska
342716fd348SMartin Matuska	# Get path up to /sys/.../hostX
343716fd348SMartin Matuska	i=1
344716fd348SMartin Matuska
345716fd348SMartin Matuska	while [ $i -le "$num_dirs" ] ; do
346716fd348SMartin Matuska		d=$(eval echo '$'{$i})
347716fd348SMartin Matuska		scsi_host_dir="$scsi_host_dir/$d"
348716fd348SMartin Matuska		echo "$d" | grep -q -E '^host[0-9]+$' && break
349716fd348SMartin Matuska		i=$((i + 1))
350716fd348SMartin Matuska	done
351716fd348SMartin Matuska
352716fd348SMartin Matuska	# Lets grab the SAS host channel number and save it for JBOD sorting later
353716fd348SMartin Matuska	HOSTCHAN=$(echo "$d" | awk -F/ '{ gsub("host","",$NF); print $NF}')
354716fd348SMartin Matuska
355716fd348SMartin Matuska	if [ $i = "$num_dirs" ] ; then
356716fd348SMartin Matuska		return
357716fd348SMartin Matuska	fi
358716fd348SMartin Matuska
359716fd348SMartin Matuska	PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
360716fd348SMartin Matuska
361716fd348SMartin Matuska	# In sas_switch mode, the directory four levels beneath
362716fd348SMartin Matuska	# /sys/.../hostX contains symlinks to phy devices that reveal
363716fd348SMartin Matuska	# the switch port number.  In sas_direct mode, the phy links one
364716fd348SMartin Matuska	# directory down reveal the HBA port.
365716fd348SMartin Matuska	port_dir=$scsi_host_dir
366716fd348SMartin Matuska
367716fd348SMartin Matuska	case $TOPOLOGY in
368716fd348SMartin Matuska		"sas_switch") j=$((i + 4)) ;;
369716fd348SMartin Matuska		"sas_direct") j=$((i + 1)) ;;
370716fd348SMartin Matuska	esac
371716fd348SMartin Matuska
372716fd348SMartin Matuska	i=$((i + 1))
373716fd348SMartin Matuska
374716fd348SMartin Matuska	while [ $i -le $j ] ; do
375716fd348SMartin Matuska		port_dir="$port_dir/$(eval echo '$'{$i})"
376716fd348SMartin Matuska		i=$((i + 1))
377716fd348SMartin Matuska	done
378716fd348SMartin Matuska
379716fd348SMartin Matuska	PHY=$(ls -vd "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}')
380716fd348SMartin Matuska	if [ -z "$PHY" ] ; then
381716fd348SMartin Matuska		PHY=0
382716fd348SMartin Matuska	fi
383716fd348SMartin Matuska	PORT=$((PHY / PHYS_PER_PORT))
384716fd348SMartin Matuska
385716fd348SMartin Matuska	# Look in /sys/.../sas_device/end_device-X for the bay_identifier
386716fd348SMartin Matuska	# attribute.
387716fd348SMartin Matuska	end_device_dir=$port_dir
388716fd348SMartin Matuska
389716fd348SMartin Matuska	while [ $i -lt "$num_dirs" ] ; do
390716fd348SMartin Matuska		d=$(eval echo '$'{$i})
391716fd348SMartin Matuska		end_device_dir="$end_device_dir/$d"
392716fd348SMartin Matuska		if echo "$d" | grep -q '^end_device' ; then
393716fd348SMartin Matuska			end_device_dir="$end_device_dir/sas_device/$d"
394716fd348SMartin Matuska			break
395716fd348SMartin Matuska		fi
396716fd348SMartin Matuska		i=$((i + 1))
397716fd348SMartin Matuska	done
398716fd348SMartin Matuska
399716fd348SMartin Matuska	# Add 'mix' slot type for environments where dm-multipath devices
400716fd348SMartin Matuska	# include end-devices connected via SAS expanders or direct connection
401716fd348SMartin Matuska	# to SAS HBA. A mixed connectivity environment such as pool devices
402716fd348SMartin Matuska	# contained in a SAS JBOD and spare drives or log devices directly
403716fd348SMartin Matuska	# connected in a server backplane without expanders in the I/O path.
404716fd348SMartin Matuska	SLOT=
405716fd348SMartin Matuska
406716fd348SMartin Matuska	case $BAY in
407716fd348SMartin Matuska	"bay")
408716fd348SMartin Matuska		SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
409716fd348SMartin Matuska		;;
410716fd348SMartin Matuska	"mix")
411716fd348SMartin Matuska		if [ $(cat "$end_device_dir/bay_identifier" 2>/dev/null) ] ; then
412716fd348SMartin Matuska			SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
413716fd348SMartin Matuska		else
414716fd348SMartin Matuska			SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
415716fd348SMartin Matuska		fi
416716fd348SMartin Matuska		;;
417716fd348SMartin Matuska	"phy")
418716fd348SMartin Matuska		SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
419716fd348SMartin Matuska		;;
420716fd348SMartin Matuska	"port")
421716fd348SMartin Matuska		d=$(eval echo '$'{$i})
422716fd348SMartin Matuska		SLOT=$(echo "$d" | sed -e 's/^.*://')
423716fd348SMartin Matuska		;;
424716fd348SMartin Matuska	"id")
425716fd348SMartin Matuska		i=$((i + 1))
426716fd348SMartin Matuska		d=$(eval echo '$'{$i})
427716fd348SMartin Matuska		SLOT=$(echo "$d" | sed -e 's/^.*://')
428716fd348SMartin Matuska		;;
429716fd348SMartin Matuska	"lun")
430716fd348SMartin Matuska		i=$((i + 2))
431716fd348SMartin Matuska		d=$(eval echo '$'{$i})
432716fd348SMartin Matuska		SLOT=$(echo "$d" | sed -e 's/^.*://')
433716fd348SMartin Matuska		;;
434*87bf66d4SMartin Matuska	"bay_lun")
435*87bf66d4SMartin Matuska		# Like 'bay' but with the LUN number appened. Added for SAS
436*87bf66d4SMartin Matuska		# multi-actuator HDDs, where one physical drive has multiple
437*87bf66d4SMartin Matuska		# LUNs, thus multiple logical drives share the same bay number
438*87bf66d4SMartin Matuska		i=$((i + 2))
439*87bf66d4SMartin Matuska		d=$(eval echo '$'{$i})
440*87bf66d4SMartin Matuska		LUN="-lun$(echo "$d" | sed -e 's/^.*://')"
441*87bf66d4SMartin Matuska		SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
442*87bf66d4SMartin Matuska		;;
443716fd348SMartin Matuska	"ses")
444716fd348SMartin Matuska		# look for this SAS path in all SCSI Enclosure Services
445716fd348SMartin Matuska		# (SES) enclosures
446716fd348SMartin Matuska		sas_address=$(cat "$end_device_dir/sas_address" 2>/dev/null)
447716fd348SMartin Matuska		enclosures=$(lsscsi -g | \
448716fd348SMartin Matuska			sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p')
449716fd348SMartin Matuska		for enclosure in $enclosures; do
450716fd348SMartin Matuska			set -- $(sg_ses -p aes "$enclosure" | \
451716fd348SMartin Matuska				awk "/device slot number:/{slot=\$12} \
452716fd348SMartin Matuska					/SAS address: $sas_address/\
453716fd348SMartin Matuska					{print slot}")
454716fd348SMartin Matuska			SLOT=$1
455716fd348SMartin Matuska			if [ -n "$SLOT" ] ; then
456716fd348SMartin Matuska				break
457716fd348SMartin Matuska			fi
458716fd348SMartin Matuska		done
459716fd348SMartin Matuska		;;
460716fd348SMartin Matuska	esac
461716fd348SMartin Matuska	if [ -z "$SLOT" ] ; then
462716fd348SMartin Matuska		return
463716fd348SMartin Matuska	fi
464716fd348SMartin Matuska
465716fd348SMartin Matuska	if [ "$MULTIJBOD_MODE" = "yes" ] ; then
466716fd348SMartin Matuska		CHAN=$(map_channel "$PCI_ID" "$PORT")
467716fd348SMartin Matuska		SLOT=$(map_slot "$SLOT" "$CHAN")
468716fd348SMartin Matuska		JBOD=$(map_jbod "$DEV")
469716fd348SMartin Matuska
470716fd348SMartin Matuska		if [ -z "$CHAN" ] ; then
471716fd348SMartin Matuska			return
472716fd348SMartin Matuska		fi
473*87bf66d4SMartin Matuska		echo "${CHAN}"-"${JBOD}"-"${SLOT}${LUN}${PART}"
474716fd348SMartin Matuska	else
475716fd348SMartin Matuska		CHAN=$(map_channel "$PCI_ID" "$PORT")
476716fd348SMartin Matuska		SLOT=$(map_slot "$SLOT" "$CHAN")
477716fd348SMartin Matuska
478716fd348SMartin Matuska		if [ -z "$CHAN" ] ; then
479716fd348SMartin Matuska			return
480716fd348SMartin Matuska		fi
481*87bf66d4SMartin Matuska		echo "${CHAN}${SLOT}${LUN}${PART}"
482716fd348SMartin Matuska	fi
483716fd348SMartin Matuska}
484716fd348SMartin Matuska
485716fd348SMartin Matuskascsi_handler() {
486716fd348SMartin Matuska	if [ -z "$FIRST_BAY_NUMBER" ] ; then
487716fd348SMartin Matuska		FIRST_BAY_NUMBER=$(awk '$1 == "first_bay_number" \
488716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
489716fd348SMartin Matuska	fi
490716fd348SMartin Matuska	FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
491716fd348SMartin Matuska
492716fd348SMartin Matuska	if [ -z "$PHYS_PER_PORT" ] ; then
493716fd348SMartin Matuska		PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
494716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
495716fd348SMartin Matuska	fi
496716fd348SMartin Matuska	PHYS_PER_PORT=${PHYS_PER_PORT:-4}
497716fd348SMartin Matuska
498716fd348SMartin Matuska	if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
499716fd348SMartin Matuska		echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
500716fd348SMartin Matuska		exit 1
501716fd348SMartin Matuska	fi
502716fd348SMartin Matuska
503716fd348SMartin Matuska	if [ -z "$MULTIPATH_MODE" ] ; then
504716fd348SMartin Matuska		MULTIPATH_MODE=$(awk '$1 == "multipath" \
505716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
506716fd348SMartin Matuska	fi
507716fd348SMartin Matuska
508716fd348SMartin Matuska	# Use first running component device if we're handling a dm-mpath device
509716fd348SMartin Matuska	if [ "$MULTIPATH_MODE" = "yes" ] ; then
510716fd348SMartin Matuska		# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
511716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
512716fd348SMartin Matuska			DM_NAME=$(ls -l --full-time /dev/mapper |
513716fd348SMartin Matuska				grep "$DEV"$ | awk '{print $9}')
514716fd348SMartin Matuska		fi
515716fd348SMartin Matuska
516716fd348SMartin Matuska		# For raw disks udev exports DEVTYPE=partition when
517716fd348SMartin Matuska		# handling partitions, and the rules can be written to
518716fd348SMartin Matuska		# take advantage of this to append a -part suffix.  For
519716fd348SMartin Matuska		# dm devices we get DEVTYPE=disk even for partitions so
520716fd348SMartin Matuska		# we have to append the -part suffix directly in the
521716fd348SMartin Matuska		# helper.
522716fd348SMartin Matuska		if [ "$DEVTYPE" != "partition" ] ; then
523716fd348SMartin Matuska			# Match p[number], remove the 'p' and prepend "-part"
524716fd348SMartin Matuska			PART=$(echo "$DM_NAME" |
525716fd348SMartin Matuska			    awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
526716fd348SMartin Matuska		fi
527716fd348SMartin Matuska
528716fd348SMartin Matuska		# Strip off partition information.
529716fd348SMartin Matuska		DM_NAME=$(echo "$DM_NAME" | sed 's/p[0-9][0-9]*$//')
530716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
531716fd348SMartin Matuska			return
532716fd348SMartin Matuska		fi
533716fd348SMartin Matuska
534716fd348SMartin Matuska		# Get the raw scsi device name from multipath -ll. Strip off
535716fd348SMartin Matuska		# leading pipe symbols to make field numbering consistent.
536716fd348SMartin Matuska		DEV=$(multipath -ll "$DM_NAME" |
537716fd348SMartin Matuska			awk '/running/{gsub("^[|]"," "); print $3 ; exit}')
538716fd348SMartin Matuska		if [ -z "$DEV" ] ; then
539716fd348SMartin Matuska			return
540716fd348SMartin Matuska		fi
541716fd348SMartin Matuska	fi
542716fd348SMartin Matuska
543716fd348SMartin Matuska	if echo "$DEV" | grep -q ^/devices/ ; then
544716fd348SMartin Matuska		sys_path=$DEV
545716fd348SMartin Matuska	else
546716fd348SMartin Matuska		sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
547716fd348SMartin Matuska	fi
548716fd348SMartin Matuska
549716fd348SMartin Matuska	# expect sys_path like this, for example:
550716fd348SMartin Matuska	# /devices/pci0000:00/0000:00:0b.0/0000:09:00.0/0000:0a:05.0/0000:0c:00.0/host3/target3:1:0/3:1:0:21/block/sdv
551716fd348SMartin Matuska
552716fd348SMartin Matuska	# Use positional parameters as an ad-hoc array
553716fd348SMartin Matuska	set -- $(echo "$sys_path" | tr / ' ')
554716fd348SMartin Matuska	num_dirs=$#
555716fd348SMartin Matuska	scsi_host_dir="/sys"
556716fd348SMartin Matuska
557716fd348SMartin Matuska	# Get path up to /sys/.../hostX
558716fd348SMartin Matuska	i=1
559716fd348SMartin Matuska
560716fd348SMartin Matuska	while [ $i -le "$num_dirs" ] ; do
561716fd348SMartin Matuska		d=$(eval echo '$'{$i})
562716fd348SMartin Matuska		scsi_host_dir="$scsi_host_dir/$d"
563716fd348SMartin Matuska
564716fd348SMartin Matuska		echo "$d" | grep -q -E '^host[0-9]+$' && break
565716fd348SMartin Matuska		i=$((i + 1))
566716fd348SMartin Matuska	done
567716fd348SMartin Matuska
568716fd348SMartin Matuska	if [ $i = "$num_dirs" ] ; then
569716fd348SMartin Matuska		return
570716fd348SMartin Matuska	fi
571716fd348SMartin Matuska
572716fd348SMartin Matuska	PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
573716fd348SMartin Matuska
574716fd348SMartin Matuska	# In scsi mode, the directory two levels beneath
575716fd348SMartin Matuska	# /sys/.../hostX reveals the port and slot.
576716fd348SMartin Matuska	port_dir=$scsi_host_dir
577716fd348SMartin Matuska	j=$((i + 2))
578716fd348SMartin Matuska
579716fd348SMartin Matuska	i=$((i + 1))
580716fd348SMartin Matuska	while [ $i -le $j ] ; do
581716fd348SMartin Matuska		port_dir="$port_dir/$(eval echo '$'{$i})"
582716fd348SMartin Matuska		i=$((i + 1))
583716fd348SMartin Matuska	done
584716fd348SMartin Matuska
585716fd348SMartin Matuska	set -- $(echo "$port_dir" | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
586716fd348SMartin Matuska	PORT=$1
587716fd348SMartin Matuska	SLOT=$(($2 + FIRST_BAY_NUMBER))
588716fd348SMartin Matuska
589716fd348SMartin Matuska	if [ -z "$SLOT" ] ; then
590716fd348SMartin Matuska		return
591716fd348SMartin Matuska	fi
592716fd348SMartin Matuska
593716fd348SMartin Matuska	CHAN=$(map_channel "$PCI_ID" "$PORT")
594716fd348SMartin Matuska	SLOT=$(map_slot "$SLOT" "$CHAN")
595716fd348SMartin Matuska
596716fd348SMartin Matuska	if [ -z "$CHAN" ] ; then
597716fd348SMartin Matuska		return
598716fd348SMartin Matuska	fi
599716fd348SMartin Matuska	echo "${CHAN}${SLOT}${PART}"
600716fd348SMartin Matuska}
601716fd348SMartin Matuska
602716fd348SMartin Matuska# Figure out the name for the enclosure symlink
603716fd348SMartin Matuskaenclosure_handler () {
604716fd348SMartin Matuska	# We get all the info we need from udev's DEVPATH variable:
605716fd348SMartin Matuska	#
606716fd348SMartin Matuska	# DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0
607716fd348SMartin Matuska
608716fd348SMartin Matuska	# Get the enclosure ID ("0:0:0:0")
609716fd348SMartin Matuska	ENC="${DEVPATH%/*}"
610716fd348SMartin Matuska	ENC="${ENC%/*}"
611716fd348SMartin Matuska	ENC="${ENC##*/}"
612716fd348SMartin Matuska	if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
613716fd348SMartin Matuska		# Not an enclosure, bail out
614716fd348SMartin Matuska		return
615716fd348SMartin Matuska	fi
616716fd348SMartin Matuska
617716fd348SMartin Matuska	# Get the long sysfs device path to our enclosure. Looks like:
618716fd348SMartin Matuska	# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0/ ... /enclosure/0:0:0:0
619716fd348SMartin Matuska
620716fd348SMartin Matuska	ENC_DEVICE=$(readlink "/sys/class/enclosure/$ENC")
621716fd348SMartin Matuska
622716fd348SMartin Matuska	# Grab the full path to the hosts port dir:
623716fd348SMartin Matuska	# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
624716fd348SMartin Matuska	PORT_DIR=$(echo "$ENC_DEVICE" | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
625716fd348SMartin Matuska
626716fd348SMartin Matuska	# Get the port number
627716fd348SMartin Matuska	PORT_ID=$(echo "$PORT_DIR" | grep -Eo "[0-9]+$")
628716fd348SMartin Matuska
629716fd348SMartin Matuska	# The PCI directory is two directories up from the port directory
630716fd348SMartin Matuska	# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
631716fd348SMartin Matuska	PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")"
632716fd348SMartin Matuska	PCI_ID_LONG="${PCI_ID_LONG##*/}"
633716fd348SMartin Matuska
634716fd348SMartin Matuska	# Strip down the PCI address from 0000:05:00.0 to 05:00.0
635716fd348SMartin Matuska	PCI_ID="${PCI_ID_LONG#[0-9]*:}"
636716fd348SMartin Matuska
637716fd348SMartin Matuska	# Name our device according to vdev_id.conf (like "L0" or "U1").
638716fd348SMartin Matuska	NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
639716fd348SMartin Matuska		\$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG)
640716fd348SMartin Matuska
641716fd348SMartin Matuska	echo "${NAME}"
642716fd348SMartin Matuska}
643716fd348SMartin Matuska
644716fd348SMartin Matuskaalias_handler () {
645716fd348SMartin Matuska	# Special handling is needed to correctly append a -part suffix
646716fd348SMartin Matuska	# to partitions of device mapper devices.  The DEVTYPE attribute
647716fd348SMartin Matuska	# is normally set to "disk" instead of "partition" in this case,
648716fd348SMartin Matuska	# so the udev rules won't handle that for us as they do for
649716fd348SMartin Matuska	# "plain" block devices.
650716fd348SMartin Matuska	#
651716fd348SMartin Matuska	# For example, we may have the following links for a device and its
652716fd348SMartin Matuska	# partitions,
653716fd348SMartin Matuska	#
654716fd348SMartin Matuska	#  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0   -> ../../dm-0
655716fd348SMartin Matuska	#  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p1 -> ../../dm-1
656716fd348SMartin Matuska	#  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p2 -> ../../dm-3
657716fd348SMartin Matuska	#
658716fd348SMartin Matuska	# and the following alias in vdev_id.conf.
659716fd348SMartin Matuska	#
660716fd348SMartin Matuska	#   alias A0 dm-name-isw_dibgbfcije_ARRAY0
661716fd348SMartin Matuska	#
662716fd348SMartin Matuska	# The desired outcome is for the following links to be created
663716fd348SMartin Matuska	# without having explicitly defined aliases for the partitions.
664716fd348SMartin Matuska	#
665716fd348SMartin Matuska	#  /dev/disk/by-vdev/A0       -> ../../dm-0
666716fd348SMartin Matuska	#  /dev/disk/by-vdev/A0-part1 -> ../../dm-1
667716fd348SMartin Matuska	#  /dev/disk/by-vdev/A0-part2 -> ../../dm-3
668716fd348SMartin Matuska	#
669716fd348SMartin Matuska	# Warning: The following grep pattern will misidentify whole-disk
670716fd348SMartin Matuska	#          devices whose names end with 'p' followed by a string of
671716fd348SMartin Matuska	#          digits as partitions, causing alias creation to fail. This
672716fd348SMartin Matuska	#          ambiguity seems unavoidable, so devices using this facility
673716fd348SMartin Matuska	#          must not use such names.
674716fd348SMartin Matuska	DM_PART=
675716fd348SMartin Matuska	if echo "$DM_NAME" | grep -q -E 'p[0-9][0-9]*$' ; then
676716fd348SMartin Matuska		if [ "$DEVTYPE" != "partition" ] ; then
677716fd348SMartin Matuska			# Match p[number], remove the 'p' and prepend "-part"
678716fd348SMartin Matuska			DM_PART=$(echo "$DM_NAME" |
679716fd348SMartin Matuska			    awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
680716fd348SMartin Matuska		fi
681716fd348SMartin Matuska	fi
682716fd348SMartin Matuska
683716fd348SMartin Matuska	# DEVLINKS attribute must have been populated by already-run udev rules.
684716fd348SMartin Matuska	for link in $DEVLINKS ; do
685716fd348SMartin Matuska		# Remove partition information to match key of top-level device.
686716fd348SMartin Matuska		if [ -n "$DM_PART" ] ; then
687716fd348SMartin Matuska			link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
688716fd348SMartin Matuska		fi
689716fd348SMartin Matuska		# Check both the fully qualified and the base name of link.
690716fd348SMartin Matuska		for l in $link ${link##*/} ; do
691716fd348SMartin Matuska			if [ ! -z "$l" ]; then
692716fd348SMartin Matuska				alias=$(awk -v var="$l" '($1 == "alias") && \
693716fd348SMartin Matuska					($3 == var) \
694716fd348SMartin Matuska					{ print $2; exit }' $CONFIG)
695716fd348SMartin Matuska				if [ -n "$alias" ] ; then
696716fd348SMartin Matuska					echo "${alias}${DM_PART}"
697716fd348SMartin Matuska					return
698716fd348SMartin Matuska				fi
699716fd348SMartin Matuska			fi
700716fd348SMartin Matuska		done
701716fd348SMartin Matuska	done
702716fd348SMartin Matuska}
703716fd348SMartin Matuska
704716fd348SMartin Matuska# main
705716fd348SMartin Matuskawhile getopts 'c:d:eg:jmp:h' OPTION; do
706716fd348SMartin Matuska	case ${OPTION} in
707716fd348SMartin Matuska	c)
708716fd348SMartin Matuska		CONFIG=${OPTARG}
709716fd348SMartin Matuska		;;
710716fd348SMartin Matuska	d)
711716fd348SMartin Matuska		DEV=${OPTARG}
712716fd348SMartin Matuska		;;
713716fd348SMartin Matuska	e)
714716fd348SMartin Matuska	# When udev sees a scsi_generic device, it calls this script with -e to
715716fd348SMartin Matuska	# create the enclosure device symlinks only.  We also need
716716fd348SMartin Matuska	# "enclosure_symlinks yes" set in vdev_id.config to actually create the
717716fd348SMartin Matuska	# symlink.
718716fd348SMartin Matuska	ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") \
719716fd348SMartin Matuska		print $2}' "$CONFIG")
720716fd348SMartin Matuska
721716fd348SMartin Matuska	if [ "$ENCLOSURE_MODE" != "yes" ] ; then
722716fd348SMartin Matuska		exit 0
723716fd348SMartin Matuska	fi
724716fd348SMartin Matuska		;;
725716fd348SMartin Matuska	g)
726716fd348SMartin Matuska		TOPOLOGY=$OPTARG
727716fd348SMartin Matuska		;;
728716fd348SMartin Matuska	p)
729716fd348SMartin Matuska		PHYS_PER_PORT=${OPTARG}
730716fd348SMartin Matuska		;;
731716fd348SMartin Matuska	j)
732716fd348SMartin Matuska		MULTIJBOD_MODE=yes
733716fd348SMartin Matuska		;;
734716fd348SMartin Matuska	m)
735716fd348SMartin Matuska		MULTIPATH_MODE=yes
736716fd348SMartin Matuska		;;
737716fd348SMartin Matuska	h)
738716fd348SMartin Matuska		usage
739716fd348SMartin Matuska		;;
740716fd348SMartin Matuska	esac
741716fd348SMartin Matuskadone
742716fd348SMartin Matuska
743716fd348SMartin Matuskaif [ ! -r "$CONFIG" ] ; then
744716fd348SMartin Matuska	echo "Error: Config file \"$CONFIG\" not found"
745716fd348SMartin Matuska	exit 1
746716fd348SMartin Matuskafi
747716fd348SMartin Matuska
748716fd348SMartin Matuskaif [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
749716fd348SMartin Matuska	echo "Error: missing required option -d"
750716fd348SMartin Matuska	exit 1
751716fd348SMartin Matuskafi
752716fd348SMartin Matuska
753716fd348SMartin Matuskaif [ -z "$TOPOLOGY" ] ; then
754716fd348SMartin Matuska	TOPOLOGY=$(awk '($1 == "topology") {print $2; exit}' "$CONFIG")
755716fd348SMartin Matuskafi
756716fd348SMartin Matuska
757716fd348SMartin Matuskaif [ -z "$BAY" ] ; then
758716fd348SMartin Matuska	BAY=$(awk '($1 == "slot") {print $2; exit}' "$CONFIG")
759716fd348SMartin Matuskafi
760716fd348SMartin Matuska
761*87bf66d4SMartin MatuskaZPAD=$(awk '($1 == "zpad_slot") {print $2; exit}' "$CONFIG")
762*87bf66d4SMartin Matuska
763716fd348SMartin MatuskaTOPOLOGY=${TOPOLOGY:-sas_direct}
764716fd348SMartin Matuska
765716fd348SMartin Matuska# Should we create /dev/by-enclosure symlinks?
766716fd348SMartin Matuskaif [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
767716fd348SMartin Matuska	ID_ENCLOSURE=$(enclosure_handler)
768716fd348SMartin Matuska	if [ -z "$ID_ENCLOSURE" ] ; then
769716fd348SMartin Matuska		exit 0
770716fd348SMartin Matuska	fi
771716fd348SMartin Matuska
772716fd348SMartin Matuska	# Just create the symlinks to the enclosure devices and then exit.
773716fd348SMartin Matuska	ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' "$CONFIG")
774716fd348SMartin Matuska	if [ -z "$ENCLOSURE_PREFIX" ] ; then
775716fd348SMartin Matuska		ENCLOSURE_PREFIX="enc"
776716fd348SMartin Matuska	fi
777716fd348SMartin Matuska	echo "ID_ENCLOSURE=$ID_ENCLOSURE"
778716fd348SMartin Matuska	echo "ID_ENCLOSURE_PATH=by-enclosure/$ENCLOSURE_PREFIX-$ID_ENCLOSURE"
779716fd348SMartin Matuska	exit 0
780716fd348SMartin Matuskafi
781716fd348SMartin Matuska
782716fd348SMartin Matuska# First check if an alias was defined for this device.
783716fd348SMartin MatuskaID_VDEV=$(alias_handler)
784716fd348SMartin Matuska
785716fd348SMartin Matuskaif [ -z "$ID_VDEV" ] ; then
786716fd348SMartin Matuska	BAY=${BAY:-bay}
787716fd348SMartin Matuska	case $TOPOLOGY in
788716fd348SMartin Matuska		sas_direct|sas_switch)
789716fd348SMartin Matuska			ID_VDEV=$(sas_handler)
790716fd348SMartin Matuska			;;
791716fd348SMartin Matuska		scsi)
792716fd348SMartin Matuska			ID_VDEV=$(scsi_handler)
793716fd348SMartin Matuska			;;
794716fd348SMartin Matuska		*)
795716fd348SMartin Matuska			echo "Error: unknown topology $TOPOLOGY"
796716fd348SMartin Matuska			exit 1
797716fd348SMartin Matuska			;;
798716fd348SMartin Matuska	esac
799716fd348SMartin Matuskafi
800716fd348SMartin Matuska
801716fd348SMartin Matuskaif [ -n "$ID_VDEV" ] ; then
802716fd348SMartin Matuska	echo "ID_VDEV=${ID_VDEV}"
803716fd348SMartin Matuska	echo "ID_VDEV_PATH=disk/by-vdev/${ID_VDEV}"
804716fd348SMartin Matuskafi
805