Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab1d848f authored by Nigel Hislop's avatar Nigel Hislop Committed by Martin Schwidefsky
Browse files

[S390] Add ioctl support for EMC Symmetrix Subsystem Control I/O



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: default avatarNigel Hislop <hislop_nigel@emc.com>
Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 3ce66093
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -3,6 +3,8 @@
 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
 * Bugreports.to..: <Linux390@de.ibm.com>
 * Bugreports.to..: <Linux390@de.ibm.com>
 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
 * (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
 * 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
 * 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_SEQ_PRESTAGE  0x4
#define DASD_REC_ACCESS    0x5
#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
 * SECTION: Definition of IOCTLs
@@ -247,6 +259,7 @@ typedef struct attrib_data_t {
/* Set Attributes (cache operations) */
/* Set Attributes (cache operations) */
#define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
#define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 


#define BIODASDSYMMIO  _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)


#endif				/* DASD_H */
#endif				/* DASD_H */


+101 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,8 @@
 *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
 *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
 * Bugreports.to..: <Linux390@de.ibm.com>
 * Bugreports.to..: <Linux390@de.ibm.com>
 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
 * (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;
	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
static int
dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
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);
		return dasd_eckd_reserve(device);
	case BIODASDSLCK:
	case BIODASDSLCK:
		return dasd_eckd_steal_lock(device);
		return dasd_eckd_steal_lock(device);
	case BIODASDSYMMIO:
		return dasd_symm_io(device, argp);
	default:
	default:
		return -ENOIOCTLCMD;
		return -ENOIOCTLCMD;
	}
	}