diff options
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 132 |
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 | */ | ||
2092 | static 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 | |||
2175 | out_sfree: | ||
2176 | dasd_sfree_request(cqr, cqr->memdev); | ||
2177 | out_free: | ||
2178 | kfree(rssd_result); | ||
2179 | kfree(psf_data); | ||
2180 | out: | ||
2181 | DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc); | ||
2182 | return rc; | ||
2183 | } | ||
2184 | |||
2071 | static int | 2185 | static int |
2072 | dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) | 2186 | dasd_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++) { |