mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
s390/dasd: Add new ioctl BIODASDCHECKFMT
Implement new DASD IOCTL BIODASDCHECKFMT to check a range of tracks on a DASD volume for correct formatting. The following characteristics are checked: - Block size - ECKD key length - ECKD record ID - Number of records per track Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
committed by
Martin Schwidefsky
parent
3fa7ee8844
commit
8fd575200d
@@ -187,6 +187,36 @@ typedef struct format_data_t {
|
||||
#define DASD_FMT_INT_INVAL 4 /* invalidate tracks */
|
||||
#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
|
||||
|
||||
/*
|
||||
* struct format_check_t
|
||||
* represents all data necessary to evaluate the format of
|
||||
* different tracks of a dasd
|
||||
*/
|
||||
typedef struct format_check_t {
|
||||
/* Input */
|
||||
struct format_data_t expect;
|
||||
|
||||
/* Output */
|
||||
unsigned int result; /* Error indication (DASD_FMT_ERR_*) */
|
||||
unsigned int unit; /* Track that is in error */
|
||||
unsigned int rec; /* Record that is in error */
|
||||
unsigned int num_records; /* Records in the track in error */
|
||||
unsigned int blksize; /* Blocksize of first record in error */
|
||||
unsigned int key_length; /* Key length of first record in error */
|
||||
} format_check_t;
|
||||
|
||||
/* Values returned in format_check_t when a format error is detected: */
|
||||
/* Too few records were found on a single track */
|
||||
#define DASD_FMT_ERR_TOO_FEW_RECORDS 1
|
||||
/* Too many records were found on a single track */
|
||||
#define DASD_FMT_ERR_TOO_MANY_RECORDS 2
|
||||
/* Blocksize/data-length of a record was wrong */
|
||||
#define DASD_FMT_ERR_BLKSIZE 3
|
||||
/* A record ID is defined by cylinder, head, and record number (CHR). */
|
||||
/* On mismatch, this error is set */
|
||||
#define DASD_FMT_ERR_RECORD_ID 4
|
||||
/* If key-length was != 0 */
|
||||
#define DASD_FMT_ERR_KEY_LENGTH 5
|
||||
|
||||
/*
|
||||
* struct attrib_data_t
|
||||
@@ -288,6 +318,8 @@ struct dasd_snid_ioctl_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_check_t */
|
||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
|
||||
|
||||
#define BIODASDSYMMIO _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)
|
||||
|
||||
|
||||
@@ -1638,6 +1638,9 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
||||
struct dasd_ccw_req *cqr, *next;
|
||||
struct dasd_device *device;
|
||||
unsigned long long now;
|
||||
int nrf_suppressed = 0;
|
||||
int fp_suppressed = 0;
|
||||
u8 *sense = NULL;
|
||||
int expires;
|
||||
|
||||
if (IS_ERR(irb)) {
|
||||
@@ -1673,7 +1676,23 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
||||
dasd_put_device(device);
|
||||
return;
|
||||
}
|
||||
device->discipline->dump_sense_dbf(device, irb, "int");
|
||||
|
||||
/*
|
||||
* In some cases 'File Protected' or 'No Record Found' errors
|
||||
* might be expected and debug log messages for the
|
||||
* corresponding interrupts shouldn't be written then.
|
||||
* Check if either of the according suppress bits is set.
|
||||
*/
|
||||
sense = dasd_get_sense(irb);
|
||||
if (sense) {
|
||||
fp_suppressed = (sense[1] & SNS1_FILE_PROTECTED) &&
|
||||
test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
|
||||
nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) &&
|
||||
test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
|
||||
}
|
||||
if (!(fp_suppressed || nrf_suppressed))
|
||||
device->discipline->dump_sense_dbf(device, irb, "int");
|
||||
|
||||
if (device->features & DASD_FEATURE_ERPLOG)
|
||||
device->discipline->dump_sense(device, cqr, irb);
|
||||
device->discipline->check_for_device_change(device, cqr, irb);
|
||||
@@ -2312,6 +2331,7 @@ static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
struct dasd_ccw_req *cqr, *n;
|
||||
u8 *sense = NULL;
|
||||
int rc;
|
||||
|
||||
retry:
|
||||
@@ -2357,6 +2377,20 @@ retry:
|
||||
|
||||
rc = 0;
|
||||
list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
|
||||
/*
|
||||
* In some cases the 'File Protected' or 'Incorrect Length'
|
||||
* error might be expected and error recovery would be
|
||||
* unnecessary in these cases. Check if the according suppress
|
||||
* bit is set.
|
||||
*/
|
||||
sense = dasd_get_sense(&cqr->irb);
|
||||
if (sense && sense[1] & SNS1_FILE_PROTECTED &&
|
||||
test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags))
|
||||
continue;
|
||||
if (scsw_cstat(&cqr->irb.scsw) == 0x40 &&
|
||||
test_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* for alias devices simplify error recovery and
|
||||
* return to upper layer
|
||||
|
||||
@@ -1367,8 +1367,14 @@ dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
|
||||
|
||||
struct dasd_device *device = default_erp->startdev;
|
||||
|
||||
dev_err(&device->cdev->dev,
|
||||
"The specified record was not found\n");
|
||||
/*
|
||||
* In some cases the 'No Record Found' error might be expected and
|
||||
* log messages shouldn't be written then.
|
||||
* Check if the according suppress bit is set.
|
||||
*/
|
||||
if (!test_bit(DASD_CQR_SUPPRESS_NRF, &default_erp->flags))
|
||||
dev_err(&device->cdev->dev,
|
||||
"The specified record was not found\n");
|
||||
|
||||
return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
|
||||
|
||||
@@ -1393,8 +1399,14 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
|
||||
|
||||
struct dasd_device *device = erp->startdev;
|
||||
|
||||
dev_err(&device->cdev->dev, "Accessing the DASD failed because of "
|
||||
"a hardware error\n");
|
||||
/*
|
||||
* In some cases the 'File Protected' error might be expected and
|
||||
* log messages shouldn't be written then.
|
||||
* Check if the according suppress bit is set.
|
||||
*/
|
||||
if (!test_bit(DASD_CQR_SUPPRESS_FP, &erp->flags))
|
||||
dev_err(&device->cdev->dev,
|
||||
"Accessing the DASD failed because of a hardware error\n");
|
||||
|
||||
return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
|
||||
|
||||
|
||||
+519
-16
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@
|
||||
#define DASD_ECKD_CCW_READ_MT 0x86
|
||||
#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d
|
||||
#define DASD_ECKD_CCW_READ_KD_MT 0x8e
|
||||
#define DASD_ECKD_CCW_READ_COUNT_MT 0x92
|
||||
#define DASD_ECKD_CCW_RELEASE 0x94
|
||||
#define DASD_ECKD_CCW_WRITE_FULL_TRACK 0x95
|
||||
#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
|
||||
|
||||
@@ -236,6 +236,13 @@ struct dasd_ccw_req {
|
||||
* stolen. Should not be combined with
|
||||
* DASD_CQR_FLAGS_USE_ERP
|
||||
*/
|
||||
/*
|
||||
* The following flags are used to suppress output of certain errors.
|
||||
* These flags should only be used for format checks!
|
||||
*/
|
||||
#define DASD_CQR_SUPPRESS_NRF 4 /* Suppress 'No Record Found' error */
|
||||
#define DASD_CQR_SUPPRESS_FP 5 /* Suppress 'File Protected' error*/
|
||||
#define DASD_CQR_SUPPRESS_IL 6 /* Suppress 'Incorrect Length' error */
|
||||
|
||||
/* Signature for error recovery functions. */
|
||||
typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
|
||||
@@ -318,7 +325,8 @@ struct dasd_discipline {
|
||||
* Device operation functions. build_cp creates a ccw chain for
|
||||
* a block device request, start_io starts the request and
|
||||
* term_IO cancels it (e.g. in case of a timeout). format_device
|
||||
* returns a ccw chain to be used to format the device.
|
||||
* formats the device and check_device_format compares the format of
|
||||
* a device with the expected format_data.
|
||||
* handle_terminated_request allows to examine a cqr and prepare
|
||||
* it for retry.
|
||||
*/
|
||||
@@ -329,7 +337,9 @@ struct dasd_discipline {
|
||||
int (*term_IO) (struct dasd_ccw_req *);
|
||||
void (*handle_terminated_request) (struct dasd_ccw_req *);
|
||||
int (*format_device) (struct dasd_device *,
|
||||
struct format_data_t *, int enable_pav);
|
||||
struct format_data_t *, int);
|
||||
int (*check_device_format)(struct dasd_device *,
|
||||
struct format_check_t *, int);
|
||||
int (*free_cp) (struct dasd_ccw_req *, struct request *);
|
||||
|
||||
/*
|
||||
|
||||
@@ -238,6 +238,23 @@ dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dasd_check_format(struct dasd_block *block,
|
||||
struct format_check_t *cdata)
|
||||
{
|
||||
struct dasd_device *base;
|
||||
int rc;
|
||||
|
||||
base = block->base;
|
||||
if (!base->discipline->check_device_format)
|
||||
return -ENOTTY;
|
||||
|
||||
rc = base->discipline->check_device_format(base, cdata, 1);
|
||||
if (rc == -EAGAIN)
|
||||
rc = base->discipline->check_device_format(base, cdata, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Format device.
|
||||
*/
|
||||
@@ -272,6 +289,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
||||
}
|
||||
rc = dasd_format(base->block, &fdata);
|
||||
dasd_put_device(base);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check device format
|
||||
*/
|
||||
static int dasd_ioctl_check_format(struct block_device *bdev, void __user *argp)
|
||||
{
|
||||
struct format_check_t cdata;
|
||||
struct dasd_device *base;
|
||||
int rc = 0;
|
||||
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
|
||||
base = dasd_device_from_gendisk(bdev->bd_disk);
|
||||
if (!base)
|
||||
return -ENODEV;
|
||||
if (bdev != bdev->bd_contains) {
|
||||
pr_warn("%s: The specified DASD is a partition and cannot be checked\n",
|
||||
dev_name(&base->cdev->dev));
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (copy_from_user(&cdata, argp, sizeof(cdata))) {
|
||||
rc = -EFAULT;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rc = dasd_check_format(base->block, &cdata);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
|
||||
if (copy_to_user(argp, &cdata, sizeof(cdata)))
|
||||
rc = -EFAULT;
|
||||
|
||||
out_err:
|
||||
dasd_put_device(base);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -519,6 +577,9 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
case BIODASDFMT:
|
||||
rc = dasd_ioctl_format(bdev, argp);
|
||||
break;
|
||||
case BIODASDCHECKFMT:
|
||||
rc = dasd_ioctl_check_format(bdev, argp);
|
||||
break;
|
||||
case BIODASDINFO:
|
||||
rc = dasd_ioctl_information(block, cmd, argp);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user