diff options
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 50cf96389d2..bf61274af3b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2802,6 +2802,73 @@ dasd_eckd_steal_lock(struct dasd_device *device) } /* + * SNID - Sense Path Group ID + * This ioctl may be used in situations where I/O is stalled due to + * a reserve, so if the normal dasd_smalloc_request fails, we use the + * preallocated dasd_reserve_req. + */ +static int dasd_eckd_snid(struct dasd_device *device, + void __user *argp) +{ + struct dasd_ccw_req *cqr; + int rc; + struct ccw1 *ccw; + int useglobal; + struct dasd_snid_ioctl_data usrparm; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (copy_from_user(&usrparm, argp, sizeof(usrparm))) + return -EFAULT; + + useglobal = 0; + cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, + sizeof(struct dasd_snid_data), device); + if (IS_ERR(cqr)) { + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; + } + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_SNID; + ccw->flags |= CCW_FLAG_SLI; + ccw->count = 12; + ccw->cda = (__u32)(addr_t) cqr->data; + cqr->startdev = device; + cqr->memdev = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); + cqr->retries = 5; + cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + cqr->lpm = usrparm.path_mask; + + rc = dasd_sleep_on_immediatly(cqr); + /* verify that I/O processing didn't modify the path mask */ + if (!rc && usrparm.path_mask && (cqr->lpm != usrparm.path_mask)) + rc = -EIO; + if (!rc) { + usrparm.data = *((struct dasd_snid_data *)cqr->data); + if (copy_to_user(argp, &usrparm, sizeof(usrparm))) + rc = -EFAULT; + } + + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); + return rc; +} + +/* * Read performance statistics */ static int @@ -3036,6 +3103,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) return dasd_eckd_reserve(device); case BIODASDSLCK: return dasd_eckd_steal_lock(device); + case BIODASDSNID: + return dasd_eckd_snid(device, argp); case BIODASDSYMMIO: return dasd_symm_io(device, argp); default: |