mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
This commit is based on the s390-tools-1.39.0 version. Changes on top of s390-tools-1.39.0: - Add MIT license to all source files - Add LICENSE file - Transform REAMDE to README.md (markdown) - Add AUTHORS.md file - Add CONTRIBUTING.md file - Move changelog from README to CHANGELOG.md file Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
720 lines
16 KiB
C
720 lines
16 KiB
C
/*
|
|
* tunedasd - Adjust tunable parameters on DASD devices
|
|
*
|
|
* Functions to handle DASD-IOCTLs
|
|
*
|
|
* Copyright IBM Corp. 2004, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include "lib/dasd_sys.h"
|
|
|
|
#include "disk.h"
|
|
#include "tunedasd.h"
|
|
|
|
#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,
|
|
prof_sects = 1,
|
|
prof_sizes = 2,
|
|
prof_total = 3,
|
|
prof_totsect = 4,
|
|
prof_start = 5,
|
|
prof_irq = 6,
|
|
prof_irqsect = 7,
|
|
prof_end = 8,
|
|
prof_queue = 9
|
|
};
|
|
|
|
/* Mapping for caching modes */
|
|
static struct {
|
|
char* mode;
|
|
int id;
|
|
} mode_list[] = {
|
|
{ "normal", DASD_NORMAL_CACHE },
|
|
{ "bypass", DASD_BYPASS_CACHE },
|
|
{ "inhibit", DASD_INHIBIT_LOAD },
|
|
{ "sequential", DASD_SEQ_ACCESS },
|
|
{ "prestage", DASD_SEQ_PRESTAGE },
|
|
{ "record", DASD_REC_ACCESS }
|
|
};
|
|
|
|
|
|
/*
|
|
* Check for valid cache parameters.
|
|
*/
|
|
int
|
|
check_cache (char* cache)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* Check for valid parameters */
|
|
for (i = 0; i < sizeof(mode_list)/sizeof(mode_list[0]); i++) {
|
|
if (!strcmp (cache, mode_list[i].mode)) {
|
|
return mode_list[i].id;
|
|
}
|
|
}
|
|
error_print ("Invalid caching mode '%s' given", cache);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Retrieve name of cache mode identified by number.
|
|
*/
|
|
static char *get_cache_name(int id)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < sizeof (mode_list) / sizeof (mode_list[0]);
|
|
i++) {
|
|
if (id == mode_list[i].id) {
|
|
return mode_list[i].mode;
|
|
}
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
|
|
/*
|
|
* Check for valid number of cylinders.
|
|
*/
|
|
int
|
|
check_no_cyl (char* no_cyl)
|
|
{
|
|
int nr_cyl;
|
|
char* err_ptr;
|
|
if (!no_cyl) {
|
|
/* set default = 2 Cylinders - if option is missing */
|
|
return 2;
|
|
} else {
|
|
err_ptr = NULL;
|
|
nr_cyl = strtoul (no_cyl, &err_ptr, 0);
|
|
|
|
if ((errno) ||
|
|
(*err_ptr != '\0')) {
|
|
error_print ("Invalid number of cylinders given '%s'",
|
|
no_cyl);
|
|
return -1;
|
|
}
|
|
}
|
|
return nr_cyl;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check for valid profile item parameters.
|
|
*/
|
|
int
|
|
check_prof_item (char* prof_item)
|
|
{
|
|
/* Mapping for profile items */
|
|
static struct {
|
|
char* item;
|
|
int id;
|
|
} prof_list[] = {
|
|
{ "reqs", prof_reqs },
|
|
{ "sects", prof_sects },
|
|
{ "sizes", prof_sizes },
|
|
{ "total", prof_total },
|
|
{ "totsect", prof_totsect },
|
|
{ "start", prof_start },
|
|
{ "irq", prof_irq },
|
|
{ "irqsect", prof_irqsect },
|
|
{ "end", prof_end },
|
|
{ "queue", prof_queue }
|
|
};
|
|
|
|
unsigned int i;
|
|
|
|
/* Check for valid parameters */
|
|
for (i = 0; i < sizeof(prof_list)/sizeof(prof_list[0]); i++) {
|
|
if (!strcmp (prof_item, prof_list[i].item)) {
|
|
return prof_list[i].id;
|
|
}
|
|
}
|
|
error_print ("Invalid profile item '%s' given", prof_item);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get 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_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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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 fd;
|
|
attrib_data_t attrib_data;
|
|
|
|
/* get caching mode and # cylinders */
|
|
attrib_data.operation = check_cache (cache);
|
|
attrib_data.nr_cyl = check_no_cyl (no_cyl);
|
|
|
|
if (attrib_data.nr_cyl > 40) {
|
|
printf ("WARNING: This is a very large number of "
|
|
"cylinders ;) %i\n",
|
|
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);
|
|
return -1;
|
|
}
|
|
|
|
printf ("Done.\n");
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Reserve the 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;
|
|
}
|
|
|
|
/* Reserve device */
|
|
printf ("Reserving device <%s>...\n", device);
|
|
if (ioctl (fd, BIODASDRSRV)) {
|
|
error_print ("Could not reserve device <%s>", device);
|
|
close (fd);
|
|
return -1;
|
|
}
|
|
|
|
printf ("Done.\n");
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Release the 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;
|
|
}
|
|
|
|
/* Release device */
|
|
printf ("Releasing device <%s>...\n", device);
|
|
if (ioctl (fd, BIODASDRLSE)) {
|
|
error_print ("Could not release device <%s>", device);
|
|
close (fd);
|
|
return -1;
|
|
}
|
|
|
|
printf ("Done.\n");
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Unconditional reserve the 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 fd;
|
|
|
|
/* Open device file */
|
|
fd = open (device, O_RDONLY);
|
|
if (fd == -1) {
|
|
error_print ("<%s> - %s", device, strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
/* 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);
|
|
return -1;
|
|
}
|
|
|
|
printf ("Done.\n");
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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 fd;
|
|
struct dasd_snid_ioctl_data snid;
|
|
|
|
/* Open device file */
|
|
fd = open (device, O_RDONLY);
|
|
if (fd == -1) {
|
|
error_print ("<%s> - %s", device, strerror (errno));
|
|
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) {
|
|
case 0:
|
|
printf("none\n");
|
|
break;
|
|
case 1:
|
|
printf("implicit\n");
|
|
break;
|
|
case 2:
|
|
printf("other\n");
|
|
break;
|
|
case 3:
|
|
printf("reserved\n");
|
|
break;
|
|
}
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
static int disk_profile_summary(dasd_profile_info_t dasd_profile_info)
|
|
{
|
|
int factor, i;
|
|
|
|
/* prevent counter 'overflow' on output */
|
|
for (factor = 1; (dasd_profile_info.dasd_io_reqs / factor) > 9999999;
|
|
factor *= 10) ;
|
|
/* print the profile info */
|
|
printf("\n%d dasd I/O requests\n", dasd_profile_info.dasd_io_reqs);
|
|
printf("with %u sectors(512B each)\n",
|
|
dasd_profile_info.dasd_io_sects);
|
|
printf("Scale factor is %d \n\n", factor);
|
|
|
|
printf(" __<4 ___8 __16 __32 __64 "
|
|
" _128 _256 _512 __1k __2k "
|
|
" __4k __8k _16k _32k _64k "
|
|
" 128k\n");
|
|
|
|
printf(" _256 _512 __1M __2M __4M "
|
|
" __8M _16M _32M _64M 128M "
|
|
" 256M 512M __1G __2G __4G "
|
|
" _>4G\n");
|
|
|
|
printf("Histogram of sizes (512B secs)\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_secs[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_secs[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Histogram of I/O times (microseconds)\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_times[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_times[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Histogram of I/O times per sector\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_timps[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_timps[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Histogram of I/O time till ssch\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time1[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time1[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Histogram of I/O time between ssch and irq\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time2[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time2[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Histogram of I/O time between ssch and irq per "
|
|
"sector\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time2ps[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time2ps[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("Histogram of I/O time between irq and end\n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time3[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_time3[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
printf("# of req in chanq at enqueuing (1..32) \n");
|
|
for (i = 0; i < 16; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_nr_req[i] / factor);
|
|
}
|
|
printf("\n");
|
|
for (; i < 32; i++) {
|
|
printf("%7d ", dasd_profile_info.dasd_io_nr_req[i] / factor);
|
|
}
|
|
printf("\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int disk_profile_item(dasd_profile_info_t dasd_profile_info,
|
|
char *prof_item)
|
|
{
|
|
int i;
|
|
|
|
/* Check for given profile item*/
|
|
switch (check_prof_item (prof_item)) {
|
|
case prof_reqs:
|
|
printf ("%d", dasd_profile_info.dasd_io_reqs);
|
|
break;
|
|
case prof_sects:
|
|
printf ("%d", dasd_profile_info.dasd_io_sects);
|
|
break;
|
|
case prof_sizes:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_secs[i]);
|
|
}
|
|
break;
|
|
case prof_total:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_times[i]);
|
|
}
|
|
break;
|
|
case prof_totsect:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_timps[i]);
|
|
}
|
|
break;
|
|
case prof_start:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_time1[i]);
|
|
}
|
|
break;
|
|
case prof_irq:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_time2[i]);
|
|
}
|
|
break;
|
|
case prof_irqsect:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_time2ps[i]);
|
|
}
|
|
break;
|
|
case prof_end:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_time3[i]);
|
|
}
|
|
break;
|
|
case prof_queue:
|
|
for (i = 0; i < 32; i++) {
|
|
printf ("%10d|", dasd_profile_info.dasd_io_nr_req[i]);
|
|
}
|
|
break;
|
|
}
|
|
|
|
printf ("\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get and print the profiling info of the device.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/* Get the profile info */
|
|
if (ioctl (fd, BIODASDPRRD, &dasd_profile_info)) {
|
|
switch (errno) {
|
|
case EIO: /* profiling is not active */
|
|
error_print ("Profiling (on device <%s>) is not "
|
|
"active.", device);
|
|
break;
|
|
default: /* all other errors */
|
|
error_print ("Could not get profile info for device "
|
|
"<%s>.", device);
|
|
}
|
|
close (fd);
|
|
return -1;
|
|
}
|
|
/* Check for profile item or summary */
|
|
if (!prof_item) {
|
|
rc = disk_profile_summary (dasd_profile_info);
|
|
} 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 fd;
|
|
|
|
/* Open device file */
|
|
fd = open (device, O_RDONLY);
|
|
if (fd == -1) {
|
|
error_print ("<%s> - %s", device, strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
/* 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);
|
|
return -1;
|
|
}
|
|
|
|
printf ("Done.\n");
|
|
close (fd);
|
|
return 0;
|
|
}
|
|
|
|
int disk_reset_chpid(char *device, char *chpid)
|
|
{
|
|
int rc;
|
|
|
|
if (chpid)
|
|
printf("Resetting chpid %s for device <%s>...\n", chpid,
|
|
device);
|
|
else
|
|
printf("Resetting all chpids for device <%s>...\n", device);
|
|
|
|
rc = dasd_reset_chpid(device, chpid);
|
|
switch (rc) {
|
|
case 0:
|
|
printf("Done.\n");
|
|
return 0;
|
|
case ENODEV:
|
|
error_print("%s: %s", device, strerror(errno));
|
|
break;
|
|
case EINVAL:
|
|
error_print("%s: Could not reset chpid %s: Invalid CHPID",
|
|
device, chpid);
|
|
break;
|
|
case ENOENT:
|
|
error_print("%s: Could not reset chpid %s: CHPID not defined for device",
|
|
device, chpid);
|
|
break;
|
|
default:
|
|
error_print("%s: Could not reset chpid %s",
|
|
device, chpid);
|
|
break;
|
|
}
|
|
|
|
return -1;
|
|
}
|