]>
Commit | Line | Data |
---|---|---|
c9c0d073 BB |
1 | #!/bin/bash |
2 | # | |
3 | # Set BUSES and PORTS to match the topology of your system. As each | |
4 | # port is enumerated it will be assigned the next channel name. The | |
5 | # current script enumerates each port on a bus before moving on to | |
6 | # enumerate the next bus. | |
7 | # | |
8 | # Every distribution, version of udev, and type of attached storage | |
9 | # seems to result in slightly different formatting of the by-path | |
10 | # name. For this reason you may need to adjust the parsing below | |
11 | # to suit your needs. This is one of the reasons to use a custom | |
12 | # /etc/zfs/zdev.conf file, it allows the by-path naming convertion | |
13 | # to change and still keep the simple <channel><rank> naming. | |
14 | # | |
a5b4d635 | 15 | AWK=${AWK:-/bin/awk} |
c9c0d073 BB |
16 | CONFIG=${CONFIG:-/etc/zfs/zdev.conf} |
17 | BUSES=( 01 02 03 ) | |
18 | PORTS=( 4 0 ) | |
19 | CHANNELS=( A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ) | |
a5b4d635 BB |
20 | TRIGGER="no" |
21 | MAPPING=linux | |
22 | ||
c9c0d073 BB |
23 | |
24 | usage() { | |
25 | cat << EOF | |
a5b4d635 BB |
26 | Usage: zpool_layout [-th] [-c file] [-b buses] [-p ports] [-n channels] [-m map] |
27 | -c Alternate config file [default=${CONFIG}] | |
28 | -b Enumerate buses [default="${BUSES[*]}"] | |
29 | -p Enumerate ports [default="${PORTS[*]}"] | |
c9c0d073 | 30 | -n Channel names [default="A..Z"] |
a5b4d635 BB |
31 | -t Trigger and wait for udev to settle [default=${TRIGGER}] |
32 | -m Slot mapping [default=${MAPPING}] | |
c9c0d073 BB |
33 | -h Show this message |
34 | EOF | |
35 | exit 0 | |
36 | } | |
37 | ||
a5b4d635 | 38 | while getopts 'c:b:p:n:m:th' OPTION; do |
c9c0d073 BB |
39 | case ${OPTION} in |
40 | c) | |
41 | CONFIG=${OPTARG} | |
42 | ;; | |
43 | b) | |
44 | BUSES=(${OPTARG}) | |
45 | ;; | |
46 | p) | |
47 | PORTS=(${OPTARG}) | |
48 | ;; | |
49 | n) | |
50 | CHANNELS=(${OPTARG}) | |
51 | ;; | |
a5b4d635 BB |
52 | m) |
53 | MAPPING=`readlink -e ${OPTARG}` | |
54 | ;; | |
c9c0d073 | 55 | t) |
a5b4d635 | 56 | TRIGGER=yes |
c9c0d073 BB |
57 | ;; |
58 | h) | |
59 | usage | |
60 | ;; | |
61 | esac | |
62 | done | |
63 | ||
a5b4d635 BB |
64 | # Verify mapping file exists if specified. |
65 | # Linux-Slot Custom-Slot | |
66 | if [ ${MAPPING} != "linux" ] && [ ! -e ${MAPPING} ]; then | |
67 | echo "Error: Mapping file '${MAPPING}' does not exist" | |
68 | exit 1 | |
69 | fi | |
70 | ||
c9c0d073 BB |
71 | # Save stdout as fd #8, then redirect stdout to the config file. |
72 | exec 8>&1 | |
73 | exec >${CONFIG} | |
74 | pushd /dev/disk/by-path >/dev/null | |
75 | ||
a5b4d635 BB |
76 | map_slot() { |
77 | local LINUX_SLOT=$1 | |
78 | local MAPPED_SLOT= | |
79 | ||
80 | if [ ${MAPPING} = "linux" ]; then | |
81 | MAPPED_SLOT=${LINUX_SLOT} | |
82 | else | |
83 | MAPPED_SLOT=`${AWK} "\\$1 == ${LINUX_SLOT} && !/^#/ \ | |
84 | { print \\$2; exit }" $MAPPING` | |
85 | fi | |
86 | printf "%d" ${MAPPED_SLOT} | |
87 | } | |
88 | ||
c9c0d073 BB |
89 | # Generate comment header. |
90 | echo "#" | |
91 | echo "# Custom /dev/disk/by-path to /dev/disk/zpool mapping, " | |
92 | echo "# based of the following physical cable layout." | |
93 | echo "#" | |
94 | ||
95 | # Generate host port layout table for comment header. | |
96 | echo "# ------------------ Host Port Layout ---------------------" | |
97 | echo -n "# " | |
98 | for (( i=0; i<${#BUSES[*]}; i++ )); do | |
99 | printf "%-8d" ${BUSES[$i]} | |
100 | done | |
101 | echo | |
102 | ||
103 | for (( i=0, k=0; i<${#PORTS[*]}; i++ )); do | |
104 | printf "# Port %-2d " ${PORTS[$i]} | |
105 | ||
106 | for (( j=0; j<${#BUSES[*]}; j++, k++ )); do | |
107 | let k=$j*${#PORTS[*]}+$i | |
108 | printf "%-8s" ${CHANNELS[$k]} | |
109 | done | |
110 | echo | |
111 | done | |
112 | echo "#" | |
113 | ||
114 | # Generate channel/disk layout table for comment header. | |
115 | echo "# ----------------- Channel/Disk Layout -------------------" | |
116 | echo "# Channel Disks" | |
117 | for (( i=0, k=0; i<${#BUSES[*]}; i++ )); do | |
118 | for (( j=0; j<${#PORTS[*]}; j++, k++ )); do | |
119 | printf "# %-9s" ${CHANNELS[$k]} | |
120 | ls *:${BUSES[$i]}:*:${PORTS[$j]}* 2>/dev/null | \ | |
121 | cut -f7 -d'-' | sort -u -n | tr '\n' ',' | |
122 | echo | |
123 | done | |
124 | done | |
125 | echo "#" | |
126 | ||
127 | # Generate mapping from <channel><rank> to by-path name. | |
c9c0d073 BB |
128 | for (( i=0, k=0; i<${#BUSES[*]}; i++ )); do |
129 | for (( j=0; j<${#PORTS[*]}; j++, k++ )); do | |
a5b4d635 BB |
130 | BYPATH=(`ls *:${BUSES[$i]}:*:${PORTS[$j]}* 2>/dev/null | \ |
131 | grep -v part | sort -n -k7 -t'-' | cut -f1-6 -d'-'`) | |
132 | SLOTS=(`ls *:${BUSES[$i]}:*:${PORTS[$j]}* 2>/dev/null | \ | |
133 | grep -v part | sort -n -k7 -t'-' | cut -f7 -d'-'`) | |
134 | TMP_FILE=`mktemp` | |
135 | ||
136 | for (( l=0; l<${#SLOTS[*]}; l++ )); do | |
137 | MAPPED_SLOT=`map_slot ${SLOTS[$l]}` | |
138 | printf "%s%d\t%s-%d\n" \ | |
139 | ${CHANNELS[$k]} ${MAPPED_SLOT} \ | |
140 | ${BYPATH[$l]} ${SLOTS[$l]} >>${TMP_FILE} | |
141 | done | |
c9c0d073 BB |
142 | |
143 | echo | |
144 | echo -n "# Channel ${CHANNELS[$k]}, " | |
145 | echo "Bus ${BUSES[$i]}, Port ${PORTS[$j]}" | |
a5b4d635 BB |
146 | cat ${TMP_FILE} | sort -n -k2 -t${CHANNELS[$k]} |
147 | rm -f ${TMP_FILE} | |
c9c0d073 BB |
148 | done |
149 | done | |
150 | ||
151 | # Restore stdout from fd #8 and close fd #8. | |
152 | exec 1>&8 8>&- | |
c9c0d073 BB |
153 | popd >/dev/null |
154 | ||
a5b4d635 | 155 | if [ ${TRIGGER} = "yes" ]; then |
fa417e57 | 156 | udevadm trigger --action=change --subsystem-match=block |
c9c0d073 BB |
157 | udevadm settle |
158 | fi | |
159 | ||
160 | exit 0 |