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 50cf96389d2c..bf61274af3bb 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) | |||
2802 | } | 2802 | } |
2803 | 2803 | ||
2804 | /* | 2804 | /* |
2805 | * SNID - Sense Path Group ID | ||
2806 | * This ioctl may be used in situations where I/O is stalled due to | ||
2807 | * a reserve, so if the normal dasd_smalloc_request fails, we use the | ||
2808 | * preallocated dasd_reserve_req. | ||
2809 | */ | ||
2810 | static int dasd_eckd_snid(struct dasd_device *device, | ||
2811 | void __user *argp) | ||
2812 | { | ||
2813 | struct dasd_ccw_req *cqr; | ||
2814 | int rc; | ||
2815 | struct ccw1 *ccw; | ||
2816 | int useglobal; | ||
2817 | struct dasd_snid_ioctl_data usrparm; | ||
2818 | |||
2819 | if (!capable(CAP_SYS_ADMIN)) | ||
2820 | return -EACCES; | ||
2821 | |||
2822 | if (copy_from_user(&usrparm, argp, sizeof(usrparm))) | ||
2823 | return -EFAULT; | ||
2824 | |||
2825 | useglobal = 0; | ||
2826 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, | ||
2827 | sizeof(struct dasd_snid_data), device); | ||
2828 | if (IS_ERR(cqr)) { | ||
2829 | mutex_lock(&dasd_reserve_mutex); | ||
2830 | useglobal = 1; | ||
2831 | cqr = &dasd_reserve_req->cqr; | ||
2832 | memset(cqr, 0, sizeof(*cqr)); | ||
2833 | memset(&dasd_reserve_req->ccw, 0, | ||
2834 | sizeof(dasd_reserve_req->ccw)); | ||
2835 | cqr->cpaddr = &dasd_reserve_req->ccw; | ||
2836 | cqr->data = &dasd_reserve_req->data; | ||
2837 | cqr->magic = DASD_ECKD_MAGIC; | ||
2838 | } | ||
2839 | ccw = cqr->cpaddr; | ||
2840 | ccw->cmd_code = DASD_ECKD_CCW_SNID; | ||
2841 | ccw->flags |= CCW_FLAG_SLI; | ||
2842 | ccw->count = 12; | ||
2843 | ccw->cda = (__u32)(addr_t) cqr->data; | ||
2844 | cqr->startdev = device; | ||
2845 | cqr->memdev = device; | ||
2846 | clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); | ||
2847 | set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); | ||
2848 | cqr->retries = 5; | ||
2849 | cqr->expires = 10 * HZ; | ||
2850 | cqr->buildclk = get_clock(); | ||
2851 | cqr->status = DASD_CQR_FILLED; | ||
2852 | cqr->lpm = usrparm.path_mask; | ||
2853 | |||
2854 | rc = dasd_sleep_on_immediatly(cqr); | ||
2855 | /* verify that I/O processing didn't modify the path mask */ | ||
2856 | if (!rc && usrparm.path_mask && (cqr->lpm != usrparm.path_mask)) | ||
2857 | rc = -EIO; | ||
2858 | if (!rc) { | ||
2859 | usrparm.data = *((struct dasd_snid_data *)cqr->data); | ||
2860 | if (copy_to_user(argp, &usrparm, sizeof(usrparm))) | ||
2861 | rc = -EFAULT; | ||
2862 | } | ||
2863 | |||
2864 | if (useglobal) | ||
2865 | mutex_unlock(&dasd_reserve_mutex); | ||
2866 | else | ||
2867 | dasd_sfree_request(cqr, cqr->memdev); | ||
2868 | return rc; | ||
2869 | } | ||
2870 | |||
2871 | /* | ||
2805 | * Read performance statistics | 2872 | * Read performance statistics |
2806 | */ | 2873 | */ |
2807 | static int | 2874 | static int |
@@ -3036,6 +3103,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) | |||
3036 | return dasd_eckd_reserve(device); | 3103 | return dasd_eckd_reserve(device); |
3037 | case BIODASDSLCK: | 3104 | case BIODASDSLCK: |
3038 | return dasd_eckd_steal_lock(device); | 3105 | return dasd_eckd_steal_lock(device); |
3106 | case BIODASDSNID: | ||
3107 | return dasd_eckd_snid(device, argp); | ||
3039 | case BIODASDSYMMIO: | 3108 | case BIODASDSYMMIO: |
3040 | return dasd_symm_io(device, argp); | 3109 | return dasd_symm_io(device, argp); |
3041 | default: | 3110 | default: |