]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/s390/block/dasd_eckd.c
[S390] dasd: provide a Sense Path Group ID ioctl
[net-next-2.6.git] / drivers / s390 / block / dasd_eckd.c
index 50cf96389d2c319c3d67d95a039e00157adc0078..bf61274af3bb1a0290f6bfbf897205c079da9b5f 100644 (file)
@@ -2801,6 +2801,73 @@ dasd_eckd_steal_lock(struct dasd_device *device)
        return rc;
 }
 
+/*
+ * 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
  */
@@ -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: