From 5107a7be16e4849fbda7beae0504fdbc0f2cb4b5 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 9 Aug 2022 13:12:26 +0200 Subject: [PATCH 1/7] zconf/lsdasd: fix Copy Pair related output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the default output for copy pair secondary devices to not show a faulty blockdevice entry and major:minor combination. The new output looks like: # lsdasd Bus-ID Status Name Device Type BlkSz Size Blocks ================================================================================ 0.0.9740 secondary ECKD 0.0.9741 secondary ECKD 0.0.9742 secondary ECKD 0.0.e964 active dasda 94:0 ECKD 4096 21129MB 5409180 0.0.e967 active dasdb 94:4 ECKD 4096 21129MB 5409180 0.0.9330 active dasdc 94:8 ECKD 4096 782MB 200340 0.0.9700 active dasdd 94:12 ECKD 4096 782MB 200340 0.0.9701 active dasdf 94:20 ECKD 4096 782MB 200340 0.0.9702 active dasdh 94:28 ECKD 4096 782MB 200340 Also add copy_pairs to extended output: # lsdasd -l 9700 0.0.9700/dasdd/94:12 status: active type: ECKD blksz: 4096 size: 782MB blocks: 200340 extent_size: 1113 logical_capacity: 1113 space_allocated: 1113 use_diag: 0 readonly: 0 eer_enabled: 0 erplog: 0 hpf: 1 uid: IBM.750000000ABT31.9700.00 fc_security: Unsupported paths_installed: 38 39 3a 3b paths_in_use: 38 39 3a 3b paths_non_preferred: paths_invalid_cabling: paths_cuir_quiesced: paths_invalid_hpf_characteristics: paths_error_threshold_exceeded: copy_pairs: 0.0.9700,0.0.9740 0.0.9700,0.0.9743 0.0.9700,0.0.9744 0.0.9700,0.0.9745 Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Jan Höppner --- zconf/lsdasd | 113 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 17 deletions(-) diff --git a/zconf/lsdasd b/zconf/lsdasd index 795b33b..8b2cc0f 100755 --- a/zconf/lsdasd +++ b/zconf/lsdasd @@ -146,6 +146,62 @@ function findDASDDebugfsDirectorie() { fi } +#------------------------------------------------------------------------------ +# The blockpath can usually be found over the DEVPATH +# In case of a swapped Copy Pair device the blockdev is likely associated +# with one of the secondary devices +# this function checks if the blockdev is associated with the primary device +# and if not search for it in the secondary device list +#------------------------------------------------------------------------------ +function setCorrectBlockPath() { + local DRIVERECKD="$SYSFSDIR/bus/ccw/drivers/dasd-eckd/" + local DRIVERFBA="$SYSFSDIR/bus/ccw/drivers/dasd-fba/" + local SEARCHDIRS= + local SEARCHLIST= + + if [[ "$COPYROLE" == "none" ]] || [[ -d "$DEVPATH/block" ]]; then + BLOCKPATH="$DEVPATH"/block/dasd* + return + fi + + if [[ -d "$DRIVERECKD" ]]; then + SEARCHDIRS="$DRIVERECKD" + fi + if [[ -d "$DRIVERFBA" ]]; then + SEARCHDIRS="$SEARCHDIRS $DRIVERFBA" + fi + + SEARCHLIST=$(echo $SECONDARY_LIST | sed 's/,/ /g') + for SEARCHDEV in $SEARCHLIST + do + if [[ -n "$SEARCHDIRS" ]]; then + PRIM_DEVPATH=$(find $SEARCHDIRS -type l -name $SEARCHDEV \ + -printf "%h/%l\n" 2> /dev/null) + if [[ -d "$PRIM_DEVPATH/block" ]]; then + break + fi + else + # The above paths may become invalid in the future, so we keep the + # following query as backup: + PRIM_DEVPATH=$(find "$SYSFSDIR/devices" -type l -name $SEARCHDEV \ + "driver" -lname "*/dasd*" -printf "%h\n" \ + 2> /dev/null) + fi + done + + BLOCKPATH="$PRIM_DEVPATH"/block/dasd* +} + +#------------------------------------------------------------------------------ +# gather Copy Pair related data +#------------------------------------------------------------------------------ +function gatherCopyPairData() { + read COPYPAIR 2> /dev/null < $DEVPATH/copy_pair + PRIMARY_UID=`echo $COPYPAIR | cut -d " " -f1 | cut -d "," -f1` + COPYPAIR=`echo "$COPYPAIR" | sed 's/ /,/g' | sed 's/^,//' ` + SECONDARY_LIST=`echo ${COPYPAIR//$PRIMARY_UID","/} ` +} + #------------------------------------------------------------------------------ # gather device data and call appropriate output function #------------------------------------------------------------------------------ @@ -165,16 +221,18 @@ function gatherDeviceData() { read READONLY 2> /dev/null < $DEVPATH/readonly || continue read DISCIPLINE 2> /dev/null < $DEVPATH/discipline || continue read ESE 2> /dev/null < $DEVPATH/ese + read COPYROLE 2> /dev/null < $DEVPATH/copy_role + if [[ "$COPYROLE" != "none" ]]; then + gatherCopyPairData + fi # Block device specific information is only available for # devices that are online and not a PAV alias - if [[ ! "$ONLINE" == 0 ]] && [[ ! "$ALIAS" == 1 ]]; then - #find device Path to the block device - if [[ -d "$DEVPATH/block" ]]; then - set - "$DEVPATH"/block/dasd* - else - set - "$DEVPATH"/block:dasd* - fi + if [[ ! "$ONLINE" == 0 ]] && [[ ! "$ALIAS" == 1 ]] && + [[ ! "$COPYROLE" == "secondary" ]]; then + #find device Path to the block device + setCorrectBlockPath + set - $BLOCKPATH MAJMIN= MAJOR= MINOR= @@ -194,10 +252,12 @@ function gatherDeviceData() { fi fi else - # BLOCKNAME for offline and alias devices will not be - # printed, it's just a key for sorting + # BLOCKNAME for offline, alias and secondary devices + # will not be printed, it's just a key for sorting if [[ "$ONLINE" == 0 ]]; then BLOCKNAME="" + elif [[ "$COPYROLE" == "secondary" ]]; then + BLOCKNAME="b" else BLOCKNAME="a" fi @@ -261,6 +321,15 @@ function newoutput() return fi + if [[ "$COPYROLE" == "secondary" ]]; then + printf "%s:%s:%-8s secondary %-8s %13s\n" \ + "$SORTKEYLEN" "$SORTKEY" \ + "$BUSID" \ + "$PRIMARY_BLOCKNAME" \ + "$DISCIPLINE" + return + fi + if [[ "$READONLY" == 0 ]]; then ROSTRING="" else @@ -519,10 +588,14 @@ function extended() "${HPF_PATHS[@]}" \ "${IFCC_PATHS[@]}" ; return - elif [[ "$ALIAS" == 1 ]]; then - if [[ "$BASEONLY" == "false" ]]; then - ACTIVE="alias" - printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \ + elif [[ "$ALIAS" == 1 ]] || [[ "$COPYROLE" == "secondary" ]]; then + if [[ "$BASEONLY" == "false" ]] || [[ "$COPYROLE" == "secondary" ]]; then + if [[ "$COPYROLE" == "secondary" ]]; then + ACTIVE="secondary" + else + ACTIVE="alias" + fi + printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s# copy_pairs:\t\t\t\t%s#\n" \ "$SORTKEYLEN" "$SORTKEY" \ "$BUSID" \ "$ACTIVE" \ @@ -540,7 +613,8 @@ function extended() "${CABLE_PATHS[@]}" \ "${CUIR_PATHS[@]}" \ "${HPF_PATHS[@]}" \ - "${IFCC_PATHS[@]}" ; + "${IFCC_PATHS[@]}" \ + "${COPYPAIR}" ; fi return elif [[ -z "$BLOCKNAME" ]] || [[ -z "$SIZE" ]]; then @@ -565,7 +639,7 @@ function extended() DISCIPLINE="${DISCIPLINE} (ESE)" fi - printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \ + printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s# copy_pairs:\t\t\t\t%s#\n" \ "$SORTKEYLEN" "$SORTKEY" \ "$BUSID" \ "$BLOCKNAME" \ @@ -593,7 +667,8 @@ function extended() "${CABLE_PATHS[@]}" \ "${CUIR_PATHS[@]}" \ "${HPF_PATHS[@]}" \ - "${IFCC_PATHS[@]}" ; + "${IFCC_PATHS[@]}" \ + "${COPYPAIR}" ; } function host() @@ -710,7 +785,11 @@ function uid() fi fi - printf "%s:%s:%-8s %-8s %s\n" \ + if [[ "$COPYROLE" == "secondary" ]]; then + BLOCKNAME="secondary" + fi + + printf "%s:%s:%-8s %-10s %s\n" \ "$SORTKEYLEN" "$SORTKEY" \ "$BUSID" \ "$BLOCKNAME" \ -- 2.38.1 From 803b87e324d704036c5bef1d1daba6cf5b69b668 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 12 Oct 2022 15:55:43 +0200 Subject: [PATCH 2/7] zconf/lsdasd: add Copy Pair output option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an option -P|--copy-pairs to show all DASD devices with copy relations set up in the system and their roles. The output looks like: # ./s390-tools/zconf/lsdasd -h [...] -P|--copy-pairs Print information about copy pairs. # ./s390-tools/zconf/lsdasd -P Bus-ID Role Name Paired devices ================================================================================ 0.0.9700 primary dasdd 0.0.9740,0.0.9743,0.0.9744,0.0.9745 0.0.9740 secondary 0.0.9700 0.0.9701 primary dasdf 0.0.9741 0.0.9741 secondary 0.0.9701 0.0.9702 primary dasdh 0.0.9742 0.0.9742 secondary 0.0.9702 Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Jan Höppner --- zconf/lsdasd | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/zconf/lsdasd b/zconf/lsdasd index 8b2cc0f..59720b6 100755 --- a/zconf/lsdasd +++ b/zconf/lsdasd @@ -35,6 +35,8 @@ function PrintUsage() { Print extended information about DASDs. -H|--host-access-list Print information about hosts accessing DASDs. + -P|--copy-pairs + Print information about copy pairs. -v|--verbose For compatibility/future use. Currently ignored. --version @@ -292,6 +294,8 @@ function gatherDeviceData() { uid elif [[ "$OUTPUT" == "host" ]]; then host + elif [[ "$OUTPUT" == "copy" ]]; then + copy else newoutput fi @@ -769,6 +773,41 @@ printf "\n"; rm -f $temp } +# pad sortkey with given number zeroes +function padSortKey() +{ + local LEN=$1 + for (( i=0; i<$LEN; i++ )) + do + printf -v SORTKEY "%s0" $SORTKEY + done +} + +function copy() +{ + if [[ "$COPYROLE" == "none" ]]; then + return + fi + + SORTKEYLEN=$((${#PRIMARY_UID}+${#DEV_UID})) + if [[ "$COPYROLE" == "secondary" ]]; then + SORTKEY=$PRIMARY_UID$DEV_UID + PAIREDDEVICES=$PRIMARY_UID + BLOCKNAME="" + else + SORTKEY=$PRIMARY_UID + padSortKey ${#DEV_UID} + PAIREDDEVICES=$SECONDARY_LIST + fi + + printf "%s:%s:%-8s %-10s %-8s %-8s %s \n" \ + "$SORTKEYLEN" "$SORTKEY" \ + "$BUSID" \ + "$COPYROLE" \ + "$BLOCKNAME" \ + "$PAIREDDEVICES"; +} + function uid() { #-------------------------------------------# @@ -835,6 +874,9 @@ while [ $# -gt 0 ]; do --host-access-list|-H) OUTPUT="host" ;; + --copy-pairs|-P) + OUTPUT="copy" + ;; --version) PrintVersion exit 0 @@ -889,6 +931,9 @@ if [[ "$PRINTUID" == "true" ]] && [[ "$OUTPUT" != "old" ]]; then elif [[ "$OUTPUT" == "new" ]]; then printf "Bus-ID Status Name Device Type BlkSz Size Blocks\n" printf "================================================================================\n" +elif [[ "$OUTPUT" == "copy" ]]; then + printf "Bus-ID Role Name Paired devices\n"; + printf "================================================================================\n"; elif [[ "$OUTPUT" == "extended" ]]; then PROCESSING=" $PROCESSING | sed 's/#/\n/g' " fi -- 2.38.1 From e742d1c9ae5103c9f88d3fde085e0694efaeeb5a Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 11 Aug 2022 13:52:30 +0200 Subject: [PATCH 3/7] zdev: correctly handle multiple values for CCW devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctly create multiple lines in the udev rule for CCW device attributes with multi bit set that contain multiple values. Suggested-by: Peter Oberparleiter Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Reviewed-by: Peter Oberparleiter Signed-off-by: Jan Höppner --- zdev/src/udev_ccw.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/zdev/src/udev_ccw.c b/zdev/src/udev_ccw.c index 7c0a703..3375a5e 100644 --- a/zdev/src/udev_ccw.c +++ b/zdev/src/udev_ccw.c @@ -221,6 +221,7 @@ static void write_attr_to_file(FILE *fd, struct device_state *state, const char struct ptrlist_node *p; struct setting *s; struct util_list *list = NULL; + struct strlist_node *str; /* Apply attributes in correct order. */ list = setting_list_get_sorted(state->settings); @@ -229,8 +230,13 @@ static void write_attr_to_file(FILE *fd, struct device_state *state, const char s = p->ptr; if (s->removed) continue; - if ((s->attrib && s->attrib->internal) || - internal_by_name(s->name)) { + if (s->values) { + util_list_iterate(s->values, str) { + fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", + id, s->name, str->str); + } + } else if ((s->attrib && s->attrib->internal) || + internal_by_name(s->name)) { fprintf(fd, "ENV{zdev_%s}=\"%s\"\n", internal_get_name(s->name), s->value); } else { -- 2.38.1 From f654b971d0e78a139c7ed8c0df821af2f4356a8b Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 9 Aug 2022 16:17:23 +0200 Subject: [PATCH 4/7] zdev: add copy_pair attribute for DASD devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DASD device driver has a new attribute copy_pair to make storage server copy pairs known to the driver. Add this attribute to zdev. Usage example: Add two copy pairs 1000,2000 and 1000,3000 to a DASD device 1000 $ chzdev dasd 1000 copy_pairs=1000,2000 copy_pairs=1000,3000 or $ chzdev dasd 1000 copy_pairs="1000,2000 1000,3000" To add a third copy pair later on: $ chzdev dasd 1000 copy_pairs=1000,4000 To remove all copy pairs from the device 1000: $ chzdev dasd 1000 -r copy_pairs Signed-off-by: Stefan Haberland Reviewed-by: Peter Oberparleiter Signed-off-by: Jan Höppner --- zdev/src/dasd.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/zdev/src/dasd.c b/zdev/src/dasd.c index daec916..f9fd231 100644 --- a/zdev/src/dasd.c +++ b/zdev/src/dasd.c @@ -137,6 +137,21 @@ static struct attrib dasd_attr_readonly = { .accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)), }; +static struct attrib dasd_attr_copy_pair = { + .name = "copy_pair", + .title = "Modify copy-pair relations", + .desc = "Make a copy-pair relation for this device known to the DASD " + "driver.\n" + "A copy-pair is a comma-separated pair of device bus-IDs\n" + ",.\n" + "Example: 0.0.1000,0.0.2000\n" + "Up to 4 copy-pairs are accepted by the DASD driver for each " + "device.\n", + .unstable = 1, + .multi = 1, + .activerem = 1, +}; + static struct attrib dasd_attr_erplog = { .name = "erplog", .title = "Enable logging of Error Recovery Processing", @@ -600,6 +615,81 @@ persistent: return rc; } +/* Remove all entries from the copy_pair attribute by writing 'clear' to it. */ +static void dasd_clear_copy_pair(struct setting *s) +{ + free(s->value); + s->value = misc_strdup("clear"); + strlist_free(s->values); + s->values = strlist_new(); + strlist_add(s->values, "clear"); + s->removed = 0; + s->modified = 1; +} + +/* + * Copy-pair values may contain multiple values in one line + * those need to be split up and put in multiple values entries + * delimiter is " " and "\n" depending on the source + * values read from sysfs have " " as delimiter and values from + * zdev have "\n" + */ +static void dasd_split_copy_pair(struct setting *s) +{ + struct util_list *new = NULL; + struct strlist_node *node; + + new = strlist_new(); + util_list_iterate(s->values, node) + strlist_add_multi(new, node->str, "\n ", 0); + + strlist_free(s->values); + s->values = new; +} + +/* + * For persistent configurations one value per values[] entry is required + * to achieve a correct multi-line copy-pair statement in the resulting + * udev-rule. + */ +static exit_code_t dasd_st_configure_persistent(struct subtype *st, + struct device *dev) +{ + struct setting *s; + + util_list_iterate(&dev->persistent.settings->list, s) { + if (strcmp(s->name, "copy_pair") == 0) + dasd_split_copy_pair(s); + } + + return st->super->configure_persistent(st, dev); +} + +/* + * For active configurations one value per values[] entry is required to + * correctly operate the sysfs attribute. + * + * In case of removal the string "clear" has to be written to the + * value and values[] entry. + */ +static exit_code_t dasd_st_configure_active(struct subtype *st, + struct device *dev) +{ + struct setting *s; + + util_list_iterate(&dev->active.settings->list, s) { + if (strcmp(s->name, "copy_pair") != 0) + continue; + + if (s->removed) + dasd_clear_copy_pair(s); + else + dasd_split_copy_pair(s); + } + + return st->super->configure_active(st, dev); +} + /* * DASD device sub-types. */ @@ -634,10 +724,13 @@ struct subtype dasd_subtype_eckd = { &dasd_attr_last_known_reservation_state, &dasd_attr_safe_offline, &dasd_attr_fc_security, + &dasd_attr_copy_pair, &internal_attr_early, ), .unknown_dev_attribs = 1, + .configure_active = &dasd_st_configure_active, + .configure_persistent = &dasd_st_configure_persistent, .check_pre_configure = &dasd_st_check_pre_configure, .add_modules = &dasd_st_add_modules, }; -- 2.38.1 From 4e28047eb4cacc7b7208018a8c095102517517e8 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 10 Nov 2022 16:11:09 +0100 Subject: [PATCH 5/7] tunedasd: move tunedasd ioctls to libdasd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all DASD IOCTLs to libdasd and adapt all affected users accordingly. Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Jan Höppner --- include/lib/dasd_base.h | 73 +++++++++++ libdasd/dasd_ioctl.c | 129 +++++++++++++++++++ tunedasd/src/disk.c | 268 ++++++++-------------------------------- 3 files changed, 252 insertions(+), 218 deletions(-) diff --git a/include/lib/dasd_base.h b/include/lib/dasd_base.h index b12e1f9..11ec94b 100644 --- a/include/lib/dasd_base.h +++ b/include/lib/dasd_base.h @@ -187,6 +187,61 @@ typedef struct format_check_t { #define DASD_FMT_ERR_RECORD_ID 4 #define DASD_FMT_ERR_KEY_LENGTH 5 +/* + * struct profile_info_t + * holds the profiling information + */ +typedef struct dasd_profile_info_t { + unsigned int dasd_io_reqs; /* # of requests processed at all */ + unsigned int dasd_io_sects; /* # of sectors processed at all */ + unsigned int dasd_io_secs[32]; /* request's sizes */ + unsigned int dasd_io_times[32]; /* requests's times */ + unsigned int dasd_io_timps[32]; /* requests's times per sector */ + unsigned int dasd_io_time1[32]; /* time from build to start */ + unsigned int dasd_io_time2[32]; /* time from start to irq */ + unsigned int dasd_io_time2ps[32]; /* time from start to irq */ + unsigned int dasd_io_time3[32]; /* time from irq to end */ + unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */ +} dasd_profile_info_t; + +/* + * struct attrib_data_t + * represents the operation (cache) bits for the device. + * Used in DE to influence caching of the DASD. + */ +typedef struct attrib_data_t { + unsigned char operation : 3; /* cache operation mode */ + unsigned char reserved : 5; + unsigned short nr_cyl; /* no of cyliners for read ahaed */ + unsigned char reserved2[29]; /* for future use */ +} __attribute__((packed)) attrib_data_t; + +/* definition of operation (cache) bits within attributes of DE */ +#define DASD_NORMAL_CACHE 0x0 +#define DASD_BYPASS_CACHE 0x1 +#define DASD_INHIBIT_LOAD 0x2 +#define DASD_SEQ_ACCESS 0x3 +#define DASD_SEQ_PRESTAGE 0x4 +#define DASD_REC_ACCESS 0x5 + +/* + * Data returned by Sense Path Group ID (SNID) + */ +struct dasd_snid_data { + struct { + __u8 group : 2; + __u8 reserve : 2; + __u8 mode : 1; + __u8 res : 3; + } __attribute__((packed)) path_state; + __u8 pgid[11]; +} __attribute__((packed)); + +struct dasd_snid_ioctl_data { + struct dasd_snid_data data; + __u8 path_mask; +} __attribute__((packed)); + #ifndef __linux__ /* definition from hdreg.h */ struct hd_geometry { @@ -207,12 +262,24 @@ struct hd_geometry { #define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2) /* Release the device for the current LPAR */ #define BIODASDRLSE _IO(DASD_IOCTL_LETTER, 3) +/* Unconditional reserve the device for the current LPAR */ +#define BIODASDSLCK _IO(DASD_IOCTL_LETTER, 4) +/* reset profiling information of a device */ +#define BIODASDPRRST _IO(DASD_IOCTL_LETTER, 5) +/* retrieve profiling information of a device */ +#define BIODASDPRRD _IOR(DASD_IOCTL_LETTER, 2, dasd_profile_info_t) /* Get information on a dasd device (enhanced) */ #define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t) +/* Get Attributes (cache operations) */ +#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER, 5, attrib_data_t) /* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */ #define BIODASDFMT _IOW(DASD_IOCTL_LETTER, 1, format_data_t) +/* Set Attributes (cache operations) */ +#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER, 2, attrib_data_t) /* Release Allocated Space */ #define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t) +/* Get Sense Path Group ID (SNID) data */ +#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data) /* Check device format according to format_data_t */ #define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t) @@ -245,5 +312,11 @@ int dasd_is_ro(const char *device, bool *ro); int dasd_reread_partition_table(const char *device, int ntries); int dasd_disk_reserve(const char *device); int dasd_disk_release(const char *device); +int dasd_slock(const char *device); +int dasd_get_cache(const char *device, attrib_data_t *attrib_data); +int dasd_set_cache(const char *device, attrib_data_t *attrib_data); +int dasd_query_reserve(const char *device); +int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info); +int dasd_reset_profile(const char *device); #endif /* LIB_DASD_BASE_H */ diff --git a/libdasd/dasd_ioctl.c b/libdasd/dasd_ioctl.c index f954961..40e726c 100644 --- a/libdasd/dasd_ioctl.c +++ b/libdasd/dasd_ioctl.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "lib/dasd_base.h" @@ -321,3 +322,131 @@ int dasd_disk_release(const char *device) return 0; } + +/* + * Unconditionally reserve DASD disk + * + * An existing reserve lock is lifted (steal lock) and the device + * is reserved. + * + * @param[in] device node device node's name + * + * @retval 0 in case of success + * @retval errno in case of failure + */ +int dasd_slock(const char *device) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDSLCK, NULL); + dasd_close_device(fd); + + return 0; +} + +/* + * Get the caching algorithm used for the channel programs of this device. + * + * @param[in] device node device node's name + * @param[out] attrib_data pointer to dasd attrib data with: + * 'cache' is the caching mode + * 'no_cyl' the number of cylinders to be cached. + * + * @retval 0 in case of success + * @retval errno in case of failure + */ +int dasd_get_cache(const char *device, attrib_data_t *attrib_data) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDGATTR, attrib_data); + dasd_close_device(fd); + + return 0; +} + +/* + * Set the caching algorithm used for the channel programs of this device. + * + * @param[in] device node device node's name + * @param[in] attrib_data pointer to dasd attrib data with: + * 'cache' is the caching mode + * 'no_cyl' the number of cylinders to be cached. + * + * @retval 0 in case of success + * @retval errno in case of failure + */ +int dasd_set_cache(const char *device, attrib_data_t *attrib_data) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDSATTR, attrib_data); + dasd_close_device(fd); + + return 0; +} + +/* + * Get reserve status of device. + * + * @param[in] device node device node's name + * + * @retval errno in case of failure + * @retval 0 unreserved + * @retval 1 implicit reserved + * @retval 2 other reservation + * @retval 3 reserved + */ +int dasd_query_reserve(const char *device) +{ + struct dasd_snid_ioctl_data snid = { 0 }; + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDSNID, &snid); + dasd_close_device(fd); + + return snid.data.path_state.reserve; +} + +/* + * Get and print the profiling info of the device. + * + * @param[in] device node device node's name + * @param[in] dasd_profile_info pointer to dasd profile info + * + * @retval 0 in case of success + * @retval errno in case of failure + */ +int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDPRRD, dasd_profile_info); + dasd_close_device(fd); + + return 0; +} + +/* + * Reset the profiling counters of the device. + * + * @param[in] device node device node's name + * + * @retval 0 in case of success + * @retval errno in case of failure + */ +int dasd_reset_profile(const char *device) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDPRRST, NULL); + dasd_close_device(fd); + + return 0; +} diff --git a/tunedasd/src/disk.c b/tunedasd/src/disk.c index f240651..1e8de16 100644 --- a/tunedasd/src/disk.c +++ b/tunedasd/src/disk.c @@ -19,6 +19,7 @@ #include #include +#include "lib/dasd_base.h" #include "lib/dasd_sys.h" #include "disk.h" @@ -26,91 +27,6 @@ #define BUS_ID_SIZE 30 -/* - * DASD DEFINITIONS (copied from dasd.h) - */ - -#define DASD_IOCTL_LETTER 'D' - -/* - * struct profile_info_t - * holds the profiling information - */ -typedef struct dasd_profile_info_t { - unsigned int dasd_io_reqs; /* # of requests processed at all */ - unsigned int dasd_io_sects; /* # of sectors processed at all */ - unsigned int dasd_io_secs[32]; /* request's sizes */ - unsigned int dasd_io_times[32]; /* requests's times */ - unsigned int dasd_io_timps[32]; /* requests's times per sector */ - unsigned int dasd_io_time1[32]; /* time from build to start */ - unsigned int dasd_io_time2[32]; /* time from start to irq */ - unsigned int dasd_io_time2ps[32]; /*time from start to irq */ - unsigned int dasd_io_time3[32]; /* time from irq to end */ - unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */ -} dasd_profile_info_t; - - -/* - * struct attrib_data_t - * represents the operation (cache) bits for the device. - * Used in DE to influence caching of the DASD. - */ -typedef struct attrib_data_t { - unsigned char operation:3; /* cache operation mode */ - unsigned char reserved:5; - unsigned short nr_cyl; /* no of cyliners for read ahaed */ - unsigned char reserved2[29]; /* for future use */ -} __attribute__ ((packed)) attrib_data_t; - -/* definition of operation (cache) bits within attributes of DE */ -#define DASD_NORMAL_CACHE 0x0 -#define DASD_BYPASS_CACHE 0x1 -#define DASD_INHIBIT_LOAD 0x2 -#define DASD_SEQ_ACCESS 0x3 -#define DASD_SEQ_PRESTAGE 0x4 -#define DASD_REC_ACCESS 0x5 - -/* - * Data returned by Sense Path Group ID (SNID) - */ -struct dasd_snid_data { - struct { - __u8 group:2; - __u8 reserve:2; - __u8 mode:1; - __u8 res:3; - } __attribute__ ((packed)) path_state; - __u8 pgid[11]; -} __attribute__ ((packed)); - -struct dasd_snid_ioctl_data { - struct dasd_snid_data data; - __u8 path_mask; -} __attribute__ ((packed)); - - -/* - * DASD-IOCTLs (copied from dasd.h) - */ -/* Issue a reserve/release command, rsp. */ -#define BIODASDRSRV _IO (DASD_IOCTL_LETTER,2) /* reserve */ -#define BIODASDRLSE _IO (DASD_IOCTL_LETTER,3) /* release */ -#define BIODASDSLCK _IO (DASD_IOCTL_LETTER,4) /* steal lock */ -/* reset profiling information of a device */ -#define BIODASDPRRST _IO (DASD_IOCTL_LETTER,5) - -/* retrieve profiling information of a device */ -#define BIODASDPRRD _IOR (DASD_IOCTL_LETTER,2,dasd_profile_info_t) -/* Get Attributes (cache operations) */ -#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t) - -/* Set Attributes (cache operations) */ -#define BIODASDSATTR _IOW (DASD_IOCTL_LETTER,2,attrib_data_t) - -/* Get Sense Path Group ID (SNID) data */ -#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data) - - /* id definition for profile items */ enum prof_id { prof_reqs = 0, @@ -241,48 +157,33 @@ check_prof_item (char* prof_item) * 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl' * the number of cylinders to be cached. */ -int -disk_get_cache (char* device) +int disk_get_cache(char *device) { - int fd; attrib_data_t attrib_data; - - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } + int rc; - /* Get the given caching attributes */ - if (ioctl (fd, BIODASDGATTR, &attrib_data)) { - error_print ("Could not get cache attributes for device <%s>", - device); - close (fd); - return -1; - } + rc = dasd_get_cache(device, &attrib_data); + if (rc) + return rc; printf ("%s (%i cyl)\n", get_cache_name(attrib_data.operation), attrib_data.nr_cyl); - close (fd); return 0; } - /* * Set the caching algorithm used for the channel programs of this device. * 'cache' is the caching mode (see ESS docu for more info) and 'no_cyl' * the number of cylinders to be cached. */ -int -disk_set_cache (char* device, char* cache, char* no_cyl) +int disk_set_cache(char *device, char *cache, char *no_cyl) { - int fd; attrib_data_t attrib_data; - - /* get caching mode and # cylinders */ + int rc; + + /* get caching mode and # cylinders */ attrib_data.operation = check_cache (cache); attrib_data.nr_cyl = check_no_cyl (no_cyl); @@ -292,52 +193,34 @@ disk_set_cache (char* device, char* cache, char* no_cyl) attrib_data.nr_cyl); } - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } - /* Set the given caching attributes */ printf ("Setting cache mode for device <%s>...\n", device); - if (ioctl (fd, BIODASDSATTR, &attrib_data)) { - error_print ("Could not set caching for device <%s>", device); - close (fd); + rc = dasd_set_cache(device, &attrib_data); + if (rc) { + error_print("Could not set caching for device <%s>", device); return -1; } - printf ("Done.\n"); - close (fd); + return 0; } - /* * Reserve the device. */ -int -disk_reserve (char* device) +int disk_reserve(char *device) { - int fd; - - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } + int rc; /* Reserve device */ printf ("Reserving device <%s>...\n", device); - if (ioctl (fd, BIODASDRSRV)) { - error_print ("Could not reserve device <%s>", device); - close (fd); + rc = dasd_disk_reserve(device); + if (rc) { + error_print("Could not reserve device <%s>", device); return -1; } - printf ("Done.\n"); - close (fd); + printf("Done.\n"); return 0; } @@ -345,28 +228,18 @@ disk_reserve (char* device) /* * Release the device. */ -int -disk_release (char* device) +int disk_release(char *device) { - int fd; - - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } + int rc; - /* Release device */ printf ("Releasing device <%s>...\n", device); - if (ioctl (fd, BIODASDRLSE)) { - error_print ("Could not release device <%s>", device); - close (fd); + rc = dasd_disk_release(device); + if (rc) { + error_print("Could not release device <%s>", device); return -1; } - printf ("Done.\n"); - close (fd); + printf("Done.\n"); return 0; } @@ -376,29 +249,19 @@ disk_release (char* device) * This means to reserve the device even if it was already reserved. * The current reserve is broken (steal lock). */ -int -disk_slock (char* device) +int disk_slock(char *device) { - int fd; - - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } + int rc; /* Unconditional reserve device */ printf ("Unconditional reserving device <%s>...\n", device); - if (ioctl (fd, BIODASDSLCK)) { - error_print ("Could not unconditional reserve device <%s>", - device); - close (fd); + rc = dasd_slock(device); + if (rc) { + error_print("Could not unconditional reserve device <%s>", device); return -1; } - printf ("Done.\n"); - close (fd); + return 0; } @@ -407,27 +270,16 @@ disk_slock (char* device) * Uses the Sense Path Group ID (SNID) ioctl to find out if * a device is reserved to it's path group. */ -int -disk_query_reserve_status(char* device) +int disk_query_reserve_status(char *device) { - int fd; - struct dasd_snid_ioctl_data snid; + int rc; - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); + rc = dasd_query_reserve(device); + if (rc < 0) { + error_print("Could not read reserve status for device <%s>", device); return -1; } - snid.path_mask = 0; - /* Release device */ - if (ioctl(fd, BIODASDSNID, &snid)) { - error_print("Could not read reserve status" - " for device <%s>", device); - close (fd); - return -1; - } - switch (snid.data.path_state.reserve) { + switch (rc) { case 0: printf("none\n"); break; @@ -441,7 +293,7 @@ disk_query_reserve_status(char* device) printf("reserved\n"); break; } - close (fd); + return 0; } @@ -615,21 +467,14 @@ static int disk_profile_item(dasd_profile_info_t dasd_profile_info, /* * Get and print the profiling info of the device. */ -int -disk_profile (char* device, char* prof_item) +int disk_profile(char *device, char *prof_item) { - int fd, rc; dasd_profile_info_t dasd_profile_info; - - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } + int rc; /* Get the profile info */ - if (ioctl (fd, BIODASDPRRD, &dasd_profile_info)) { + rc = dasd_profile(device, &dasd_profile_info); + if (rc) { switch (errno) { case EIO: /* profiling is not active */ error_print ("Profiling (on device <%s>) is not " @@ -639,7 +484,6 @@ disk_profile (char* device, char* prof_item) error_print ("Could not get profile info for device " "<%s>.", device); } - close (fd); return -1; } /* Check for profile item or summary */ @@ -648,38 +492,26 @@ disk_profile (char* device, char* prof_item) } else { rc = disk_profile_item (dasd_profile_info, prof_item); } - - close (fd); + return rc; } - /* * Reset the profiling counters of the device. */ -int -disk_reset_prof (char* device) +int disk_reset_prof(char *device) { - int fd; - - /* Open device file */ - fd = open (device, O_RDONLY); - if (fd == -1) { - error_print ("<%s> - %s", device, strerror (errno)); - return -1; - } + int rc; /* reset profile info */ printf ("Resetting profile info for device <%s>...\n", device); - if (ioctl (fd, BIODASDPRRST)) { - error_print ("Could not reset profile info for device <%s>", - device); - close (fd); + rc = dasd_reset_profile(device); + if (rc) { + error_print("Could not reset profile info for device <%s>", device); return -1; } - printf ("Done.\n"); - close (fd); + return 0; } -- 2.38.1 From 3aa7f6e29871c06537ab95bf2a14b5eb3ca6e847 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 27 Oct 2022 15:51:00 +0200 Subject: [PATCH 6/7] libdasd: fix ioctl macro to return also positive return codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of an error the ioctl macro only returns errno to the calling function. This misses positive returncodes from ioctls. Change the macro to also return positive return codes. Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Jan Höppner --- libdasd/dasd_ioctl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libdasd/dasd_ioctl.c b/libdasd/dasd_ioctl.c index 40e726c..3a36375 100644 --- a/libdasd/dasd_ioctl.c +++ b/libdasd/dasd_ioctl.c @@ -28,11 +28,13 @@ #define RUN_IOCTL(fd, req, argp) \ do { \ - if (ioctl(fd, req, argp) != 0) { \ - int err = errno; \ - if (err != EBADF) \ + int rc = ioctl(fd, req, argp); \ + if (rc != 0) { \ + if (rc == -1) \ + rc = errno; \ + if (rc != EBADF) \ dasd_close_device(fd); \ - return err; \ + return rc; \ } \ } while (0) -- 2.38.1 From 3f12bdf4c728caeaeaa64158efb26f917d905b08 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 11 Nov 2022 13:17:32 +0100 Subject: [PATCH 7/7] tunedasd: add copy_pair swap capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an option to tunedasd to trigger a copy pair swap using the appropriate ioctl for DASD devices. -s, --copy-pair-swap COPY_PAIR This command requires a comma separated pair of primary,secondary to be specified. In case of success the old secondary will become the new primary device and the old primary will become a secondary device. Example: tunedasd /dev/dasda -s 0.0.9700,0.0.9740 This will set the old secondary device 0.0.9740 as the new primary. The old primary device 0.0.9700 will automatically become a secondary device. Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Jan Höppner --- include/lib/dasd_base.h | 14 ++++++++-- libdasd/dasd_ioctl.c | 28 ++++++++++++++++++++ tunedasd/include/disk.h | 1 + tunedasd/man/tunedasd.8 | 14 ++++++++++ tunedasd/src/disk.c | 50 ++++++++++++++++++++++++++++++++++-- tunedasd/src/tunedasd.c | 57 +++++++++++++++++++++++++---------------- 6 files changed, 138 insertions(+), 26 deletions(-) diff --git a/include/lib/dasd_base.h b/include/lib/dasd_base.h index 11ec94b..400e374 100644 --- a/include/lib/dasd_base.h +++ b/include/lib/dasd_base.h @@ -20,8 +20,8 @@ #include #include -/* A bus id of a DASD is 8 characters long. E.g. 0.0.4711 */ -#define DASD_BUS_ID_SIZE 9 +/* the definition of a BUSID in the DASD driver is 20 */ +#define DASD_BUS_ID_SIZE 20 typedef struct dasd_information2_t { unsigned int devno; /* S/390 devno */ @@ -242,6 +242,13 @@ struct dasd_snid_ioctl_data { __u8 path_mask; } __attribute__((packed)); +struct dasd_copypair_swap_data { + char primary[DASD_BUS_ID_SIZE]; /* BUSID of primary */ + char secondary[DASD_BUS_ID_SIZE]; /* BUSID of secondary */ + /* Reserved for future updates. */ + char reserved[64]; +}; + #ifndef __linux__ /* definition from hdreg.h */ struct hd_geometry { @@ -278,6 +285,8 @@ struct hd_geometry { #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER, 2, attrib_data_t) /* Release Allocated Space */ #define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t) +/* Swap copy pair */ +#define BIODASDPPRCSWAP _IOW(DASD_IOCTL_LETTER, 4, struct dasd_copypair_swap_data) /* Get Sense Path Group ID (SNID) data */ #define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data) /* Check device format according to format_data_t */ @@ -318,5 +327,6 @@ int dasd_set_cache(const char *device, attrib_data_t *attrib_data); int dasd_query_reserve(const char *device); int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info); int dasd_reset_profile(const char *device); +int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data); #endif /* LIB_DASD_BASE_H */ diff --git a/libdasd/dasd_ioctl.c b/libdasd/dasd_ioctl.c index 3a36375..f684761 100644 --- a/libdasd/dasd_ioctl.c +++ b/libdasd/dasd_ioctl.c @@ -452,3 +452,31 @@ int dasd_reset_profile(const char *device) return 0; } + +/* + * Initiate the swap of a copy pairs primary,secondary relation. + * The old secondary will become the new primary and vice versa. + * + * @param[in] device node device node's name + * @param[in] copy_pair data pointer to dasd copypair data with: + * 'primary' old primary, becoming secondary + * 'secondary' old secondary, becoming primary. + * + * @retval errno in case of failure + * @retval 0 in case of success + * @retval 1 swap data invalid + * @retval 2 no active device found + * @retval 3 wrong primary specified + * @retval 4 secondary device not found + * @retval 5 swap already running + */ +int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data) +{ + int fd; + + fd = dasd_open_device(device, O_RDONLY); + RUN_IOCTL(fd, BIODASDPPRCSWAP, data); + dasd_close_device(fd); + + return 0; +} diff --git a/tunedasd/include/disk.h b/tunedasd/include/disk.h index ea35f6f..55a32d0 100644 --- a/tunedasd/include/disk.h +++ b/tunedasd/include/disk.h @@ -31,6 +31,7 @@ int disk_query_reserve_status(char* device); int disk_profile (char* device, char* prof_item); int disk_reset_prof(char *device); int disk_reset_chpid(char *device, char *chpid); +int disk_copy_swap(char *device, char *copy_pair); #endif /* not DISK_H */ diff --git a/tunedasd/man/tunedasd.8 b/tunedasd/man/tunedasd.8 index 94c3608..ae41b97 100644 --- a/tunedasd/man/tunedasd.8 +++ b/tunedasd/man/tunedasd.8 @@ -174,6 +174,14 @@ Reset all channel paths of the selected device. The channel paths might be suspended due to high IFCC error rates or a High Performance FICON failure. Use this option to resume considering all defined channel paths for I/O. +.TP +.BR "\-s" " or " "\-\-copy\-pair\-swap " +Swap the copy roles of the specified copy pair. The has to +be a comma separated pair of \fBPRIMARY,SECONDARY\fR where +\fBPRIMARY\fR is the old primary device that will become a secondary +automatically. The old \fBSECONDARY\fR device will become the new +primary device. Both devices have to be online for this operation to +succeed. .\" .\".TP .\".BR "\-o" " or " "\-\-online" @@ -197,6 +205,12 @@ channel paths for I/O. .br tunedasd -p 45 /dev/dasdc + +.br +4. Scenario: Swap copy pair 0.0.9700 and 0.0.9740 +.br + + tunedasd -s 0.0.9700,0.0.9740 /dev/dasdc .br .SH "SEE ALSO" .BR dasdview (8), diff --git a/tunedasd/src/disk.c b/tunedasd/src/disk.c index 1e8de16..490c1c5 100644 --- a/tunedasd/src/disk.c +++ b/tunedasd/src/disk.c @@ -21,12 +21,11 @@ #include "lib/dasd_base.h" #include "lib/dasd_sys.h" +#include "lib/util_libc.h" #include "disk.h" #include "tunedasd.h" -#define BUS_ID_SIZE 30 - /* id definition for profile items */ enum prof_id { prof_reqs = 0, @@ -549,3 +548,50 @@ int disk_reset_chpid(char *device, char *chpid) return -1; } + +int disk_copy_swap(char *device, char *copy_pair) +{ + struct dasd_copypair_swap_data data = { 0 }; + char *primary, *secondary; + int rc = 0; + + primary = strtok(copy_pair, ","); + secondary = strtok(NULL, ","); + + if (!primary || !secondary) { + error_print("%s: Error parsing Copy Pair %s", device, copy_pair); + return -1; + } + + util_strlcpy(data.primary, primary, DASD_BUS_ID_SIZE); + util_strlcpy(data.secondary, secondary, DASD_BUS_ID_SIZE); + + printf("Swapping copy pair %s %s on device <%s>...\n", primary, secondary, device); + rc = dasd_copy_swap(device, &data); + + switch (rc) { + case 0: + printf("Done.\n"); + return 0; + case 1: + error_print("Swap data invalid"); + break; + case 2: + error_print("No active device found"); + break; + case 3: + error_print("Wrong primary device specified"); + break; + case 4: + error_print("Secondary device not found"); + break; + case 5: + error_print("Swap already running"); + break; + default: + error_print("Swap not successful rc %d", rc); + break; + } + + return -1; +} diff --git a/tunedasd/src/tunedasd.c b/tunedasd/src/tunedasd.c index 3c14eb8..691841c 100644 --- a/tunedasd/src/tunedasd.c +++ b/tunedasd/src/tunedasd.c @@ -119,12 +119,17 @@ static struct util_opt opt_vec[] = { .desc = "Reset all channel paths of a device", .flags = UTIL_OPT_FLAG_NOSHORT, }, + { + .option = { "copy-pair-swap", required_argument, NULL, 's' }, + .argument = "COPY_PAIR", + .desc = "Swap a specified, comma separated copy pair.", + }, UTIL_OPT_HELP, UTIL_OPT_VERSION, UTIL_OPT_END }; -#define CMD_KEYWORD_NUM 16 +#define CMD_KEYWORD_NUM 17 #define DEVICES_NUM 256 enum cmd_keyword_id { @@ -144,6 +149,7 @@ enum cmd_keyword_id { cmd_keyword_path_all, cmd_keyword_enable_stats, cmd_keyword_disable_stats, + cmd_keyword_copy_swap, }; @@ -167,7 +173,8 @@ static const struct { { "path_reset", cmd_keyword_path }, { "path_reset_all", cmd_keyword_path_all }, { "enable-stats", cmd_keyword_enable_stats }, - { "disable-stats", cmd_keyword_disable_stats } + { "disable-stats", cmd_keyword_disable_stats }, + { "copy-swap", cmd_keyword_copy_swap }, }; @@ -180,26 +187,27 @@ enum cmd_key_state { /* Determines which combination of keywords are valid */ static enum cmd_key_state cmd_key_table[CMD_KEYWORD_NUM][CMD_KEYWORD_NUM] = { - /* help vers get_ cach no_c rese rele sloc prof prof rese quer path path - * ion cach e yl rve ase k ile _ite t_pr y_re _all - * e m of serv + /* help vers get_ cach no_c rese rele sloc prof prof rese quer path path enab disa copy + * ion cach e yl rve ase k ile _ite t_pr y_re _all le-s ble- -swa + * e m of serv tats stat p */ - /* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv }, - /* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, - /* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, - /* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, - /* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, - /* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, - /* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv }, - /* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv }, - /* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv }, - /* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv }, - /* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv }, - /* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv }, - /* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv }, - /* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv }, - /* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv }, - /* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req }, + /* help */ { req, opt, opt, opt, opt, opt, opt, opt, opt, opt, opt, inv, inv, inv, inv, inv, inv }, + /* version */ { inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* get_cache */ { opt, opt, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* cache */ { opt, opt, inv, req, opt, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* no_cyl */ { opt, opt, inv, req, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* reserve */ { opt, opt, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* release */ { opt, opt, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* slock */ { opt, opt, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv, inv, inv, inv }, + /* profile */ { opt, opt, inv, inv, inv, inv, inv, inv, req, opt, inv, inv, inv, inv, inv, inv, inv }, + /* prof_item */ { opt, opt, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv, inv, inv }, + /* reset_prof */ { opt, opt, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv, inv }, + /* query_reserve */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv, inv }, + /* path */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv, inv }, + /* path_all */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv, inv }, + /* enable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv }, + /* disable-stats */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv }, + /* copy-swap */ { inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req }, }; struct parameter { @@ -439,7 +447,9 @@ static int get_command_line(int argc, char *argv[], struct command_line *line) rc = store_option (&cmdline, cmd_keyword_query_reserve, optarg); break; - + case 's': + rc = store_option(&cmdline, cmd_keyword_copy_swap, optarg); + break; case -1: /* End of options string - start of devices list */ cmdline.device_id = optind; @@ -508,6 +518,9 @@ static int do_command(char *device, struct command_line cmdline) case cmd_keyword_path_all: rc = disk_reset_chpid(device, NULL); break; + case cmd_keyword_copy_swap: + rc = disk_copy_swap(device, cmdline.parm[cmd_keyword_copy_swap].data); + break; default: error_print ("Unknown command '%s' specified", get_keyword_name (i)); -- 2.38.1