aboutsummaryrefslogtreecommitdiffstats
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.c132
1 files changed, 124 insertions, 8 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 773b3fe275b2..49f9d221e23d 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -6,6 +6,8 @@
6 * Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Bugreports.to..: <Linux390@de.ibm.com> 7 * Bugreports.to..: <Linux390@de.ibm.com>
8 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 8 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
9 * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
10 * Author.........: Nigel Hislop <hislop_nigel@emc.com>
9 * 11 *
10 */ 12 */
11 13
@@ -84,7 +86,7 @@ dasd_eckd_probe (struct ccw_device *cdev)
84 if (ret) { 86 if (ret) {
85 printk(KERN_WARNING 87 printk(KERN_WARNING
86 "dasd_eckd_probe: could not set ccw-device options " 88 "dasd_eckd_probe: could not set ccw-device options "
87 "for %s\n", cdev->dev.bus_id); 89 "for %s\n", dev_name(&cdev->dev));
88 return ret; 90 return ret;
89 } 91 }
90 ret = dasd_generic_probe(cdev, &dasd_eckd_discipline); 92 ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
@@ -1501,12 +1503,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
1501 return; 1503 return;
1502 } 1504 }
1503 1505
1504 /* just report other unsolicited interrupts */ 1506 if ((irb->scsw.cmd.cc == 1) &&
1505 DEV_MESSAGE(KERN_DEBUG, device, "%s", 1507 (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
1506 "unsolicited interrupt received"); 1508 (irb->scsw.cmd.actl & SCSW_ACTL_START_PEND) &&
1507 device->discipline->dump_sense(device, NULL, irb); 1509 (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND)) {
1508 dasd_schedule_device_bh(device); 1510 /* fake irb do nothing, they are handled elsewhere */
1511 dasd_schedule_device_bh(device);
1512 return;
1513 }
1514
1515 if (!(irb->esw.esw0.erw.cons)) {
1516 /* just report other unsolicited interrupts */
1517 DEV_MESSAGE(KERN_ERR, device, "%s",
1518 "unsolicited interrupt received");
1519 } else {
1520 DEV_MESSAGE(KERN_ERR, device, "%s",
1521 "unsolicited interrupt received "
1522 "(sense available)");
1523 device->discipline->dump_sense(device, NULL, irb);
1524 }
1509 1525
1526 dasd_schedule_device_bh(device);
1510 return; 1527 return;
1511}; 1528};
1512 1529
@@ -2068,6 +2085,103 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
2068 return 0; 2085 return 0;
2069} 2086}
2070 2087
2088/*
2089 * Issue syscall I/O to EMC Symmetrix array.
2090 * CCWs are PSF and RSSD
2091 */
2092static int dasd_symm_io(struct dasd_device *device, void __user *argp)
2093{
2094 struct dasd_symmio_parms usrparm;
2095 char *psf_data, *rssd_result;
2096 struct dasd_ccw_req *cqr;
2097 struct ccw1 *ccw;
2098 int rc;
2099
2100 /* Copy parms from caller */
2101 rc = -EFAULT;
2102 if (copy_from_user(&usrparm, argp, sizeof(usrparm)))
2103 goto out;
2104#ifndef CONFIG_64BIT
2105 /* Make sure pointers are sane even on 31 bit. */
2106 if ((usrparm.psf_data >> 32) != 0 || (usrparm.rssd_result >> 32) != 0) {
2107 rc = -EINVAL;
2108 goto out;
2109 }
2110#endif
2111 /* alloc I/O data area */
2112 psf_data = kzalloc(usrparm.psf_data_len, GFP_KERNEL | GFP_DMA);
2113 rssd_result = kzalloc(usrparm.rssd_result_len, GFP_KERNEL | GFP_DMA);
2114 if (!psf_data || !rssd_result) {
2115 rc = -ENOMEM;
2116 goto out_free;
2117 }
2118
2119 /* get syscall header from user space */
2120 rc = -EFAULT;
2121 if (copy_from_user(psf_data,
2122 (void __user *)(unsigned long) usrparm.psf_data,
2123 usrparm.psf_data_len))
2124 goto out_free;
2125
2126 /* sanity check on syscall header */
2127 if (psf_data[0] != 0x17 && psf_data[1] != 0xce) {
2128 rc = -EINVAL;
2129 goto out_free;
2130 }
2131
2132 /* setup CCWs for PSF + RSSD */
2133 cqr = dasd_smalloc_request("ECKD", 2 , 0, device);
2134 if (IS_ERR(cqr)) {
2135 DEV_MESSAGE(KERN_WARNING, device, "%s",
2136 "Could not allocate initialization request");
2137 rc = PTR_ERR(cqr);
2138 goto out_free;
2139 }
2140
2141 cqr->startdev = device;
2142 cqr->memdev = device;
2143 cqr->retries = 3;
2144 cqr->expires = 10 * HZ;
2145 cqr->buildclk = get_clock();
2146 cqr->status = DASD_CQR_FILLED;
2147
2148 /* Build the ccws */
2149 ccw = cqr->cpaddr;
2150
2151 /* PSF ccw */
2152 ccw->cmd_code = DASD_ECKD_CCW_PSF;
2153 ccw->count = usrparm.psf_data_len;
2154 ccw->flags |= CCW_FLAG_CC;
2155 ccw->cda = (__u32)(addr_t) psf_data;
2156
2157 ccw++;
2158
2159 /* RSSD ccw */
2160 ccw->cmd_code = DASD_ECKD_CCW_RSSD;
2161 ccw->count = usrparm.rssd_result_len;
2162 ccw->flags = CCW_FLAG_SLI ;
2163 ccw->cda = (__u32)(addr_t) rssd_result;
2164
2165 rc = dasd_sleep_on(cqr);
2166 if (rc)
2167 goto out_sfree;
2168
2169 rc = -EFAULT;
2170 if (copy_to_user((void __user *)(unsigned long) usrparm.rssd_result,
2171 rssd_result, usrparm.rssd_result_len))
2172 goto out_sfree;
2173 rc = 0;
2174
2175out_sfree:
2176 dasd_sfree_request(cqr, cqr->memdev);
2177out_free:
2178 kfree(rssd_result);
2179 kfree(psf_data);
2180out:
2181 DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc);
2182 return rc;
2183}
2184
2071static int 2185static int
2072dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) 2186dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
2073{ 2187{
@@ -2086,6 +2200,8 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
2086 return dasd_eckd_reserve(device); 2200 return dasd_eckd_reserve(device);
2087 case BIODASDSLCK: 2201 case BIODASDSLCK:
2088 return dasd_eckd_steal_lock(device); 2202 return dasd_eckd_steal_lock(device);
2203 case BIODASDSYMMIO:
2204 return dasd_symm_io(device, argp);
2089 default: 2205 default:
2090 return -ENOIOCTLCMD; 2206 return -ENOIOCTLCMD;
2091 } 2207 }
@@ -2145,13 +2261,13 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
2145 /* dump the sense data */ 2261 /* dump the sense data */
2146 len = sprintf(page, KERN_ERR PRINTK_HEADER 2262 len = sprintf(page, KERN_ERR PRINTK_HEADER
2147 " I/O status report for device %s:\n", 2263 " I/O status report for device %s:\n",
2148 device->cdev->dev.bus_id); 2264 dev_name(&device->cdev->dev));
2149 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 2265 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
2150 " in req: %p CS: 0x%02X DS: 0x%02X\n", req, 2266 " in req: %p CS: 0x%02X DS: 0x%02X\n", req,
2151 irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); 2267 irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
2152 len += sprintf(page + len, KERN_ERR PRINTK_HEADER 2268 len += sprintf(page + len, KERN_ERR PRINTK_HEADER
2153 " device %s: Failing CCW: %p\n", 2269 " device %s: Failing CCW: %p\n",
2154 device->cdev->dev.bus_id, 2270 dev_name(&device->cdev->dev),
2155 (void *) (addr_t) irb->scsw.cmd.cpa); 2271 (void *) (addr_t) irb->scsw.cmd.cpa);
2156 if (irb->esw.esw0.erw.cons) { 2272 if (irb->esw.esw0.erw.cons) {
2157 for (sl = 0; sl < 4; sl++) { 2273 for (sl = 0; sl < 4; sl++) {