[S390] Add ioctl support for EMC Symmetrix Subsystem Control I/O
authorNigel Hislop <hislop_nigel@emc.com>
Fri, 10 Oct 2008 19:33:25 +0000 (21:33 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 10 Oct 2008 19:34:00 +0000 (21:34 +0200)
EMC Symmetrix Subsystem Control I/O through CKD dasd requires a
specific parameter list sent to the array via a Perform Subsystem
Function CCW. The Symmetrix response is retrieved from the array
via a Read Subsystem Data CCW.

Signed-off-by: Nigel Hislop <hislop_nigel@emc.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/dasd.h
drivers/s390/block/dasd_eckd.c

index 3f002e13d024ee5bf4481ffb4c63698fdcd2ee60..55b2b80cdf6e0926da9663a52292fafb0ca27762 100644 (file)
@@ -3,6 +3,8 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
  *
  * This file is the interface of the DASD device driver, which is exported to user space
  * any future changes wrt the API will result in a change of the APIVERSION reported
@@ -202,6 +204,16 @@ typedef struct attrib_data_t {
 #define DASD_SEQ_PRESTAGE  0x4
 #define DASD_REC_ACCESS    0x5
 
+/*
+ * Perform EMC Symmetrix I/O
+ */
+typedef struct dasd_symmio_parms {
+       unsigned char reserved[8];      /* compat with older releases */
+       unsigned long long psf_data;    /* char * cast to u64 */
+       unsigned long long rssd_result; /* char * cast to u64 */
+       int psf_data_len;
+       int rssd_result_len;
+} __attribute__ ((packed)) dasd_symmio_parms_t;
 
 /********************************************************************************
  * SECTION: Definition of IOCTLs
@@ -247,6 +259,7 @@ typedef struct attrib_data_t {
 /* Set Attributes (cache operations) */
 #define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
 
+#define BIODASDSYMMIO  _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)
 
 #endif                         /* DASD_H */
 
index 8095629bc493f69b661d7c2c811ba2fc5777f023..49f9d221e23d4de9dd0deda5867565d29330f3a7 100644 (file)
@@ -6,6 +6,8 @@
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
+ * Author.........: Nigel Hislop <hislop_nigel@emc.com>
  *
  */
 
@@ -2083,6 +2085,103 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
        return 0;
 }
 
+/*
+ * Issue syscall I/O to EMC Symmetrix array.
+ * CCWs are PSF and RSSD
+ */
+static int dasd_symm_io(struct dasd_device *device, void __user *argp)
+{
+       struct dasd_symmio_parms usrparm;
+       char *psf_data, *rssd_result;
+       struct dasd_ccw_req *cqr;
+       struct ccw1 *ccw;
+       int rc;
+
+       /* Copy parms from caller */
+       rc = -EFAULT;
+       if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
+               goto out;
+#ifndef CONFIG_64BIT
+       /* Make sure pointers are sane even on 31 bit. */
+       if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) {
+               rc = -EINVAL;
+               goto out;
+       }
+#endif
+       /* alloc I/O data area */
+       psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA);
+       rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA);
+       if (!psf_data || !rssd_result) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
+
+       /* get syscall header from user space */
+       rc = -EFAULT;
+       if (copy_from_user(psf_data,
+                          (void __user *)(unsigned long) usrparm.psf_data,
+                          usrparm.psf_data_len))
+               goto out_free;
+
+       /* sanity check on syscall header */
+       if (psf_data[0] != 0x17 && psf_data[1] != 0xce) {
+               rc = -EINVAL;
+               goto out_free;
+       }
+
+       /* setup CCWs for PSF + RSSD */
+       cqr = dasd_smalloc_request("ECKD", 2 , 0, device);
+       if (IS_ERR(cqr)) {
+               DEV_MESSAGE(KERN_WARNING, device, "%s",
+                       "Could not allocate initialization request");
+               rc = PTR_ERR(cqr);
+               goto out_free;
+       }
+
+       cqr->startdev = device;
+       cqr->memdev = device;
+       cqr->retries = 3;
+       cqr->expires = 10 * HZ;
+       cqr->buildclk = get_clock();
+       cqr->status = DASD_CQR_FILLED;
+
+       /* Build the ccws */
+       ccw = cqr->cpaddr;
+
+       /* PSF ccw */
+       ccw->cmd_code = DASD_ECKD_CCW_PSF;
+       ccw->count = usrparm.psf_data_len;
+       ccw->flags |= CCW_FLAG_CC;
+       ccw->cda = (__u32)(addr_t) psf_data;
+
+       ccw++;
+
+       /* RSSD ccw  */
+       ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+       ccw->count = usrparm.rssd_result_len;
+       ccw->flags = CCW_FLAG_SLI ;
+       ccw->cda = (__u32)(addr_t) rssd_result;
+
+       rc = dasd_sleep_on(cqr);
+       if (rc)
+               goto out_sfree;
+
+       rc = -EFAULT;
+       if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result,
+                          rssd_result, usrparm.rssd_result_len))
+               goto out_sfree;
+       rc = 0;
+
+out_sfree:
+       dasd_sfree_request(cqr, cqr->memdev);
+out_free:
+       kfree(rssd_result);
+       kfree(psf_data);
+out:
+       DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc);
+       return rc;
+}
+
 static int
 dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
 {
@@ -2101,6 +2200,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 BIODASDSYMMIO:
+               return dasd_symm_io(device, argp);
        default:
                return -ENOIOCTLCMD;
        }