xref: /freebsd/sys/contrib/openzfs/udev/vdev_id (revision b1c1ee4429fcca8f69873a8be66184e68e1b19d7)
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=""
12787bf66d4SMartin 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
15887bf66d4SMartin 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
291*b1c1ee44SMartin Matuska                        # WWNs end with number -> p<partition>, alphabet -> <partition>
292*b1c1ee44SMartin Matuska                        # '3' + (WWN length 16) = 17
293*b1c1ee44SMartin Matuska                        PART=${DM_NAME:17}
294*b1c1ee44SMartin Matuska                        if [[ $PART = "p"*  ]]; then
295716fd348SMartin Matuska                                # Match p[number], remove the 'p' and prepend "-part"
296716fd348SMartin Matuska                                PART=$(echo "$DM_NAME" |
297716fd348SMartin Matuska                                    awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
298*b1c1ee44SMartin Matuska                        elif [[ $PART != "" ]]; then
299*b1c1ee44SMartin Matuska                                PART="-part"${PART}
300*b1c1ee44SMartin Matuska                        fi
301716fd348SMartin Matuska		fi
302716fd348SMartin Matuska
303716fd348SMartin Matuska		# Strip off partition information.
304*b1c1ee44SMartin Matuska                DM_NAME=${DM_NAME:0:17}
305716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
306716fd348SMartin Matuska			return
307716fd348SMartin Matuska		fi
308716fd348SMartin Matuska
309716fd348SMartin Matuska		# Utilize DM device name to gather subordinate block devices
310716fd348SMartin Matuska		# using sysfs to avoid userspace utilities
311716fd348SMartin Matuska
312716fd348SMartin Matuska		# If our DEVNAME is something like /dev/dm-177, then we may be
313716fd348SMartin Matuska		# able to get our DMDEV from it.
314716fd348SMartin Matuska		DMDEV=$(echo $DEVNAME | sed 's;/dev/;;g')
315*b1c1ee44SMartin Matuska                if [ -n "$DMDEV"  ]; then
316*b1c1ee44SMartin Matuska                        DEV=$(ls /sys/block/$DMDEV/slaves)
317*b1c1ee44SMartin Matuska                        for elm in "${DEV[@]}"; do
318*b1c1ee44SMartin Matuska                                if [[ $elm == "dm-"* ]]; then
319*b1c1ee44SMartin Matuska                                        DMDEV=$elm
320*b1c1ee44SMartin Matuska                                        break
321*b1c1ee44SMartin Matuska                                fi
322*b1c1ee44SMartin Matuska                        done
323*b1c1ee44SMartin Matuska                fi
324*b1c1ee44SMartin Matuska
325716fd348SMartin Matuska		if [ ! -e /sys/block/$DMDEV/slaves/* ] ; then
326716fd348SMartin Matuska			# It's not there, try looking in /dev/mapper
327716fd348SMartin Matuska			DMDEV=$(ls -l --full-time /dev/mapper | grep $DM_NAME |
328*b1c1ee44SMartin Matuska			awk '{gsub("../", " "); print $NF}' | head -n 1)
329716fd348SMartin Matuska		fi
330716fd348SMartin Matuska
331716fd348SMartin Matuska		# Use sysfs pointers in /sys/block/dm-X/slaves because using
332716fd348SMartin Matuska		# userspace tools creates lots of overhead and should be avoided
333716fd348SMartin Matuska		# whenever possible. Use awk to isolate lowest instance of
334716fd348SMartin Matuska		# sd device member in dm device group regardless of string
335716fd348SMartin Matuska		# length.
336716fd348SMartin Matuska		DEV=$(ls "/sys/block/$DMDEV/slaves" | awk '
337716fd348SMartin Matuska			{ len=sprintf ("%20s",length($0)); gsub(/ /,0,str); a[NR]=len "_" $0; }
338716fd348SMartin Matuska			END {
339716fd348SMartin Matuska				asort(a)
340716fd348SMartin Matuska				print substr(a[1],22)
341716fd348SMartin Matuska			}')
342716fd348SMartin Matuska
343716fd348SMartin Matuska		if [ -z "$DEV" ] ; then
344716fd348SMartin Matuska			return
345716fd348SMartin Matuska		fi
346716fd348SMartin Matuska	fi
347716fd348SMartin Matuska
348716fd348SMartin Matuska	if echo "$DEV" | grep -q ^/devices/ ; then
349716fd348SMartin Matuska		sys_path=$DEV
350716fd348SMartin Matuska	else
351716fd348SMartin Matuska		sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
352716fd348SMartin Matuska	fi
353716fd348SMartin Matuska
354716fd348SMartin Matuska	# Use positional parameters as an ad-hoc array
355716fd348SMartin Matuska	set -- $(echo "$sys_path" | tr / ' ')
356716fd348SMartin Matuska	num_dirs=$#
357716fd348SMartin Matuska	scsi_host_dir="/sys"
358716fd348SMartin Matuska
359716fd348SMartin Matuska	# Get path up to /sys/.../hostX
360716fd348SMartin Matuska	i=1
361716fd348SMartin Matuska
362716fd348SMartin Matuska	while [ $i -le "$num_dirs" ] ; do
363716fd348SMartin Matuska		d=$(eval echo '$'{$i})
364716fd348SMartin Matuska		scsi_host_dir="$scsi_host_dir/$d"
365716fd348SMartin Matuska		echo "$d" | grep -q -E '^host[0-9]+$' && break
366716fd348SMartin Matuska		i=$((i + 1))
367716fd348SMartin Matuska	done
368716fd348SMartin Matuska
369716fd348SMartin Matuska	# Lets grab the SAS host channel number and save it for JBOD sorting later
370716fd348SMartin Matuska	HOSTCHAN=$(echo "$d" | awk -F/ '{ gsub("host","",$NF); print $NF}')
371716fd348SMartin Matuska
372716fd348SMartin Matuska	if [ $i = "$num_dirs" ] ; then
373716fd348SMartin Matuska		return
374716fd348SMartin Matuska	fi
375716fd348SMartin Matuska
376716fd348SMartin Matuska	PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
377716fd348SMartin Matuska
378716fd348SMartin Matuska	# In sas_switch mode, the directory four levels beneath
379716fd348SMartin Matuska	# /sys/.../hostX contains symlinks to phy devices that reveal
380716fd348SMartin Matuska	# the switch port number.  In sas_direct mode, the phy links one
381716fd348SMartin Matuska	# directory down reveal the HBA port.
382716fd348SMartin Matuska	port_dir=$scsi_host_dir
383716fd348SMartin Matuska
384716fd348SMartin Matuska	case $TOPOLOGY in
385716fd348SMartin Matuska		"sas_switch") j=$((i + 4)) ;;
386716fd348SMartin Matuska		"sas_direct") j=$((i + 1)) ;;
387716fd348SMartin Matuska	esac
388716fd348SMartin Matuska
389716fd348SMartin Matuska	i=$((i + 1))
390716fd348SMartin Matuska
391716fd348SMartin Matuska	while [ $i -le $j ] ; do
392716fd348SMartin Matuska		port_dir="$port_dir/$(eval echo '$'{$i})"
393716fd348SMartin Matuska		i=$((i + 1))
394716fd348SMartin Matuska	done
395716fd348SMartin Matuska
396716fd348SMartin Matuska	PHY=$(ls -vd "$port_dir"/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}')
397716fd348SMartin Matuska	if [ -z "$PHY" ] ; then
398716fd348SMartin Matuska		PHY=0
399716fd348SMartin Matuska	fi
400716fd348SMartin Matuska	PORT=$((PHY / PHYS_PER_PORT))
401716fd348SMartin Matuska
402716fd348SMartin Matuska	# Look in /sys/.../sas_device/end_device-X for the bay_identifier
403716fd348SMartin Matuska	# attribute.
404716fd348SMartin Matuska	end_device_dir=$port_dir
405716fd348SMartin Matuska
406716fd348SMartin Matuska	while [ $i -lt "$num_dirs" ] ; do
407716fd348SMartin Matuska		d=$(eval echo '$'{$i})
408716fd348SMartin Matuska		end_device_dir="$end_device_dir/$d"
409716fd348SMartin Matuska		if echo "$d" | grep -q '^end_device' ; then
410716fd348SMartin Matuska			end_device_dir="$end_device_dir/sas_device/$d"
411716fd348SMartin Matuska			break
412716fd348SMartin Matuska		fi
413716fd348SMartin Matuska		i=$((i + 1))
414716fd348SMartin Matuska	done
415716fd348SMartin Matuska
416716fd348SMartin Matuska	# Add 'mix' slot type for environments where dm-multipath devices
417716fd348SMartin Matuska	# include end-devices connected via SAS expanders or direct connection
418716fd348SMartin Matuska	# to SAS HBA. A mixed connectivity environment such as pool devices
419716fd348SMartin Matuska	# contained in a SAS JBOD and spare drives or log devices directly
420716fd348SMartin Matuska	# connected in a server backplane without expanders in the I/O path.
421716fd348SMartin Matuska	SLOT=
422716fd348SMartin Matuska
423716fd348SMartin Matuska	case $BAY in
424716fd348SMartin Matuska	"bay")
425716fd348SMartin Matuska		SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
426716fd348SMartin Matuska		;;
427716fd348SMartin Matuska	"mix")
428716fd348SMartin Matuska		if [ $(cat "$end_device_dir/bay_identifier" 2>/dev/null) ] ; then
429716fd348SMartin Matuska			SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
430716fd348SMartin Matuska		else
431716fd348SMartin Matuska			SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
432716fd348SMartin Matuska		fi
433716fd348SMartin Matuska		;;
434716fd348SMartin Matuska	"phy")
435716fd348SMartin Matuska		SLOT=$(cat "$end_device_dir/phy_identifier" 2>/dev/null)
436716fd348SMartin Matuska		;;
437716fd348SMartin Matuska	"port")
438716fd348SMartin Matuska		d=$(eval echo '$'{$i})
439716fd348SMartin Matuska		SLOT=$(echo "$d" | sed -e 's/^.*://')
440716fd348SMartin Matuska		;;
441716fd348SMartin Matuska	"id")
442716fd348SMartin Matuska		i=$((i + 1))
443716fd348SMartin Matuska		d=$(eval echo '$'{$i})
444716fd348SMartin Matuska		SLOT=$(echo "$d" | sed -e 's/^.*://')
445716fd348SMartin Matuska		;;
446716fd348SMartin Matuska	"lun")
447716fd348SMartin Matuska		i=$((i + 2))
448716fd348SMartin Matuska		d=$(eval echo '$'{$i})
449716fd348SMartin Matuska		SLOT=$(echo "$d" | sed -e 's/^.*://')
450716fd348SMartin Matuska		;;
45187bf66d4SMartin Matuska	"bay_lun")
45287bf66d4SMartin Matuska		# Like 'bay' but with the LUN number appened. Added for SAS
45387bf66d4SMartin Matuska		# multi-actuator HDDs, where one physical drive has multiple
45487bf66d4SMartin Matuska		# LUNs, thus multiple logical drives share the same bay number
45587bf66d4SMartin Matuska		i=$((i + 2))
45687bf66d4SMartin Matuska		d=$(eval echo '$'{$i})
45787bf66d4SMartin Matuska		LUN="-lun$(echo "$d" | sed -e 's/^.*://')"
45887bf66d4SMartin Matuska		SLOT=$(cat "$end_device_dir/bay_identifier" 2>/dev/null)
45987bf66d4SMartin Matuska		;;
460716fd348SMartin Matuska	"ses")
461716fd348SMartin Matuska		# look for this SAS path in all SCSI Enclosure Services
462716fd348SMartin Matuska		# (SES) enclosures
463716fd348SMartin Matuska		sas_address=$(cat "$end_device_dir/sas_address" 2>/dev/null)
464716fd348SMartin Matuska		enclosures=$(lsscsi -g | \
465716fd348SMartin Matuska			sed -n -e '/enclosu/s/^.* \([^ ][^ ]*\) *$/\1/p')
466716fd348SMartin Matuska		for enclosure in $enclosures; do
467716fd348SMartin Matuska			set -- $(sg_ses -p aes "$enclosure" | \
468716fd348SMartin Matuska				awk "/device slot number:/{slot=\$12} \
469716fd348SMartin Matuska					/SAS address: $sas_address/\
470716fd348SMartin Matuska					{print slot}")
471716fd348SMartin Matuska			SLOT=$1
472716fd348SMartin Matuska			if [ -n "$SLOT" ] ; then
473716fd348SMartin Matuska				break
474716fd348SMartin Matuska			fi
475716fd348SMartin Matuska		done
476716fd348SMartin Matuska		;;
477716fd348SMartin Matuska	esac
478716fd348SMartin Matuska	if [ -z "$SLOT" ] ; then
479716fd348SMartin Matuska		return
480716fd348SMartin Matuska	fi
481716fd348SMartin Matuska
482716fd348SMartin Matuska	if [ "$MULTIJBOD_MODE" = "yes" ] ; then
483716fd348SMartin Matuska		CHAN=$(map_channel "$PCI_ID" "$PORT")
484716fd348SMartin Matuska		SLOT=$(map_slot "$SLOT" "$CHAN")
485716fd348SMartin Matuska		JBOD=$(map_jbod "$DEV")
486716fd348SMartin Matuska
487716fd348SMartin Matuska		if [ -z "$CHAN" ] ; then
488716fd348SMartin Matuska			return
489716fd348SMartin Matuska		fi
49087bf66d4SMartin Matuska		echo "${CHAN}"-"${JBOD}"-"${SLOT}${LUN}${PART}"
491716fd348SMartin Matuska	else
492716fd348SMartin Matuska		CHAN=$(map_channel "$PCI_ID" "$PORT")
493716fd348SMartin Matuska		SLOT=$(map_slot "$SLOT" "$CHAN")
494716fd348SMartin Matuska
495716fd348SMartin Matuska		if [ -z "$CHAN" ] ; then
496716fd348SMartin Matuska			return
497716fd348SMartin Matuska		fi
49887bf66d4SMartin Matuska		echo "${CHAN}${SLOT}${LUN}${PART}"
499716fd348SMartin Matuska	fi
500716fd348SMartin Matuska}
501716fd348SMartin Matuska
502716fd348SMartin Matuskascsi_handler() {
503716fd348SMartin Matuska	if [ -z "$FIRST_BAY_NUMBER" ] ; then
504716fd348SMartin Matuska		FIRST_BAY_NUMBER=$(awk '$1 == "first_bay_number" \
505716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
506716fd348SMartin Matuska	fi
507716fd348SMartin Matuska	FIRST_BAY_NUMBER=${FIRST_BAY_NUMBER:-0}
508716fd348SMartin Matuska
509716fd348SMartin Matuska	if [ -z "$PHYS_PER_PORT" ] ; then
510716fd348SMartin Matuska		PHYS_PER_PORT=$(awk '$1 == "phys_per_port" \
511716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
512716fd348SMartin Matuska	fi
513716fd348SMartin Matuska	PHYS_PER_PORT=${PHYS_PER_PORT:-4}
514716fd348SMartin Matuska
515716fd348SMartin Matuska	if ! echo "$PHYS_PER_PORT" | grep -q -E '^[0-9]+$' ; then
516716fd348SMartin Matuska		echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
517716fd348SMartin Matuska		exit 1
518716fd348SMartin Matuska	fi
519716fd348SMartin Matuska
520716fd348SMartin Matuska	if [ -z "$MULTIPATH_MODE" ] ; then
521716fd348SMartin Matuska		MULTIPATH_MODE=$(awk '$1 == "multipath" \
522716fd348SMartin Matuska			{print $2; exit}' $CONFIG)
523716fd348SMartin Matuska	fi
524716fd348SMartin Matuska
525716fd348SMartin Matuska	# Use first running component device if we're handling a dm-mpath device
526716fd348SMartin Matuska	if [ "$MULTIPATH_MODE" = "yes" ] ; then
527716fd348SMartin Matuska		# If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
528716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
529716fd348SMartin Matuska			DM_NAME=$(ls -l --full-time /dev/mapper |
530716fd348SMartin Matuska				grep "$DEV"$ | awk '{print $9}')
531716fd348SMartin Matuska		fi
532716fd348SMartin Matuska
533716fd348SMartin Matuska		# For raw disks udev exports DEVTYPE=partition when
534716fd348SMartin Matuska		# handling partitions, and the rules can be written to
535716fd348SMartin Matuska		# take advantage of this to append a -part suffix.  For
536716fd348SMartin Matuska		# dm devices we get DEVTYPE=disk even for partitions so
537716fd348SMartin Matuska		# we have to append the -part suffix directly in the
538716fd348SMartin Matuska		# helper.
539716fd348SMartin Matuska		if [ "$DEVTYPE" != "partition" ] ; then
540*b1c1ee44SMartin Matuska                        # WWNs end with number -> p<partition>, alphabet -> <partition>
541*b1c1ee44SMartin Matuska                        # '3' + (WWN length 16) = 17
542*b1c1ee44SMartin Matuska                        PART=${DM_NAME:17}
543*b1c1ee44SMartin Matuska                        if [[ $PART = "p"*  ]]; then
544716fd348SMartin Matuska                                # Match p[number], remove the 'p' and prepend "-part"
545716fd348SMartin Matuska                                PART=$(echo "$DM_NAME" |
546716fd348SMartin Matuska                                    awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
547*b1c1ee44SMartin Matuska                        elif [[ $PART != "" ]]; then
548*b1c1ee44SMartin Matuska                                PART="-part"${PART}
549*b1c1ee44SMartin Matuska                        fi
550716fd348SMartin Matuska		fi
551716fd348SMartin Matuska
552716fd348SMartin Matuska		# Strip off partition information.
553*b1c1ee44SMartin Matuska                DM_NAME=${DM_NAME:0:17}
554716fd348SMartin Matuska		if [ -z "$DM_NAME" ] ; then
555716fd348SMartin Matuska			return
556716fd348SMartin Matuska		fi
557716fd348SMartin Matuska
558716fd348SMartin Matuska		# Get the raw scsi device name from multipath -ll. Strip off
559716fd348SMartin Matuska		# leading pipe symbols to make field numbering consistent.
560716fd348SMartin Matuska		DEV=$(multipath -ll "$DM_NAME" |
561716fd348SMartin Matuska			awk '/running/{gsub("^[|]"," "); print $3 ; exit}')
562716fd348SMartin Matuska		if [ -z "$DEV" ] ; then
563716fd348SMartin Matuska			return
564716fd348SMartin Matuska		fi
565716fd348SMartin Matuska	fi
566716fd348SMartin Matuska
567716fd348SMartin Matuska	if echo "$DEV" | grep -q ^/devices/ ; then
568716fd348SMartin Matuska		sys_path=$DEV
569716fd348SMartin Matuska	else
570716fd348SMartin Matuska		sys_path=$(udevadm info -q path -p "/sys/block/$DEV" 2>/dev/null)
571716fd348SMartin Matuska	fi
572716fd348SMartin Matuska
573716fd348SMartin Matuska	# expect sys_path like this, for example:
574716fd348SMartin 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
575716fd348SMartin Matuska
576716fd348SMartin Matuska	# Use positional parameters as an ad-hoc array
577716fd348SMartin Matuska	set -- $(echo "$sys_path" | tr / ' ')
578716fd348SMartin Matuska	num_dirs=$#
579716fd348SMartin Matuska	scsi_host_dir="/sys"
580716fd348SMartin Matuska
581716fd348SMartin Matuska	# Get path up to /sys/.../hostX
582716fd348SMartin Matuska	i=1
583716fd348SMartin Matuska
584716fd348SMartin Matuska	while [ $i -le "$num_dirs" ] ; do
585716fd348SMartin Matuska		d=$(eval echo '$'{$i})
586716fd348SMartin Matuska		scsi_host_dir="$scsi_host_dir/$d"
587716fd348SMartin Matuska
588716fd348SMartin Matuska		echo "$d" | grep -q -E '^host[0-9]+$' && break
589716fd348SMartin Matuska		i=$((i + 1))
590716fd348SMartin Matuska	done
591716fd348SMartin Matuska
592716fd348SMartin Matuska	if [ $i = "$num_dirs" ] ; then
593716fd348SMartin Matuska		return
594716fd348SMartin Matuska	fi
595716fd348SMartin Matuska
596716fd348SMartin Matuska	PCI_ID=$(eval echo '$'{$((i -1))} | awk -F: '{print $2":"$3}')
597716fd348SMartin Matuska
598716fd348SMartin Matuska	# In scsi mode, the directory two levels beneath
599716fd348SMartin Matuska	# /sys/.../hostX reveals the port and slot.
600716fd348SMartin Matuska	port_dir=$scsi_host_dir
601716fd348SMartin Matuska	j=$((i + 2))
602716fd348SMartin Matuska
603716fd348SMartin Matuska	i=$((i + 1))
604716fd348SMartin Matuska	while [ $i -le $j ] ; do
605716fd348SMartin Matuska		port_dir="$port_dir/$(eval echo '$'{$i})"
606716fd348SMartin Matuska		i=$((i + 1))
607716fd348SMartin Matuska	done
608716fd348SMartin Matuska
609716fd348SMartin Matuska	set -- $(echo "$port_dir" | sed -e 's/^.*:\([^:]*\):\([^:]*\)$/\1 \2/')
610716fd348SMartin Matuska	PORT=$1
611716fd348SMartin Matuska	SLOT=$(($2 + FIRST_BAY_NUMBER))
612716fd348SMartin Matuska
613716fd348SMartin Matuska	if [ -z "$SLOT" ] ; then
614716fd348SMartin Matuska		return
615716fd348SMartin Matuska	fi
616716fd348SMartin Matuska
617716fd348SMartin Matuska	CHAN=$(map_channel "$PCI_ID" "$PORT")
618716fd348SMartin Matuska	SLOT=$(map_slot "$SLOT" "$CHAN")
619716fd348SMartin Matuska
620716fd348SMartin Matuska	if [ -z "$CHAN" ] ; then
621716fd348SMartin Matuska		return
622716fd348SMartin Matuska	fi
623716fd348SMartin Matuska	echo "${CHAN}${SLOT}${PART}"
624716fd348SMartin Matuska}
625716fd348SMartin Matuska
626716fd348SMartin Matuska# Figure out the name for the enclosure symlink
627716fd348SMartin Matuskaenclosure_handler () {
628716fd348SMartin Matuska	# We get all the info we need from udev's DEVPATH variable:
629716fd348SMartin Matuska	#
630716fd348SMartin Matuska	# DEVPATH=/sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/subsystem/devices/0:0:0:0/scsi_generic/sg0
631716fd348SMartin Matuska
632716fd348SMartin Matuska	# Get the enclosure ID ("0:0:0:0")
633716fd348SMartin Matuska	ENC="${DEVPATH%/*}"
634716fd348SMartin Matuska	ENC="${ENC%/*}"
635716fd348SMartin Matuska	ENC="${ENC##*/}"
636716fd348SMartin Matuska	if [ ! -d "/sys/class/enclosure/$ENC" ] ; then
637716fd348SMartin Matuska		# Not an enclosure, bail out
638716fd348SMartin Matuska		return
639716fd348SMartin Matuska	fi
640716fd348SMartin Matuska
641716fd348SMartin Matuska	# Get the long sysfs device path to our enclosure. Looks like:
642716fd348SMartin Matuska	# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0/ ... /enclosure/0:0:0:0
643716fd348SMartin Matuska
644716fd348SMartin Matuska	ENC_DEVICE=$(readlink "/sys/class/enclosure/$ENC")
645716fd348SMartin Matuska
646716fd348SMartin Matuska	# Grab the full path to the hosts port dir:
647716fd348SMartin Matuska	# /devices/pci0000:00/0000:00:03.0/0000:05:00.0/host0/port-0:0
648716fd348SMartin Matuska	PORT_DIR=$(echo "$ENC_DEVICE" | grep -Eo '.+host[0-9]+/port-[0-9]+:[0-9]+')
649716fd348SMartin Matuska
650716fd348SMartin Matuska	# Get the port number
651716fd348SMartin Matuska	PORT_ID=$(echo "$PORT_DIR" | grep -Eo "[0-9]+$")
652716fd348SMartin Matuska
653716fd348SMartin Matuska	# The PCI directory is two directories up from the port directory
654716fd348SMartin Matuska	# /sys/devices/pci0000:00/0000:00:03.0/0000:05:00.0
655716fd348SMartin Matuska	PCI_ID_LONG="$(readlink -m "/sys/$PORT_DIR/../..")"
656716fd348SMartin Matuska	PCI_ID_LONG="${PCI_ID_LONG##*/}"
657716fd348SMartin Matuska
658716fd348SMartin Matuska	# Strip down the PCI address from 0000:05:00.0 to 05:00.0
659716fd348SMartin Matuska	PCI_ID="${PCI_ID_LONG#[0-9]*:}"
660716fd348SMartin Matuska
661716fd348SMartin Matuska	# Name our device according to vdev_id.conf (like "L0" or "U1").
662716fd348SMartin Matuska	NAME=$(awk "/channel/{if (\$1 == \"channel\" && \$2 == \"$PCI_ID\" && \
663716fd348SMartin Matuska		\$3 == \"$PORT_ID\") {print \$4\$3}}" $CONFIG)
664716fd348SMartin Matuska
665716fd348SMartin Matuska	echo "${NAME}"
666716fd348SMartin Matuska}
667716fd348SMartin Matuska
668716fd348SMartin Matuskaalias_handler () {
669716fd348SMartin Matuska	# Special handling is needed to correctly append a -part suffix
670716fd348SMartin Matuska	# to partitions of device mapper devices.  The DEVTYPE attribute
671716fd348SMartin Matuska	# is normally set to "disk" instead of "partition" in this case,
672716fd348SMartin Matuska	# so the udev rules won't handle that for us as they do for
673716fd348SMartin Matuska	# "plain" block devices.
674716fd348SMartin Matuska	#
675716fd348SMartin Matuska	# For example, we may have the following links for a device and its
676716fd348SMartin Matuska	# partitions,
677716fd348SMartin Matuska	#
678716fd348SMartin Matuska	#  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0   -> ../../dm-0
679716fd348SMartin Matuska	#  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p1 -> ../../dm-1
680716fd348SMartin Matuska	#  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p2 -> ../../dm-3
681716fd348SMartin Matuska	#
682716fd348SMartin Matuska	# and the following alias in vdev_id.conf.
683716fd348SMartin Matuska	#
684716fd348SMartin Matuska	#   alias A0 dm-name-isw_dibgbfcije_ARRAY0
685716fd348SMartin Matuska	#
686716fd348SMartin Matuska	# The desired outcome is for the following links to be created
687716fd348SMartin Matuska	# without having explicitly defined aliases for the partitions.
688716fd348SMartin Matuska	#
689716fd348SMartin Matuska	#  /dev/disk/by-vdev/A0       -> ../../dm-0
690716fd348SMartin Matuska	#  /dev/disk/by-vdev/A0-part1 -> ../../dm-1
691716fd348SMartin Matuska	#  /dev/disk/by-vdev/A0-part2 -> ../../dm-3
692716fd348SMartin Matuska	#
693716fd348SMartin Matuska	# Warning: The following grep pattern will misidentify whole-disk
694716fd348SMartin Matuska	#          devices whose names end with 'p' followed by a string of
695716fd348SMartin Matuska	#          digits as partitions, causing alias creation to fail. This
696716fd348SMartin Matuska	#          ambiguity seems unavoidable, so devices using this facility
697716fd348SMartin Matuska	#          must not use such names.
698716fd348SMartin Matuska	DM_PART=
699716fd348SMartin Matuska	if echo "$DM_NAME" | grep -q -E 'p[0-9][0-9]*$' ; then
700716fd348SMartin Matuska		if [ "$DEVTYPE" != "partition" ] ; then
701716fd348SMartin Matuska			# Match p[number], remove the 'p' and prepend "-part"
702716fd348SMartin Matuska			DM_PART=$(echo "$DM_NAME" |
703716fd348SMartin Matuska			    awk 'match($0,/p[0-9]+$/) {print "-part"substr($0,RSTART+1,RLENGTH-1)}')
704716fd348SMartin Matuska		fi
705716fd348SMartin Matuska	fi
706716fd348SMartin Matuska
707716fd348SMartin Matuska	# DEVLINKS attribute must have been populated by already-run udev rules.
708716fd348SMartin Matuska	for link in $DEVLINKS ; do
709716fd348SMartin Matuska		# Remove partition information to match key of top-level device.
710716fd348SMartin Matuska		if [ -n "$DM_PART" ] ; then
711716fd348SMartin Matuska			link=$(echo "$link" | sed 's/p[0-9][0-9]*$//')
712716fd348SMartin Matuska		fi
713716fd348SMartin Matuska		# Check both the fully qualified and the base name of link.
714716fd348SMartin Matuska		for l in $link ${link##*/} ; do
715716fd348SMartin Matuska			if [ ! -z "$l" ]; then
716716fd348SMartin Matuska				alias=$(awk -v var="$l" '($1 == "alias") && \
717716fd348SMartin Matuska					($3 == var) \
718716fd348SMartin Matuska					{ print $2; exit }' $CONFIG)
719716fd348SMartin Matuska				if [ -n "$alias" ] ; then
720716fd348SMartin Matuska					echo "${alias}${DM_PART}"
721716fd348SMartin Matuska					return
722716fd348SMartin Matuska				fi
723716fd348SMartin Matuska			fi
724716fd348SMartin Matuska		done
725716fd348SMartin Matuska	done
726716fd348SMartin Matuska}
727716fd348SMartin Matuska
728716fd348SMartin Matuska# main
729716fd348SMartin Matuskawhile getopts 'c:d:eg:jmp:h' OPTION; do
730716fd348SMartin Matuska	case ${OPTION} in
731716fd348SMartin Matuska	c)
732716fd348SMartin Matuska		CONFIG=${OPTARG}
733716fd348SMartin Matuska		;;
734716fd348SMartin Matuska	d)
735716fd348SMartin Matuska		DEV=${OPTARG}
736716fd348SMartin Matuska		;;
737716fd348SMartin Matuska	e)
738716fd348SMartin Matuska	# When udev sees a scsi_generic device, it calls this script with -e to
739716fd348SMartin Matuska	# create the enclosure device symlinks only.  We also need
740716fd348SMartin Matuska	# "enclosure_symlinks yes" set in vdev_id.config to actually create the
741716fd348SMartin Matuska	# symlink.
742716fd348SMartin Matuska	ENCLOSURE_MODE=$(awk '{if ($1 == "enclosure_symlinks") \
743716fd348SMartin Matuska		print $2}' "$CONFIG")
744716fd348SMartin Matuska
745716fd348SMartin Matuska	if [ "$ENCLOSURE_MODE" != "yes" ] ; then
746716fd348SMartin Matuska		exit 0
747716fd348SMartin Matuska	fi
748716fd348SMartin Matuska		;;
749716fd348SMartin Matuska	g)
750716fd348SMartin Matuska		TOPOLOGY=$OPTARG
751716fd348SMartin Matuska		;;
752716fd348SMartin Matuska	p)
753716fd348SMartin Matuska		PHYS_PER_PORT=${OPTARG}
754716fd348SMartin Matuska		;;
755716fd348SMartin Matuska	j)
756716fd348SMartin Matuska		MULTIJBOD_MODE=yes
757716fd348SMartin Matuska		;;
758716fd348SMartin Matuska	m)
759716fd348SMartin Matuska		MULTIPATH_MODE=yes
760716fd348SMartin Matuska		;;
761716fd348SMartin Matuska	h)
762716fd348SMartin Matuska		usage
763716fd348SMartin Matuska		;;
764716fd348SMartin Matuska	esac
765716fd348SMartin Matuskadone
766716fd348SMartin Matuska
767716fd348SMartin Matuskaif [ ! -r "$CONFIG" ] ; then
768716fd348SMartin Matuska	echo "Error: Config file \"$CONFIG\" not found"
769716fd348SMartin Matuska	exit 1
770716fd348SMartin Matuskafi
771716fd348SMartin Matuska
772716fd348SMartin Matuskaif [ -z "$DEV" ] && [ -z "$ENCLOSURE_MODE" ] ; then
773716fd348SMartin Matuska	echo "Error: missing required option -d"
774716fd348SMartin Matuska	exit 1
775716fd348SMartin Matuskafi
776716fd348SMartin Matuska
777716fd348SMartin Matuskaif [ -z "$TOPOLOGY" ] ; then
778716fd348SMartin Matuska	TOPOLOGY=$(awk '($1 == "topology") {print $2; exit}' "$CONFIG")
779716fd348SMartin Matuskafi
780716fd348SMartin Matuska
781716fd348SMartin Matuskaif [ -z "$BAY" ] ; then
782716fd348SMartin Matuska	BAY=$(awk '($1 == "slot") {print $2; exit}' "$CONFIG")
783716fd348SMartin Matuskafi
784716fd348SMartin Matuska
78587bf66d4SMartin MatuskaZPAD=$(awk '($1 == "zpad_slot") {print $2; exit}' "$CONFIG")
78687bf66d4SMartin Matuska
787716fd348SMartin MatuskaTOPOLOGY=${TOPOLOGY:-sas_direct}
788716fd348SMartin Matuska
789716fd348SMartin Matuska# Should we create /dev/by-enclosure symlinks?
790716fd348SMartin Matuskaif [ "$ENCLOSURE_MODE" = "yes" ] && [ "$TOPOLOGY" = "sas_direct" ] ; then
791716fd348SMartin Matuska	ID_ENCLOSURE=$(enclosure_handler)
792716fd348SMartin Matuska	if [ -z "$ID_ENCLOSURE" ] ; then
793716fd348SMartin Matuska		exit 0
794716fd348SMartin Matuska	fi
795716fd348SMartin Matuska
796716fd348SMartin Matuska	# Just create the symlinks to the enclosure devices and then exit.
797716fd348SMartin Matuska	ENCLOSURE_PREFIX=$(awk '/enclosure_symlinks_prefix/{print $2}' "$CONFIG")
798716fd348SMartin Matuska	if [ -z "$ENCLOSURE_PREFIX" ] ; then
799716fd348SMartin Matuska		ENCLOSURE_PREFIX="enc"
800716fd348SMartin Matuska	fi
801716fd348SMartin Matuska	echo "ID_ENCLOSURE=$ID_ENCLOSURE"
802716fd348SMartin Matuska	echo "ID_ENCLOSURE_PATH=by-enclosure/$ENCLOSURE_PREFIX-$ID_ENCLOSURE"
803716fd348SMartin Matuska	exit 0
804716fd348SMartin Matuskafi
805716fd348SMartin Matuska
806716fd348SMartin Matuska# First check if an alias was defined for this device.
807716fd348SMartin MatuskaID_VDEV=$(alias_handler)
808716fd348SMartin Matuska
809716fd348SMartin Matuskaif [ -z "$ID_VDEV" ] ; then
810716fd348SMartin Matuska	BAY=${BAY:-bay}
811716fd348SMartin Matuska	case $TOPOLOGY in
812716fd348SMartin Matuska		sas_direct|sas_switch)
813716fd348SMartin Matuska			ID_VDEV=$(sas_handler)
814716fd348SMartin Matuska			;;
815716fd348SMartin Matuska		scsi)
816716fd348SMartin Matuska			ID_VDEV=$(scsi_handler)
817716fd348SMartin Matuska			;;
818716fd348SMartin Matuska		*)
819716fd348SMartin Matuska			echo "Error: unknown topology $TOPOLOGY"
820716fd348SMartin Matuska			exit 1
821716fd348SMartin Matuska			;;
822716fd348SMartin Matuska	esac
823716fd348SMartin Matuskafi
824716fd348SMartin Matuska
825716fd348SMartin Matuskaif [ -n "$ID_VDEV" ] ; then
826716fd348SMartin Matuska	echo "ID_VDEV=${ID_VDEV}"
827716fd348SMartin Matuska	echo "ID_VDEV_PATH=disk/by-vdev/${ID_VDEV}"
828716fd348SMartin Matuskafi
829