aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r--drivers/s390/block/dasd_eckd.c69
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: