2 # This file and its contents are supplied under the terms of the
3 # Common Development and Distribution License ("CDDL"), version 1.0.
4 # You may only use this file in accordance with the terms of version
7 # A full copy of the text of the CDDL should have accompanied this
8 # source. A copy of the CDDL is also available via the Internet at
9 # http://www.illumos.org/license/CDDL.
13 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
14 # Use is subject to license terms.
15 # Copyright (c) 2012, 2016 by Delphix. All rights reserved.
16 # Copyright 2016 Nexenta Systems, Inc.
17 # Copyright (c) 2016, 2017 by Intel Corporation. All rights reserved.
18 # Copyright (c) 2017 Lawrence Livermore National Security, LLC.
19 # Copyright (c) 2017 Datto Inc.
20 # Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
21 # Copyright 2019 Richard Elling
25 # Returns SCSI host number for the given disk
27 function get_scsi_host #disk
30 ls /sys/block/${disk}/device/scsi_device | cut -d : -f 1
34 # Cause a scan of all scsi host adapters by default
36 # $1 optional host number
38 function scan_scsi_hosts
43 if [[ -z $hostnum ]]; then
44 for host in /sys/class/scsi_host/host*; do
45 log_must eval "echo '- - -' > $host/scan"
49 "echo /sys/class/scsi_host/host$hostnum/scan" \
52 "echo '- - -' > /sys/class/scsi_host/host$hostnum/scan"
58 # Wait for newly created block devices to have their minors created.
59 # Additional arguments can be passed to udevadm trigger, with the expected
60 # arguments to typically be a block device pathname. This is useful when
61 # checking waiting on a specific device to settle rather than triggering
62 # all devices and waiting for them all to settle.
64 # The udevadm settle timeout can be 120 or 180 seconds by default for
65 # some distros. If a long delay is experienced, it could be due to some
66 # strangeness in a malfunctioning device that isn't related to the devices
67 # under test. To help debug this condition, a notice is given if settle takes
70 # Note: there is no meaningful return code if udevadm fails. Consumers
71 # should not expect a return code (do not call as argument to log_must)
73 function block_device_wait
77 typeset local start=$SECONDS
79 typeset local elapsed=$((SECONDS - start))
80 [[ $elapsed > 60 ]] && \
81 log_note udevadm settle time too long: $elapsed
86 # Check if the given device is physical device
88 function is_physical_device #device
90 typeset device=${1#$DEV_DSKDIR}
91 device=${device#$DEV_RDSKDIR}
94 [[ -b "$DEV_DSKDIR/$device" ]] && \
95 [[ -f /sys/module/loop/parameters/max_part ]]
98 echo $device | egrep "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1
104 # Check if the given device is a real device (ie SCSI device)
106 function is_real_device #disk
109 [[ -z $disk ]] && log_fail "No argument for disk given."
112 lsblk $DEV_RDSKDIR/$disk -o TYPE 2>/dev/null | \
113 egrep disk >/dev/null
119 # Check if the given device is a loop device
121 function is_loop_device #disk
124 [[ -z $disk ]] && log_fail "No argument for disk given."
127 lsblk $DEV_RDSKDIR/$disk -o TYPE 2>/dev/null | \
128 egrep loop >/dev/null
134 # Check if the given device is a multipath device and if there is a sybolic
135 # link to a device mapper and to a disk
136 # Currently no support for dm devices alone without multipath
138 function is_mpath_device #disk
141 [[ -z $disk ]] && log_fail "No argument for disk given."
144 lsblk $DEV_MPATHDIR/$disk -o TYPE 2>/dev/null | \
145 egrep mpath >/dev/null
147 readlink $DEV_MPATHDIR/$disk > /dev/null 2>&1
155 # Set the slice prefix for disk partitioning depending
156 # on whether the device is a real, multipath, or loop device.
157 # Currently all disks have to be of the same type, so only
158 # checks first disk to determine slice prefix.
160 function set_slice_prefix
166 while (( i < $DISK_ARRAY_NUM )); do
167 disk="$(echo $DISKS | nawk '{print $(i + 1)}')"
168 if ( is_mpath_device $disk ) && [[ -z $(echo $disk | awk 'substr($1,18,1)\
169 ~ /^[[:digit:]]+$/') ]] || ( is_real_device $disk ); then
170 export SLICE_PREFIX=""
172 elif ( is_mpath_device $disk || is_loop_device \
174 export SLICE_PREFIX="p"
177 log_fail "$disk not supported for partitioning."
185 # Set the directory path of the listed devices in $DISK_ARRAY_NUM
186 # Currently all disks have to be of the same type, so only
187 # checks first disk to determine device directory
188 # default = /dev (linux)
189 # real disk = /dev (linux)
190 # multipath device = /dev/mapper (linux)
192 function set_device_dir
198 while (( i < $DISK_ARRAY_NUM )); do
199 disk="$(echo $DISKS | nawk '{print $(i + 1)}')"
200 if is_mpath_device $disk; then
201 export DEV_DSKDIR=$DEV_MPATHDIR
204 export DEV_DSKDIR=$DEV_RDSKDIR
210 export DEV_DSKDIR=$DEV_RDSKDIR
215 # Get the directory path of given device
217 function get_device_dir #device
221 if ! $(is_physical_device $device) ; then
222 if [[ $device != "/" ]]; then
225 if [[ -b "$DEV_DSKDIR/$device" ]]; then
235 # Get persistent name for given disk
237 function get_persistent_disk_name #device
243 if is_real_device $device; then
244 dev_id="$(udevadm info -q all -n $DEV_DSKDIR/$device \
245 | egrep disk/by-id | nawk '{print $2; exit}' \
246 | nawk -F / '{print $3}')"
248 elif is_mpath_device $device; then
249 dev_id="$(udevadm info -q all -n $DEV_DSKDIR/$device \
250 | egrep disk/by-id/dm-uuid \
251 | nawk '{print $2; exit}' \
252 | nawk -F / '{print $3}')"
263 # Online or offline a disk on the system
265 # First checks state of disk. Test will fail if disk is not properly onlined
266 # or offlined. Online is a full rescan of SCSI disks by echoing to every
269 function on_off_disk # disk state{online,offline} host
275 [[ -z $disk ]] || [[ -z $state ]] && \
276 log_fail "Arguments invalid or missing"
279 if [[ $state == "offline" ]] && ( is_mpath_device $disk ); then
280 dm_name="$(readlink $DEV_DSKDIR/$disk \
281 | nawk -F / '{print $2}')"
282 slave="$(ls /sys/block/${dm_name}/slaves \
283 | nawk '{print $1}')"
284 while [[ -n $slave ]]; do
285 #check if disk is online
286 lsscsi | egrep $slave > /dev/null
288 slave_dir="/sys/block/${dm_name}"
289 slave_dir+="/slaves/${slave}/device"
290 ss="${slave_dir}/state"
291 sd="${slave_dir}/delete"
292 log_must eval "echo 'offline' > ${ss}"
293 log_must eval "echo '1' > ${sd}"
294 lsscsi | egrep $slave > /dev/null
296 log_fail "Offlining" \
300 slave="$(ls /sys/block/$dm_name/slaves \
301 2>/dev/null | nawk '{print $1}')"
303 elif [[ $state == "offline" ]] && ( is_real_device $disk ); then
304 #check if disk is online
305 lsscsi | egrep $disk > /dev/null
307 dev_state="/sys/block/$disk/device/state"
308 dev_delete="/sys/block/$disk/device/delete"
309 log_must eval "echo 'offline' > ${dev_state}"
310 log_must eval "echo '1' > ${dev_delete}"
311 lsscsi | egrep $disk > /dev/null
313 log_fail "Offlining $disk" \
317 log_note "$disk is already offline"
319 elif [[ $state == "online" ]]; then
321 scan_scsi_hosts $host
323 if is_mpath_device $disk; then
324 dm_name="$(readlink $DEV_DSKDIR/$disk \
325 | nawk -F / '{print $2}')"
326 slave="$(ls /sys/block/$dm_name/slaves \
327 | nawk '{print $1}')"
328 lsscsi | egrep $slave > /dev/null
330 log_fail "Onlining $disk failed"
332 elif is_real_device $disk; then
335 while ! lsscsi | egrep -q $disk; do
336 if (( $retries > 2 )); then
337 log_fail "Onlining $disk failed"
344 log_fail "$disk is not a real dev"
347 log_fail "$disk failed to $state"
353 # Simulate disk removal
355 function remove_disk #disk
358 on_off_disk $disk "offline"
363 # Simulate disk insertion for the given SCSI host
365 function insert_disk #disk scsi_host
369 on_off_disk $disk "online" $scsi_host
374 # Load scsi_debug module with specified parameters
375 # $blksz can be either one of: < 512b | 512e | 4Kn >
377 function load_scsi_debug # dev_size_mb add_host num_tgts max_luns blksz
385 [[ -z $devsize ]] || [[ -z $hosts ]] || [[ -z $tgts ]] || \
386 [[ -z $luns ]] || [[ -z $blksz ]] && \
387 log_fail "Arguments invalid or missing"
402 *) log_fail "Unsupported blksz value: $5" ;;
406 modprobe -n scsi_debug
408 log_unsupported "Platform does not have scsi_debug"
411 lsmod | egrep scsi_debug > /dev/null
413 log_fail "scsi_debug module already installed"
415 log_must modprobe scsi_debug dev_size_mb=$devsize \
416 add_host=$hosts num_tgts=$tgts max_luns=$luns \
417 sector_size=$sector physblk_exp=$blkexp
419 lsscsi | egrep scsi_debug > /dev/null
421 log_fail "scsi_debug module install failed"
428 # Unload scsi_debug module, if needed.
430 function unload_scsi_debug
432 log_must_retry "in use" 5 modprobe -r scsi_debug
436 # Get scsi_debug device name.
437 # Returns basename of scsi_debug device (for example "sdb").
439 function get_debug_device
441 for i in {1..10} ; do
442 val=$(lsscsi | nawk '/scsi_debug/ {print $6; exit}' | cut -d / -f3)
444 # lsscsi can take time to settle
445 if [ "$val" != "-" ] ; then
454 # Get actual devices used by the pool (i.e. linux sdb1 not sdb).
456 function get_pool_devices #testpool #devdir
463 out=$(zpool status -P $testpool |grep ${devdir} | awk '{print $1}')
464 out=$(echo $out | sed -e "s|${devdir}/||g" | tr '\n' ' ')