aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/s390/block/dasd.c33
-rw-r--r--drivers/s390/block/dasd_devmap.c24
-rw-r--r--drivers/s390/block/dasd_eckd.c372
-rw-r--r--drivers/s390/block/dasd_eckd.h63
-rw-r--r--drivers/s390/block/dasd_int.h10
-rw-r--r--drivers/s390/char/Kconfig13
-rw-r--r--drivers/s390/char/Makefile3
-rw-r--r--drivers/s390/char/diag_ftp.c237
-rw-r--r--drivers/s390/char/diag_ftp.h21
-rw-r--r--drivers/s390/char/hmcdrv_cache.c252
-rw-r--r--drivers/s390/char/hmcdrv_cache.h24
-rw-r--r--drivers/s390/char/hmcdrv_dev.c370
-rw-r--r--drivers/s390/char/hmcdrv_dev.h14
-rw-r--r--drivers/s390/char/hmcdrv_ftp.c343
-rw-r--r--drivers/s390/char/hmcdrv_ftp.h63
-rw-r--r--drivers/s390/char/hmcdrv_mod.c64
-rw-r--r--drivers/s390/char/sclp.h2
-rw-r--r--drivers/s390/char/sclp_diag.h89
-rw-r--r--drivers/s390/char/sclp_early.c2
-rw-r--r--drivers/s390/char/sclp_ftp.c275
-rw-r--r--drivers/s390/char/sclp_ftp.h21
-rw-r--r--drivers/s390/char/sclp_rw.c13
-rw-r--r--drivers/s390/char/sclp_vt220.c4
-rw-r--r--drivers/s390/char/tape_char.c4
-rw-r--r--drivers/s390/char/zcore.c18
-rw-r--r--drivers/s390/cio/airq.c2
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/crypto/ap_bus.c30
-rw-r--r--drivers/s390/crypto/ap_bus.h7
-rw-r--r--drivers/s390/crypto/zcrypt_api.c7
30 files changed, 2334 insertions, 48 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 5df05f26b7d9..329db997ee66 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1660,6 +1660,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
1660 device->discipline->check_for_device_change(device, cqr, irb); 1660 device->discipline->check_for_device_change(device, cqr, irb);
1661 dasd_put_device(device); 1661 dasd_put_device(device);
1662 } 1662 }
1663
1664 /* check for for attention message */
1665 if (scsw_dstat(&irb->scsw) & DEV_STAT_ATTENTION) {
1666 device = dasd_device_from_cdev_locked(cdev);
1667 device->discipline->check_attention(device, irb->esw.esw1.lpum);
1668 dasd_put_device(device);
1669 }
1670
1663 if (!cqr) 1671 if (!cqr)
1664 return; 1672 return;
1665 1673
@@ -2261,8 +2269,8 @@ static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
2261static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible) 2269static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
2262{ 2270{
2263 struct dasd_device *device; 2271 struct dasd_device *device;
2264 int rc;
2265 struct dasd_ccw_req *cqr, *n; 2272 struct dasd_ccw_req *cqr, *n;
2273 int rc;
2266 2274
2267retry: 2275retry:
2268 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) { 2276 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
@@ -2310,21 +2318,26 @@ retry:
2310 /* 2318 /*
2311 * for alias devices simplify error recovery and 2319 * for alias devices simplify error recovery and
2312 * return to upper layer 2320 * return to upper layer
2321 * do not skip ERP requests
2313 */ 2322 */
2314 if (cqr->startdev != cqr->basedev && 2323 if (cqr->startdev != cqr->basedev && !cqr->refers &&
2315 (cqr->status == DASD_CQR_TERMINATED || 2324 (cqr->status == DASD_CQR_TERMINATED ||
2316 cqr->status == DASD_CQR_NEED_ERP)) 2325 cqr->status == DASD_CQR_NEED_ERP))
2317 return -EAGAIN; 2326 return -EAGAIN;
2318 else { 2327
2319 /* normal recovery for basedev IO */ 2328 /* normal recovery for basedev IO */
2320 if (__dasd_sleep_on_erp(cqr)) { 2329 if (__dasd_sleep_on_erp(cqr)) {
2321 if (!cqr->status == DASD_CQR_TERMINATED && 2330 goto retry;
2322 !cqr->status == DASD_CQR_NEED_ERP) 2331 /* remember that ERP was needed */
2323 break; 2332 rc = 1;
2324 rc = 1; 2333 /* skip processing for active cqr */
2325 } 2334 if (cqr->status != DASD_CQR_TERMINATED &&
2335 cqr->status != DASD_CQR_NEED_ERP)
2336 break;
2326 } 2337 }
2327 } 2338 }
2339
2340 /* start ERP requests in upper loop */
2328 if (rc) 2341 if (rc)
2329 goto retry; 2342 goto retry;
2330 2343
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 14ba80bfa571..8286f742436b 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -1432,6 +1432,29 @@ static ssize_t dasd_reservation_state_store(struct device *dev,
1432static DEVICE_ATTR(last_known_reservation_state, 0644, 1432static DEVICE_ATTR(last_known_reservation_state, 0644,
1433 dasd_reservation_state_show, dasd_reservation_state_store); 1433 dasd_reservation_state_show, dasd_reservation_state_store);
1434 1434
1435static ssize_t dasd_pm_show(struct device *dev,
1436 struct device_attribute *attr, char *buf)
1437{
1438 struct dasd_device *device;
1439 u8 opm, nppm, cablepm, cuirpm, hpfpm;
1440
1441 device = dasd_device_from_cdev(to_ccwdev(dev));
1442 if (IS_ERR(device))
1443 return sprintf(buf, "0\n");
1444
1445 opm = device->path_data.opm;
1446 nppm = device->path_data.npm;
1447 cablepm = device->path_data.cablepm;
1448 cuirpm = device->path_data.cuirpm;
1449 hpfpm = device->path_data.hpfpm;
1450 dasd_put_device(device);
1451
1452 return sprintf(buf, "%02x %02x %02x %02x %02x\n", opm, nppm,
1453 cablepm, cuirpm, hpfpm);
1454}
1455
1456static DEVICE_ATTR(path_masks, 0444, dasd_pm_show, NULL);
1457
1435static struct attribute * dasd_attrs[] = { 1458static struct attribute * dasd_attrs[] = {
1436 &dev_attr_readonly.attr, 1459 &dev_attr_readonly.attr,
1437 &dev_attr_discipline.attr, 1460 &dev_attr_discipline.attr,
@@ -1450,6 +1473,7 @@ static struct attribute * dasd_attrs[] = {
1450 &dev_attr_reservation_policy.attr, 1473 &dev_attr_reservation_policy.attr,
1451 &dev_attr_last_known_reservation_state.attr, 1474 &dev_attr_last_known_reservation_state.attr,
1452 &dev_attr_safe_offline.attr, 1475 &dev_attr_safe_offline.attr,
1476 &dev_attr_path_masks.attr,
1453 NULL, 1477 NULL,
1454}; 1478};
1455 1479
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 51dea7baf02c..d47f5b99623a 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -29,6 +29,8 @@
29#include <asm/cio.h> 29#include <asm/cio.h>
30#include <asm/ccwdev.h> 30#include <asm/ccwdev.h>
31#include <asm/itcw.h> 31#include <asm/itcw.h>
32#include <asm/schid.h>
33#include <asm/chpid.h>
32 34
33#include "dasd_int.h" 35#include "dasd_int.h"
34#include "dasd_eckd.h" 36#include "dasd_eckd.h"
@@ -112,6 +114,12 @@ struct path_verification_work_data {
112static struct path_verification_work_data *path_verification_worker; 114static struct path_verification_work_data *path_verification_worker;
113static DEFINE_MUTEX(dasd_path_verification_mutex); 115static DEFINE_MUTEX(dasd_path_verification_mutex);
114 116
117struct check_attention_work_data {
118 struct work_struct worker;
119 struct dasd_device *device;
120 __u8 lpum;
121};
122
115/* initial attempt at a probe function. this can be simplified once 123/* initial attempt at a probe function. this can be simplified once
116 * the other detection code is gone */ 124 * the other detection code is gone */
117static int 125static int
@@ -1126,6 +1134,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
1126 "device %s instead of %s\n", lpm, 1134 "device %s instead of %s\n", lpm,
1127 print_path_uid, print_device_uid); 1135 print_path_uid, print_device_uid);
1128 path_err = -EINVAL; 1136 path_err = -EINVAL;
1137 path_data->cablepm |= lpm;
1129 continue; 1138 continue;
1130 } 1139 }
1131 1140
@@ -1141,6 +1150,13 @@ static int dasd_eckd_read_conf(struct dasd_device *device)
1141 break; 1150 break;
1142 } 1151 }
1143 path_data->opm |= lpm; 1152 path_data->opm |= lpm;
1153 /*
1154 * if the path is used
1155 * it should not be in one of the negative lists
1156 */
1157 path_data->cablepm &= ~lpm;
1158 path_data->hpfpm &= ~lpm;
1159 path_data->cuirpm &= ~lpm;
1144 1160
1145 if (conf_data != private->conf_data) 1161 if (conf_data != private->conf_data)
1146 kfree(conf_data); 1162 kfree(conf_data);
@@ -1230,7 +1246,7 @@ static void do_path_verification_work(struct work_struct *work)
1230 struct dasd_eckd_private path_private; 1246 struct dasd_eckd_private path_private;
1231 struct dasd_uid *uid; 1247 struct dasd_uid *uid;
1232 __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE]; 1248 __u8 path_rcd_buf[DASD_ECKD_RCD_DATA_SIZE];
1233 __u8 lpm, opm, npm, ppm, epm; 1249 __u8 lpm, opm, npm, ppm, epm, hpfpm, cablepm;
1234 unsigned long flags; 1250 unsigned long flags;
1235 char print_uid[60]; 1251 char print_uid[60];
1236 int rc; 1252 int rc;
@@ -1248,6 +1264,9 @@ static void do_path_verification_work(struct work_struct *work)
1248 npm = 0; 1264 npm = 0;
1249 ppm = 0; 1265 ppm = 0;
1250 epm = 0; 1266 epm = 0;
1267 hpfpm = 0;
1268 cablepm = 0;
1269
1251 for (lpm = 0x80; lpm; lpm >>= 1) { 1270 for (lpm = 0x80; lpm; lpm >>= 1) {
1252 if (!(lpm & data->tbvpm)) 1271 if (!(lpm & data->tbvpm))
1253 continue; 1272 continue;
@@ -1289,6 +1308,7 @@ static void do_path_verification_work(struct work_struct *work)
1289 opm &= ~lpm; 1308 opm &= ~lpm;
1290 npm &= ~lpm; 1309 npm &= ~lpm;
1291 ppm &= ~lpm; 1310 ppm &= ~lpm;
1311 hpfpm |= lpm;
1292 continue; 1312 continue;
1293 } 1313 }
1294 1314
@@ -1350,6 +1370,7 @@ static void do_path_verification_work(struct work_struct *work)
1350 opm &= ~lpm; 1370 opm &= ~lpm;
1351 npm &= ~lpm; 1371 npm &= ~lpm;
1352 ppm &= ~lpm; 1372 ppm &= ~lpm;
1373 cablepm |= lpm;
1353 continue; 1374 continue;
1354 } 1375 }
1355 } 1376 }
@@ -1364,12 +1385,21 @@ static void do_path_verification_work(struct work_struct *work)
1364 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); 1385 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
1365 if (!device->path_data.opm && opm) { 1386 if (!device->path_data.opm && opm) {
1366 device->path_data.opm = opm; 1387 device->path_data.opm = opm;
1388 device->path_data.cablepm &= ~opm;
1389 device->path_data.cuirpm &= ~opm;
1390 device->path_data.hpfpm &= ~opm;
1367 dasd_generic_path_operational(device); 1391 dasd_generic_path_operational(device);
1368 } else 1392 } else {
1369 device->path_data.opm |= opm; 1393 device->path_data.opm |= opm;
1394 device->path_data.cablepm &= ~opm;
1395 device->path_data.cuirpm &= ~opm;
1396 device->path_data.hpfpm &= ~opm;
1397 }
1370 device->path_data.npm |= npm; 1398 device->path_data.npm |= npm;
1371 device->path_data.ppm |= ppm; 1399 device->path_data.ppm |= ppm;
1372 device->path_data.tbvpm |= epm; 1400 device->path_data.tbvpm |= epm;
1401 device->path_data.cablepm |= cablepm;
1402 device->path_data.hpfpm |= hpfpm;
1373 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); 1403 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
1374 } 1404 }
1375 1405
@@ -4475,6 +4505,343 @@ out_err:
4475 return -1; 4505 return -1;
4476} 4506}
4477 4507
4508static int dasd_eckd_read_message_buffer(struct dasd_device *device,
4509 struct dasd_rssd_messages *messages,
4510 __u8 lpum)
4511{
4512 struct dasd_rssd_messages *message_buf;
4513 struct dasd_psf_prssd_data *prssdp;
4514 struct dasd_eckd_private *private;
4515 struct dasd_ccw_req *cqr;
4516 struct ccw1 *ccw;
4517 int rc;
4518
4519 private = (struct dasd_eckd_private *) device->private;
4520 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ + 1 /* RSSD */,
4521 (sizeof(struct dasd_psf_prssd_data) +
4522 sizeof(struct dasd_rssd_messages)),
4523 device);
4524 if (IS_ERR(cqr)) {
4525 DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
4526 "Could not allocate read message buffer request");
4527 return PTR_ERR(cqr);
4528 }
4529
4530 cqr->startdev = device;
4531 cqr->memdev = device;
4532 cqr->block = NULL;
4533 cqr->retries = 256;
4534 cqr->expires = 10 * HZ;
4535
4536 /* we need to check for messages on exactly this path */
4537 set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags);
4538 cqr->lpm = lpum;
4539
4540 /* Prepare for Read Subsystem Data */
4541 prssdp = (struct dasd_psf_prssd_data *) cqr->data;
4542 memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
4543 prssdp->order = PSF_ORDER_PRSSD;
4544 prssdp->suborder = 0x03; /* Message Buffer */
4545 /* all other bytes of prssdp must be zero */
4546
4547 ccw = cqr->cpaddr;
4548 ccw->cmd_code = DASD_ECKD_CCW_PSF;
4549 ccw->count = sizeof(struct dasd_psf_prssd_data);
4550 ccw->flags |= CCW_FLAG_CC;
4551 ccw->flags |= CCW_FLAG_SLI;
4552 ccw->cda = (__u32)(addr_t) prssdp;
4553
4554 /* Read Subsystem Data - message buffer */
4555 message_buf = (struct dasd_rssd_messages *) (prssdp + 1);
4556 memset(message_buf, 0, sizeof(struct dasd_rssd_messages));
4557
4558 ccw++;
4559 ccw->cmd_code = DASD_ECKD_CCW_RSSD;
4560 ccw->count = sizeof(struct dasd_rssd_messages);
4561 ccw->flags |= CCW_FLAG_SLI;
4562 ccw->cda = (__u32)(addr_t) message_buf;
4563
4564 cqr->buildclk = get_tod_clock();
4565 cqr->status = DASD_CQR_FILLED;
4566 rc = dasd_sleep_on_immediatly(cqr);
4567 if (rc == 0) {
4568 prssdp = (struct dasd_psf_prssd_data *) cqr->data;
4569 message_buf = (struct dasd_rssd_messages *)
4570 (prssdp + 1);
4571 memcpy(messages, message_buf,
4572 sizeof(struct dasd_rssd_messages));
4573 } else
4574 DBF_EVENT_DEVID(DBF_WARNING, device->cdev,
4575 "Reading messages failed with rc=%d\n"
4576 , rc);
4577 dasd_sfree_request(cqr, cqr->memdev);
4578 return rc;
4579}
4580
4581/*
4582 * Perform Subsystem Function - CUIR response
4583 */
4584static int
4585dasd_eckd_psf_cuir_response(struct dasd_device *device, int response,
4586 __u32 message_id,
4587 struct channel_path_desc *desc,
4588 struct subchannel_id sch_id)
4589{
4590 struct dasd_psf_cuir_response *psf_cuir;
4591 struct dasd_ccw_req *cqr;
4592 struct ccw1 *ccw;
4593 int rc;
4594
4595 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* PSF */ ,
4596 sizeof(struct dasd_psf_cuir_response),
4597 device);
4598
4599 if (IS_ERR(cqr)) {
4600 DBF_DEV_EVENT(DBF_WARNING, device, "%s",
4601 "Could not allocate PSF-CUIR request");
4602 return PTR_ERR(cqr);
4603 }
4604
4605 psf_cuir = (struct dasd_psf_cuir_response *)cqr->data;
4606 psf_cuir->order = PSF_ORDER_CUIR_RESPONSE;
4607 psf_cuir->cc = response;
4608 if (desc)
4609 psf_cuir->chpid = desc->chpid;
4610 psf_cuir->message_id = message_id;
4611 psf_cuir->cssid = sch_id.cssid;
4612 psf_cuir->ssid = sch_id.ssid;
4613
4614 ccw = cqr->cpaddr;
4615 ccw->cmd_code = DASD_ECKD_CCW_PSF;
4616 ccw->cda = (__u32)(addr_t)psf_cuir;
4617 ccw->count = sizeof(struct dasd_psf_cuir_response);
4618
4619 cqr->startdev = device;
4620 cqr->memdev = device;
4621 cqr->block = NULL;
4622 cqr->retries = 256;
4623 cqr->expires = 10*HZ;
4624 cqr->buildclk = get_tod_clock();
4625 cqr->status = DASD_CQR_FILLED;
4626
4627 rc = dasd_sleep_on(cqr);
4628
4629 dasd_sfree_request(cqr, cqr->memdev);
4630 return rc;
4631}
4632
4633static int dasd_eckd_cuir_change_state(struct dasd_device *device, __u8 lpum)
4634{
4635 unsigned long flags;
4636 __u8 tbcpm;
4637
4638 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
4639 tbcpm = device->path_data.opm & ~lpum;
4640 if (tbcpm) {
4641 device->path_data.opm = tbcpm;
4642 device->path_data.cuirpm |= lpum;
4643 }
4644 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
4645 return tbcpm ? 0 : PSF_CUIR_LAST_PATH;
4646}
4647
4648/*
4649 * walk through all devices and quiesce them
4650 * if it is the last path return error
4651 *
4652 * if only part of the devices are quiesced and an error
4653 * occurs no onlining necessary, the storage server will
4654 * notify the already set offline devices again
4655 */
4656static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum,
4657 struct channel_path_desc *desc,
4658 struct subchannel_id sch_id)
4659{
4660 struct alias_pav_group *pavgroup, *tempgroup;
4661 struct dasd_eckd_private *private;
4662 struct dasd_device *dev, *n;
4663 int rc;
4664
4665 private = (struct dasd_eckd_private *) device->private;
4666 rc = 0;
4667
4668 /* active devices */
4669 list_for_each_entry_safe(dev, n,
4670 &private->lcu->active_devices,
4671 alias_list) {
4672 rc = dasd_eckd_cuir_change_state(dev, lpum);
4673 if (rc)
4674 goto out;
4675 }
4676
4677 /* inactive devices */
4678 list_for_each_entry_safe(dev, n,
4679 &private->lcu->inactive_devices,
4680 alias_list) {
4681 rc = dasd_eckd_cuir_change_state(dev, lpum);
4682 if (rc)
4683 goto out;
4684 }
4685
4686 /* devices in PAV groups */
4687 list_for_each_entry_safe(pavgroup, tempgroup,
4688 &private->lcu->grouplist, group) {
4689 list_for_each_entry_safe(dev, n, &pavgroup->baselist,
4690 alias_list) {
4691 rc = dasd_eckd_cuir_change_state(dev, lpum);
4692 if (rc)
4693 goto out;
4694 }
4695 list_for_each_entry_safe(dev, n, &pavgroup->aliaslist,
4696 alias_list) {
4697 rc = dasd_eckd_cuir_change_state(dev, lpum);
4698 if (rc)
4699 goto out;
4700 }
4701 }
4702
4703 pr_warn("Service on the storage server caused path %x.%02x to go offline",
4704 sch_id.cssid, desc ? desc->chpid : 0);
4705 rc = PSF_CUIR_COMPLETED;
4706out:
4707 return rc;
4708}
4709
4710static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum,
4711 struct channel_path_desc *desc,
4712 struct subchannel_id sch_id)
4713{
4714 struct alias_pav_group *pavgroup, *tempgroup;
4715 struct dasd_eckd_private *private;
4716 struct dasd_device *dev, *n;
4717
4718 pr_info("Path %x.%02x is back online after service on the storage server",
4719 sch_id.cssid, desc ? desc->chpid : 0);
4720 private = (struct dasd_eckd_private *) device->private;
4721
4722 /*
4723 * the path may have been added through a generic path event before
4724 * only trigger path verification if the path is not already in use
4725 */
4726
4727 list_for_each_entry_safe(dev, n,
4728 &private->lcu->active_devices,
4729 alias_list) {
4730 if (!(dev->path_data.opm & lpum)) {
4731 dev->path_data.tbvpm |= lpum;
4732 dasd_schedule_device_bh(dev);
4733 }
4734 }
4735
4736 list_for_each_entry_safe(dev, n,
4737 &private->lcu->inactive_devices,
4738 alias_list) {
4739 if (!(dev->path_data.opm & lpum)) {
4740 dev->path_data.tbvpm |= lpum;
4741 dasd_schedule_device_bh(dev);
4742 }
4743 }
4744
4745 /* devices in PAV groups */
4746 list_for_each_entry_safe(pavgroup, tempgroup,
4747 &private->lcu->grouplist,
4748 group) {
4749 list_for_each_entry_safe(dev, n,
4750 &pavgroup->baselist,
4751 alias_list) {
4752 if (!(dev->path_data.opm & lpum)) {
4753 dev->path_data.tbvpm |= lpum;
4754 dasd_schedule_device_bh(dev);
4755 }
4756 }
4757 list_for_each_entry_safe(dev, n,
4758 &pavgroup->aliaslist,
4759 alias_list) {
4760 if (!(dev->path_data.opm & lpum)) {
4761 dev->path_data.tbvpm |= lpum;
4762 dasd_schedule_device_bh(dev);
4763 }
4764 }
4765 }
4766 return PSF_CUIR_COMPLETED;
4767}
4768
4769static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages,
4770 __u8 lpum)
4771{
4772 struct dasd_cuir_message *cuir = messages;
4773 struct channel_path_desc *desc;
4774 struct subchannel_id sch_id;
4775 int pos, response;
4776 ccw_device_get_schid(device->cdev, &sch_id);
4777
4778 /* get position of path in mask */
4779 pos = 8 - ffs(lpum);
4780 /* get channel path descriptor from this position */
4781 desc = ccw_device_get_chp_desc(device->cdev, pos);
4782
4783 if (cuir->code == CUIR_QUIESCE) {
4784 /* quiesce */
4785 response = dasd_eckd_cuir_quiesce(device, lpum, desc, sch_id);
4786 } else if (cuir->code == CUIR_RESUME) {
4787 /* resume */
4788 response = dasd_eckd_cuir_resume(device, lpum, desc, sch_id);
4789 } else
4790 response = PSF_CUIR_NOT_SUPPORTED;
4791
4792 dasd_eckd_psf_cuir_response(device, response, cuir->message_id,
4793 desc, sch_id);
4794
4795 /* free descriptor copy */
4796 kfree(desc);
4797}
4798
4799static void dasd_eckd_check_attention_work(struct work_struct *work)
4800{
4801 struct check_attention_work_data *data;
4802 struct dasd_rssd_messages *messages;
4803 struct dasd_device *device;
4804 int rc;
4805
4806 data = container_of(work, struct check_attention_work_data, worker);
4807 device = data->device;
4808
4809 messages = kzalloc(sizeof(*messages), GFP_KERNEL);
4810 if (!messages) {
4811 DBF_DEV_EVENT(DBF_WARNING, device, "%s",
4812 "Could not allocate attention message buffer");
4813 goto out;
4814 }
4815
4816 rc = dasd_eckd_read_message_buffer(device, messages, data->lpum);
4817 if (rc)
4818 goto out;
4819
4820 if (messages->length == ATTENTION_LENGTH_CUIR &&
4821 messages->format == ATTENTION_FORMAT_CUIR)
4822 dasd_eckd_handle_cuir(device, messages, data->lpum);
4823
4824out:
4825 dasd_put_device(device);
4826 kfree(messages);
4827 kfree(data);
4828}
4829
4830static int dasd_eckd_check_attention(struct dasd_device *device, __u8 lpum)
4831{
4832 struct check_attention_work_data *data;
4833
4834 data = kzalloc(sizeof(*data), GFP_ATOMIC);
4835 if (!data)
4836 return -ENOMEM;
4837 INIT_WORK(&data->worker, dasd_eckd_check_attention_work);
4838 dasd_get_device(device);
4839 data->device = device;
4840 data->lpum = lpum;
4841 schedule_work(&data->worker);
4842 return 0;
4843}
4844
4478static struct ccw_driver dasd_eckd_driver = { 4845static struct ccw_driver dasd_eckd_driver = {
4479 .driver = { 4846 .driver = {
4480 .name = "dasd-eckd", 4847 .name = "dasd-eckd",
@@ -4539,6 +4906,7 @@ static struct dasd_discipline dasd_eckd_discipline = {
4539 .reload = dasd_eckd_reload_device, 4906 .reload = dasd_eckd_reload_device,
4540 .get_uid = dasd_eckd_get_uid, 4907 .get_uid = dasd_eckd_get_uid,
4541 .kick_validate = dasd_eckd_kick_validate_server, 4908 .kick_validate = dasd_eckd_kick_validate_server,
4909 .check_attention = dasd_eckd_check_attention,
4542}; 4910};
4543 4911
4544static int __init 4912static int __init
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 2555e494591f..ddab7df36e25 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -51,8 +51,35 @@
51/* 51/*
52 * Perform Subsystem Function / Sub-Orders 52 * Perform Subsystem Function / Sub-Orders
53 */ 53 */
54#define PSF_ORDER_PRSSD 0x18 54#define PSF_ORDER_PRSSD 0x18
55#define PSF_ORDER_SSC 0x1D 55#define PSF_ORDER_CUIR_RESPONSE 0x1A
56#define PSF_ORDER_SSC 0x1D
57
58/*
59 * CUIR response condition codes
60 */
61#define PSF_CUIR_INVALID 0x00
62#define PSF_CUIR_COMPLETED 0x01
63#define PSF_CUIR_NOT_SUPPORTED 0x02
64#define PSF_CUIR_ERROR_IN_REQ 0x03
65#define PSF_CUIR_DENIED 0x04
66#define PSF_CUIR_LAST_PATH 0x05
67#define PSF_CUIR_DEVICE_ONLINE 0x06
68#define PSF_CUIR_VARY_FAILURE 0x07
69#define PSF_CUIR_SOFTWARE_FAILURE 0x08
70#define PSF_CUIR_NOT_RECOGNIZED 0x09
71
72/*
73 * CUIR codes
74 */
75#define CUIR_QUIESCE 0x01
76#define CUIR_RESUME 0x02
77
78/*
79 * attention message definitions
80 */
81#define ATTENTION_LENGTH_CUIR 0x0e
82#define ATTENTION_FORMAT_CUIR 0x01
56 83
57/* 84/*
58 * Size that is reportet for large volumes in the old 16-bit no_cyl field 85 * Size that is reportet for large volumes in the old 16-bit no_cyl field
@@ -342,6 +369,38 @@ struct dasd_rssd_features {
342 char feature[256]; 369 char feature[256];
343} __attribute__((packed)); 370} __attribute__((packed));
344 371
372struct dasd_rssd_messages {
373 __u16 length;
374 __u8 format;
375 __u8 code;
376 __u32 message_id;
377 __u8 flags;
378 char messages[4087];
379} __packed;
380
381struct dasd_cuir_message {
382 __u16 length;
383 __u8 format;
384 __u8 code;
385 __u32 message_id;
386 __u8 flags;
387 __u8 neq_map[3];
388 __u8 ned_map;
389 __u8 record_selector;
390} __packed;
391
392struct dasd_psf_cuir_response {
393 __u8 order;
394 __u8 flags;
395 __u8 cc;
396 __u8 chpid;
397 __u16 device_nr;
398 __u16 reserved;
399 __u32 message_id;
400 __u64 system_id;
401 __u8 cssid;
402 __u8 ssid;
403} __packed;
345 404
346/* 405/*
347 * Perform Subsystem Function - Prepare for Read Subsystem Data 406 * Perform Subsystem Function - Prepare for Read Subsystem Data
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index c20170166909..8b5d4100abf7 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -357,6 +357,7 @@ struct dasd_discipline {
357 357
358 int (*get_uid) (struct dasd_device *, struct dasd_uid *); 358 int (*get_uid) (struct dasd_device *, struct dasd_uid *);
359 void (*kick_validate) (struct dasd_device *); 359 void (*kick_validate) (struct dasd_device *);
360 int (*check_attention)(struct dasd_device *, __u8);
360}; 361};
361 362
362extern struct dasd_discipline *dasd_diag_discipline_pointer; 363extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -382,6 +383,10 @@ struct dasd_path {
382 __u8 tbvpm; 383 __u8 tbvpm;
383 __u8 ppm; 384 __u8 ppm;
384 __u8 npm; 385 __u8 npm;
386 /* paths that are not used because of a special condition */
387 __u8 cablepm; /* miss-cabled */
388 __u8 hpfpm; /* the HPF requirements of the other paths are not met */
389 __u8 cuirpm; /* CUIR varied offline */
385}; 390};
386 391
387struct dasd_profile_info { 392struct dasd_profile_info {
@@ -501,7 +506,10 @@ struct dasd_block {
501 struct dasd_profile profile; 506 struct dasd_profile profile;
502}; 507};
503 508
504 509struct dasd_attention_data {
510 struct dasd_device *device;
511 __u8 lpum;
512};
505 513
506/* reasons why device (ccw_device_start) was stopped */ 514/* reasons why device (ccw_device_start) was stopped */
507#define DASD_STOPPED_NOT_ACC 1 /* not accessible */ 515#define DASD_STOPPED_NOT_ACC 1 /* not accessible */
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 71bf959732fe..dc24ecfac2d1 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -102,6 +102,19 @@ config SCLP_ASYNC
102 want for inform other people about your kernel panics, 102 want for inform other people about your kernel panics,
103 need this feature and intend to run your kernel in LPAR. 103 need this feature and intend to run your kernel in LPAR.
104 104
105config HMC_DRV
106 def_tristate m
107 prompt "Support for file transfers from HMC drive CD/DVD-ROM"
108 depends on 64BIT
109 select CRC16
110 help
111 This option enables support for file transfers from a Hardware
112 Management Console (HMC) drive CD/DVD-ROM. It is available as a
113 module, called 'hmcdrv', and also as kernel built-in. There is one
114 optional parameter for this module: cachesize=N, which modifies the
115 transfer cache size from it's default value 0.5MB to N bytes. If N
116 is zero, then no caching is performed.
117
105config S390_TAPE 118config S390_TAPE
106 def_tristate m 119 def_tristate m
107 prompt "S/390 tape device support" 120 prompt "S/390 tape device support"
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 78b6ace7edcb..6fa9364d1c07 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -33,3 +33,6 @@ obj-$(CONFIG_S390_VMUR) += vmur.o
33 33
34zcore_mod-objs := sclp_sdias.o zcore.o 34zcore_mod-objs := sclp_sdias.o zcore.o
35obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o 35obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
36
37hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o
38obj-$(CONFIG_HMC_DRV) += hmcdrv.o
diff --git a/drivers/s390/char/diag_ftp.c b/drivers/s390/char/diag_ftp.c
new file mode 100644
index 000000000000..93889632fdf9
--- /dev/null
+++ b/drivers/s390/char/diag_ftp.c
@@ -0,0 +1,237 @@
1/*
2 * DIAGNOSE X'2C4' instruction based HMC FTP services, useable on z/VM
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 *
7 */
8
9#define KMSG_COMPONENT "hmcdrv"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
12#include <linux/kernel.h>
13#include <linux/mm.h>
14#include <linux/irq.h>
15#include <linux/wait.h>
16#include <linux/string.h>
17#include <asm/ctl_reg.h>
18
19#include "hmcdrv_ftp.h"
20#include "diag_ftp.h"
21
22/* DIAGNOSE X'2C4' return codes in Ry */
23#define DIAG_FTP_RET_OK 0 /* HMC FTP started successfully */
24#define DIAG_FTP_RET_EBUSY 4 /* HMC FTP service currently busy */
25#define DIAG_FTP_RET_EIO 8 /* HMC FTP service I/O error */
26/* and an artificial extension */
27#define DIAG_FTP_RET_EPERM 2 /* HMC FTP service privilege error */
28
29/* FTP service status codes (after INTR at guest real location 133) */
30#define DIAG_FTP_STAT_OK 0U /* request completed successfully */
31#define DIAG_FTP_STAT_PGCC 4U /* program check condition */
32#define DIAG_FTP_STAT_PGIOE 8U /* paging I/O error */
33#define DIAG_FTP_STAT_TIMEOUT 12U /* timeout */
34#define DIAG_FTP_STAT_EBASE 16U /* base of error codes from SCLP */
35#define DIAG_FTP_STAT_LDFAIL (DIAG_FTP_STAT_EBASE + 1U) /* failed */
36#define DIAG_FTP_STAT_LDNPERM (DIAG_FTP_STAT_EBASE + 2U) /* not allowed */
37#define DIAG_FTP_STAT_LDRUNS (DIAG_FTP_STAT_EBASE + 3U) /* runs */
38#define DIAG_FTP_STAT_LDNRUNS (DIAG_FTP_STAT_EBASE + 4U) /* not runs */
39
40/**
41 * struct diag_ftp_ldfpl - load file FTP parameter list (LDFPL)
42 * @bufaddr: real buffer address (at 4k boundary)
43 * @buflen: length of buffer
44 * @offset: dir/file offset
45 * @intparm: interruption parameter (unused)
46 * @transferred: bytes transferred
47 * @fsize: file size, filled on GET
48 * @failaddr: failing address
49 * @spare: padding
50 * @fident: file name - ASCII
51 */
52struct diag_ftp_ldfpl {
53 u64 bufaddr;
54 u64 buflen;
55 u64 offset;
56 u64 intparm;
57 u64 transferred;
58 u64 fsize;
59 u64 failaddr;
60 u64 spare;
61 u8 fident[HMCDRV_FTP_FIDENT_MAX];
62} __packed;
63
64static DECLARE_COMPLETION(diag_ftp_rx_complete);
65static int diag_ftp_subcode;
66
67/**
68 * diag_ftp_handler() - FTP services IRQ handler
69 * @extirq: external interrupt (sub-) code
70 * @param32: 32-bit interruption parameter from &struct diag_ftp_ldfpl
71 * @param64: unused (for 64-bit interrupt parameters)
72 */
73static void diag_ftp_handler(struct ext_code extirq,
74 unsigned int param32,
75 unsigned long param64)
76{
77 if ((extirq.subcode >> 8) != 8)
78 return; /* not a FTP services sub-code */
79
80 inc_irq_stat(IRQEXT_FTP);
81 diag_ftp_subcode = extirq.subcode & 0xffU;
82 complete(&diag_ftp_rx_complete);
83}
84
85/**
86 * diag_ftp_2c4() - DIAGNOSE X'2C4' service call
87 * @fpl: pointer to prepared LDFPL
88 * @cmd: FTP command to be executed
89 *
90 * Performs a DIAGNOSE X'2C4' call with (input/output) FTP parameter list
91 * @fpl and FTP function code @cmd. In case of an error the function does
92 * nothing and returns an (negative) error code.
93 *
94 * Notes:
95 * 1. This function only initiates a transfer, so the caller must wait
96 * for completion (asynchronous execution).
97 * 2. The FTP parameter list @fpl must be aligned to a double-word boundary.
98 * 3. fpl->bufaddr must be a real address, 4k aligned
99 */
100static int diag_ftp_2c4(struct diag_ftp_ldfpl *fpl,
101 enum hmcdrv_ftp_cmdid cmd)
102{
103 int rc;
104
105 asm volatile(
106 " diag %[addr],%[cmd],0x2c4\n"
107 "0: j 2f\n"
108 "1: la %[rc],%[err]\n"
109 "2:\n"
110 EX_TABLE(0b, 1b)
111 : [rc] "=d" (rc), "+m" (*fpl)
112 : [cmd] "0" (cmd), [addr] "d" (virt_to_phys(fpl)),
113 [err] "i" (DIAG_FTP_RET_EPERM)
114 : "cc");
115
116 switch (rc) {
117 case DIAG_FTP_RET_OK:
118 return 0;
119 case DIAG_FTP_RET_EBUSY:
120 return -EBUSY;
121 case DIAG_FTP_RET_EPERM:
122 return -EPERM;
123 case DIAG_FTP_RET_EIO:
124 default:
125 return -EIO;
126 }
127}
128
129/**
130 * diag_ftp_cmd() - executes a DIAG X'2C4' FTP command, targeting a HMC
131 * @ftp: pointer to FTP command specification
132 * @fsize: return of file size (or NULL if undesirable)
133 *
134 * Attention: Notice that this function is not reentrant - so the caller
135 * must ensure locking.
136 *
137 * Return: number of bytes read/written or a (negative) error code
138 */
139ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
140{
141 struct diag_ftp_ldfpl *ldfpl;
142 ssize_t len;
143#ifdef DEBUG
144 unsigned long start_jiffies;
145
146 pr_debug("starting DIAG X'2C4' on '%s', requesting %zd bytes\n",
147 ftp->fname, ftp->len);
148 start_jiffies = jiffies;
149#endif
150 init_completion(&diag_ftp_rx_complete);
151
152 ldfpl = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
153 if (!ldfpl) {
154 len = -ENOMEM;
155 goto out;
156 }
157
158 len = strlcpy(ldfpl->fident, ftp->fname, sizeof(ldfpl->fident));
159 if (len >= HMCDRV_FTP_FIDENT_MAX) {
160 len = -EINVAL;
161 goto out_free;
162 }
163
164 ldfpl->transferred = 0;
165 ldfpl->fsize = 0;
166 ldfpl->offset = ftp->ofs;
167 ldfpl->buflen = ftp->len;
168 ldfpl->bufaddr = virt_to_phys(ftp->buf);
169
170 len = diag_ftp_2c4(ldfpl, ftp->id);
171 if (len)
172 goto out_free;
173
174 /*
175 * There is no way to cancel the running diag X'2C4', the code
176 * needs to wait unconditionally until the transfer is complete.
177 */
178 wait_for_completion(&diag_ftp_rx_complete);
179
180#ifdef DEBUG
181 pr_debug("completed DIAG X'2C4' after %lu ms\n",
182 (jiffies - start_jiffies) * 1000 / HZ);
183 pr_debug("status of DIAG X'2C4' is %u, with %lld/%lld bytes\n",
184 diag_ftp_subcode, ldfpl->transferred, ldfpl->fsize);
185#endif
186
187 switch (diag_ftp_subcode) {
188 case DIAG_FTP_STAT_OK: /* success */
189 len = ldfpl->transferred;
190 if (fsize)
191 *fsize = ldfpl->fsize;
192 break;
193 case DIAG_FTP_STAT_LDNPERM:
194 len = -EPERM;
195 break;
196 case DIAG_FTP_STAT_LDRUNS:
197 len = -EBUSY;
198 break;
199 case DIAG_FTP_STAT_LDFAIL:
200 len = -ENOENT; /* no such file or media */
201 break;
202 default:
203 len = -EIO;
204 break;
205 }
206
207out_free:
208 free_page((unsigned long) ldfpl);
209out:
210 return len;
211}
212
213/**
214 * diag_ftp_startup() - startup of FTP services, when running on z/VM
215 *
216 * Return: 0 on success, else an (negative) error code
217 */
218int diag_ftp_startup(void)
219{
220 int rc;
221
222 rc = register_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
223 if (rc)
224 return rc;
225
226 ctl_set_bit(0, 63 - 22);
227 return 0;
228}
229
230/**
231 * diag_ftp_shutdown() - shutdown of FTP services, when running on z/VM
232 */
233void diag_ftp_shutdown(void)
234{
235 ctl_clear_bit(0, 63 - 22);
236 unregister_external_irq(EXT_IRQ_CP_SERVICE, diag_ftp_handler);
237}
diff --git a/drivers/s390/char/diag_ftp.h b/drivers/s390/char/diag_ftp.h
new file mode 100644
index 000000000000..3abd2614053a
--- /dev/null
+++ b/drivers/s390/char/diag_ftp.h
@@ -0,0 +1,21 @@
1/*
2 * DIAGNOSE X'2C4' instruction based SE/HMC FTP Services, useable on z/VM
3 *
4 * Notice that all functions exported here are not reentrant.
5 * So usage should be exclusive, ensured by the caller (e.g. using a
6 * mutex).
7 *
8 * Copyright IBM Corp. 2013
9 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
10 */
11
12#ifndef __DIAG_FTP_H__
13#define __DIAG_FTP_H__
14
15#include "hmcdrv_ftp.h"
16
17int diag_ftp_startup(void);
18void diag_ftp_shutdown(void);
19ssize_t diag_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize);
20
21#endif /* __DIAG_FTP_H__ */
diff --git a/drivers/s390/char/hmcdrv_cache.c b/drivers/s390/char/hmcdrv_cache.c
new file mode 100644
index 000000000000..4cda5ada143a
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_cache.c
@@ -0,0 +1,252 @@
1/*
2 * SE/HMC Drive (Read) Cache Functions
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 *
7 */
8
9#define KMSG_COMPONENT "hmcdrv"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
12#include <linux/kernel.h>
13#include <linux/mm.h>
14#include <linux/jiffies.h>
15
16#include "hmcdrv_ftp.h"
17#include "hmcdrv_cache.h"
18
19#define HMCDRV_CACHE_TIMEOUT 30 /* aging timeout in seconds */
20
21/**
22 * struct hmcdrv_cache_entry - file cache (only used on read/dir)
23 * @id: FTP command ID
24 * @content: kernel-space buffer, 4k aligned
25 * @len: size of @content cache (0 if caching disabled)
26 * @ofs: start of content within file (-1 if no cached content)
27 * @fname: file name
28 * @fsize: file size
29 * @timeout: cache timeout in jiffies
30 *
31 * Notice that the first three members (id, fname, fsize) are cached on all
32 * read/dir requests. But content is cached only under some preconditions.
33 * Uncached content is signalled by a negative value of @ofs.
34 */
35struct hmcdrv_cache_entry {
36 enum hmcdrv_ftp_cmdid id;
37 char fname[HMCDRV_FTP_FIDENT_MAX];
38 size_t fsize;
39 loff_t ofs;
40 unsigned long timeout;
41 void *content;
42 size_t len;
43};
44
45static int hmcdrv_cache_order; /* cache allocated page order */
46
47static struct hmcdrv_cache_entry hmcdrv_cache_file = {
48 .fsize = SIZE_MAX,
49 .ofs = -1,
50 .len = 0,
51 .fname = {'\0'}
52};
53
54/**
55 * hmcdrv_cache_get() - looks for file data/content in read cache
56 * @ftp: pointer to FTP command specification
57 *
58 * Return: number of bytes read from cache or a negative number if nothing
59 * in content cache (for the file/cmd specified in @ftp)
60 */
61static ssize_t hmcdrv_cache_get(const struct hmcdrv_ftp_cmdspec *ftp)
62{
63 loff_t pos; /* position in cache (signed) */
64 ssize_t len;
65
66 if ((ftp->id != hmcdrv_cache_file.id) ||
67 strcmp(hmcdrv_cache_file.fname, ftp->fname))
68 return -1;
69
70 if (ftp->ofs >= hmcdrv_cache_file.fsize) /* EOF ? */
71 return 0;
72
73 if ((hmcdrv_cache_file.ofs < 0) || /* has content? */
74 time_after(jiffies, hmcdrv_cache_file.timeout))
75 return -1;
76
77 /* there seems to be cached content - calculate the maximum number
78 * of bytes that can be returned (regarding file size and offset)
79 */
80 len = hmcdrv_cache_file.fsize - ftp->ofs;
81
82 if (len > ftp->len)
83 len = ftp->len;
84
85 /* check if the requested chunk falls into our cache (which starts
86 * at offset 'hmcdrv_cache_file.ofs' in the file of interest)
87 */
88 pos = ftp->ofs - hmcdrv_cache_file.ofs;
89
90 if ((pos >= 0) &&
91 ((pos + len) <= hmcdrv_cache_file.len)) {
92
93 memcpy(ftp->buf,
94 hmcdrv_cache_file.content + pos,
95 len);
96 pr_debug("using cached content of '%s', returning %zd/%zd bytes\n",
97 hmcdrv_cache_file.fname, len,
98 hmcdrv_cache_file.fsize);
99
100 return len;
101 }
102
103 return -1;
104}
105
106/**
107 * hmcdrv_cache_do() - do a HMC drive CD/DVD transfer with cache update
108 * @ftp: pointer to FTP command specification
109 * @func: FTP transfer function to be used
110 *
111 * Return: number of bytes read/written or a (negative) error code
112 */
113static ssize_t hmcdrv_cache_do(const struct hmcdrv_ftp_cmdspec *ftp,
114 hmcdrv_cache_ftpfunc func)
115{
116 ssize_t len;
117
118 /* only cache content if the read/dir cache really exists
119 * (hmcdrv_cache_file.len > 0), is large enough to handle the
120 * request (hmcdrv_cache_file.len >= ftp->len) and there is a need
121 * to do so (ftp->len > 0)
122 */
123 if ((ftp->len > 0) && (hmcdrv_cache_file.len >= ftp->len)) {
124
125 /* because the cache is not located at ftp->buf, we have to
126 * assemble a new HMC drive FTP cmd specification (pointing
127 * to our cache, and using the increased size)
128 */
129 struct hmcdrv_ftp_cmdspec cftp = *ftp; /* make a copy */
130 cftp.buf = hmcdrv_cache_file.content; /* and update */
131 cftp.len = hmcdrv_cache_file.len; /* buffer data */
132
133 len = func(&cftp, &hmcdrv_cache_file.fsize); /* now do */
134
135 if (len > 0) {
136 pr_debug("caching %zd bytes content for '%s'\n",
137 len, ftp->fname);
138
139 if (len > ftp->len)
140 len = ftp->len;
141
142 hmcdrv_cache_file.ofs = ftp->ofs;
143 hmcdrv_cache_file.timeout = jiffies +
144 HMCDRV_CACHE_TIMEOUT * HZ;
145 memcpy(ftp->buf, hmcdrv_cache_file.content, len);
146 }
147 } else {
148 len = func(ftp, &hmcdrv_cache_file.fsize);
149 hmcdrv_cache_file.ofs = -1; /* invalidate content */
150 }
151
152 if (len > 0) {
153 /* cache some file info (FTP command, file name and file
154 * size) unconditionally
155 */
156 strlcpy(hmcdrv_cache_file.fname, ftp->fname,
157 HMCDRV_FTP_FIDENT_MAX);
158 hmcdrv_cache_file.id = ftp->id;
159 pr_debug("caching cmd %d, file size %zu for '%s'\n",
160 ftp->id, hmcdrv_cache_file.fsize, ftp->fname);
161 }
162
163 return len;
164}
165
166/**
167 * hmcdrv_cache_cmd() - perform a cached HMC drive CD/DVD transfer
168 * @ftp: pointer to FTP command specification
169 * @func: FTP transfer function to be used
170 *
171 * Attention: Notice that this function is not reentrant - so the caller
172 * must ensure exclusive execution.
173 *
174 * Return: number of bytes read/written or a (negative) error code
175 */
176ssize_t hmcdrv_cache_cmd(const struct hmcdrv_ftp_cmdspec *ftp,
177 hmcdrv_cache_ftpfunc func)
178{
179 ssize_t len;
180
181 if ((ftp->id == HMCDRV_FTP_DIR) || /* read cache */
182 (ftp->id == HMCDRV_FTP_NLIST) ||
183 (ftp->id == HMCDRV_FTP_GET)) {
184
185 len = hmcdrv_cache_get(ftp);
186
187 if (len >= 0) /* got it from cache ? */
188 return len; /* yes */
189
190 len = hmcdrv_cache_do(ftp, func);
191
192 if (len >= 0)
193 return len;
194
195 } else {
196 len = func(ftp, NULL); /* simply do original command */
197 }
198
199 /* invalidate the (read) cache in case there was a write operation
200 * or an error on read/dir
201 */
202 hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
203 hmcdrv_cache_file.fsize = LLONG_MAX;
204 hmcdrv_cache_file.ofs = -1;
205
206 return len;
207}
208
209/**
210 * hmcdrv_cache_startup() - startup of HMC drive cache
211 * @cachesize: cache size
212 *
213 * Return: 0 on success, else a (negative) error code
214 */
215int hmcdrv_cache_startup(size_t cachesize)
216{
217 if (cachesize > 0) { /* perform caching ? */
218 hmcdrv_cache_order = get_order(cachesize);
219 hmcdrv_cache_file.content =
220 (void *) __get_free_pages(GFP_KERNEL | GFP_DMA,
221 hmcdrv_cache_order);
222
223 if (!hmcdrv_cache_file.content) {
224 pr_err("Allocating the requested cache size of %zu bytes failed\n",
225 cachesize);
226 return -ENOMEM;
227 }
228
229 pr_debug("content cache enabled, size is %zu bytes\n",
230 cachesize);
231 }
232
233 hmcdrv_cache_file.len = cachesize;
234 return 0;
235}
236
237/**
238 * hmcdrv_cache_shutdown() - shutdown of HMC drive cache
239 */
240void hmcdrv_cache_shutdown(void)
241{
242 if (hmcdrv_cache_file.content) {
243 free_pages((unsigned long) hmcdrv_cache_file.content,
244 hmcdrv_cache_order);
245 hmcdrv_cache_file.content = NULL;
246 }
247
248 hmcdrv_cache_file.id = HMCDRV_FTP_NOOP;
249 hmcdrv_cache_file.fsize = LLONG_MAX;
250 hmcdrv_cache_file.ofs = -1;
251 hmcdrv_cache_file.len = 0; /* no cache */
252}
diff --git a/drivers/s390/char/hmcdrv_cache.h b/drivers/s390/char/hmcdrv_cache.h
new file mode 100644
index 000000000000..a14b57526781
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_cache.h
@@ -0,0 +1,24 @@
1/*
2 * SE/HMC Drive (Read) Cache Functions
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 */
7
8#ifndef __HMCDRV_CACHE_H__
9#define __HMCDRV_CACHE_H__
10
11#include <linux/mmzone.h>
12#include "hmcdrv_ftp.h"
13
14#define HMCDRV_CACHE_SIZE_DFLT (MAX_ORDER_NR_PAGES * PAGE_SIZE / 2UL)
15
16typedef ssize_t (*hmcdrv_cache_ftpfunc)(const struct hmcdrv_ftp_cmdspec *ftp,
17 size_t *fsize);
18
19ssize_t hmcdrv_cache_cmd(const struct hmcdrv_ftp_cmdspec *ftp,
20 hmcdrv_cache_ftpfunc func);
21int hmcdrv_cache_startup(size_t cachesize);
22void hmcdrv_cache_shutdown(void);
23
24#endif /* __HMCDRV_CACHE_H__ */
diff --git a/drivers/s390/char/hmcdrv_dev.c b/drivers/s390/char/hmcdrv_dev.c
new file mode 100644
index 000000000000..0c5176179c17
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_dev.c
@@ -0,0 +1,370 @@
1/*
2 * HMC Drive CD/DVD Device
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 *
7 * This file provides a Linux "misc" character device for access to an
8 * assigned HMC drive CD/DVD-ROM. It works as follows: First create the
9 * device by calling hmcdrv_dev_init(). After open() a lseek(fd, 0,
10 * SEEK_END) indicates that a new FTP command follows (not needed on the
11 * first command after open). Then write() the FTP command ASCII string
12 * to it, e.g. "dir /" or "nls <directory>" or "get <filename>". At the
13 * end read() the response.
14 */
15
16#define KMSG_COMPONENT "hmcdrv"
17#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/fs.h>
23#include <linux/cdev.h>
24#include <linux/miscdevice.h>
25#include <linux/device.h>
26#include <linux/capability.h>
27#include <linux/delay.h>
28#include <linux/uaccess.h>
29
30#include "hmcdrv_dev.h"
31#include "hmcdrv_ftp.h"
32
33/* If the following macro is defined, then the HMC device creates it's own
34 * separated device class (and dynamically assigns a major number). If not
35 * defined then the HMC device is assigned to the "misc" class devices.
36 *
37#define HMCDRV_DEV_CLASS "hmcftp"
38 */
39
40#define HMCDRV_DEV_NAME "hmcdrv"
41#define HMCDRV_DEV_BUSY_DELAY 500 /* delay between -EBUSY trials in ms */
42#define HMCDRV_DEV_BUSY_RETRIES 3 /* number of retries on -EBUSY */
43
44struct hmcdrv_dev_node {
45
46#ifdef HMCDRV_DEV_CLASS
47 struct cdev dev; /* character device structure */
48 umode_t mode; /* mode of device node (unused, zero) */
49#else
50 struct miscdevice dev; /* "misc" device structure */
51#endif
52
53};
54
55static int hmcdrv_dev_open(struct inode *inode, struct file *fp);
56static int hmcdrv_dev_release(struct inode *inode, struct file *fp);
57static loff_t hmcdrv_dev_seek(struct file *fp, loff_t pos, int whence);
58static ssize_t hmcdrv_dev_read(struct file *fp, char __user *ubuf,
59 size_t len, loff_t *pos);
60static ssize_t hmcdrv_dev_write(struct file *fp, const char __user *ubuf,
61 size_t len, loff_t *pos);
62static ssize_t hmcdrv_dev_transfer(char __kernel *cmd, loff_t offset,
63 char __user *buf, size_t len);
64
65/*
66 * device operations
67 */
68static const struct file_operations hmcdrv_dev_fops = {
69 .open = hmcdrv_dev_open,
70 .llseek = hmcdrv_dev_seek,
71 .release = hmcdrv_dev_release,
72 .read = hmcdrv_dev_read,
73 .write = hmcdrv_dev_write,
74};
75
76static struct hmcdrv_dev_node hmcdrv_dev; /* HMC device struct (static) */
77
78#ifdef HMCDRV_DEV_CLASS
79
80static struct class *hmcdrv_dev_class; /* device class pointer */
81static dev_t hmcdrv_dev_no; /* device number (major/minor) */
82
83/**
84 * hmcdrv_dev_name() - provides a naming hint for a device node in /dev
85 * @dev: device for which the naming/mode hint is
86 * @mode: file mode for device node created in /dev
87 *
88 * See: devtmpfs.c, function devtmpfs_create_node()
89 *
90 * Return: recommended device file name in /dev
91 */
92static char *hmcdrv_dev_name(struct device *dev, umode_t *mode)
93{
94 char *nodename = NULL;
95 const char *devname = dev_name(dev); /* kernel device name */
96
97 if (devname)
98 nodename = kasprintf(GFP_KERNEL, "%s", devname);
99
100 /* on device destroy (rmmod) the mode pointer may be NULL
101 */
102 if (mode)
103 *mode = hmcdrv_dev.mode;
104
105 return nodename;
106}
107
108#endif /* HMCDRV_DEV_CLASS */
109
110/*
111 * open()
112 */
113static int hmcdrv_dev_open(struct inode *inode, struct file *fp)
114{
115 int rc;
116
117 /* check for non-blocking access, which is really unsupported
118 */
119 if (fp->f_flags & O_NONBLOCK)
120 return -EINVAL;
121
122 /* Because it makes no sense to open this device read-only (then a
123 * FTP command cannot be emitted), we respond with an error.
124 */
125 if ((fp->f_flags & O_ACCMODE) == O_RDONLY)
126 return -EINVAL;
127
128 /* prevent unloading this module as long as anyone holds the
129 * device file open - so increment the reference count here
130 */
131 if (!try_module_get(THIS_MODULE))
132 return -ENODEV;
133
134 fp->private_data = NULL; /* no command yet */
135 rc = hmcdrv_ftp_startup();
136 if (rc)
137 module_put(THIS_MODULE);
138
139 pr_debug("open file '/dev/%s' with return code %d\n",
140 fp->f_dentry->d_name.name, rc);
141 return rc;
142}
143
144/*
145 * release()
146 */
147static int hmcdrv_dev_release(struct inode *inode, struct file *fp)
148{
149 pr_debug("closing file '/dev/%s'\n", fp->f_dentry->d_name.name);
150 kfree(fp->private_data);
151 fp->private_data = NULL;
152 hmcdrv_ftp_shutdown();
153 module_put(THIS_MODULE);
154 return 0;
155}
156
157/*
158 * lseek()
159 */
160static loff_t hmcdrv_dev_seek(struct file *fp, loff_t pos, int whence)
161{
162 switch (whence) {
163 case SEEK_CUR: /* relative to current file position */
164 pos += fp->f_pos; /* new position stored in 'pos' */
165 break;
166
167 case SEEK_SET: /* absolute (relative to beginning of file) */
168 break; /* SEEK_SET */
169
170 /* We use SEEK_END as a special indicator for a SEEK_SET
171 * (set absolute position), combined with a FTP command
172 * clear.
173 */
174 case SEEK_END:
175 if (fp->private_data) {
176 kfree(fp->private_data);
177 fp->private_data = NULL;
178 }
179
180 break; /* SEEK_END */
181
182 default: /* SEEK_DATA, SEEK_HOLE: unsupported */
183 return -EINVAL;
184 }
185
186 if (pos < 0)
187 return -EINVAL;
188
189 if (fp->f_pos != pos)
190 ++fp->f_version;
191
192 fp->f_pos = pos;
193 return pos;
194}
195
196/*
197 * transfer (helper function)
198 */
199static ssize_t hmcdrv_dev_transfer(char __kernel *cmd, loff_t offset,
200 char __user *buf, size_t len)
201{
202 ssize_t retlen;
203 unsigned trials = HMCDRV_DEV_BUSY_RETRIES;
204
205 do {
206 retlen = hmcdrv_ftp_cmd(cmd, offset, buf, len);
207
208 if (retlen != -EBUSY)
209 break;
210
211 msleep(HMCDRV_DEV_BUSY_DELAY);
212
213 } while (--trials > 0);
214
215 return retlen;
216}
217
218/*
219 * read()
220 */
221static ssize_t hmcdrv_dev_read(struct file *fp, char __user *ubuf,
222 size_t len, loff_t *pos)
223{
224 ssize_t retlen;
225
226 if (((fp->f_flags & O_ACCMODE) == O_WRONLY) ||
227 (fp->private_data == NULL)) { /* no FTP cmd defined ? */
228 return -EBADF;
229 }
230
231 retlen = hmcdrv_dev_transfer((char *) fp->private_data,
232 *pos, ubuf, len);
233
234 pr_debug("read from file '/dev/%s' at %lld returns %zd/%zu\n",
235 fp->f_dentry->d_name.name, (long long) *pos, retlen, len);
236
237 if (retlen > 0)
238 *pos += retlen;
239
240 return retlen;
241}
242
243/*
244 * write()
245 */
246static ssize_t hmcdrv_dev_write(struct file *fp, const char __user *ubuf,
247 size_t len, loff_t *pos)
248{
249 ssize_t retlen;
250
251 pr_debug("writing file '/dev/%s' at pos. %lld with length %zd\n",
252 fp->f_dentry->d_name.name, (long long) *pos, len);
253
254 if (!fp->private_data) { /* first expect a cmd write */
255 fp->private_data = kmalloc(len + 1, GFP_KERNEL);
256
257 if (!fp->private_data)
258 return -ENOMEM;
259
260 if (!copy_from_user(fp->private_data, ubuf, len)) {
261 ((char *)fp->private_data)[len] = '\0';
262 return len;
263 }
264
265 kfree(fp->private_data);
266 fp->private_data = NULL;
267 return -EFAULT;
268 }
269
270 retlen = hmcdrv_dev_transfer((char *) fp->private_data,
271 *pos, (char __user *) ubuf, len);
272 if (retlen > 0)
273 *pos += retlen;
274
275 pr_debug("write to file '/dev/%s' returned %zd\n",
276 fp->f_dentry->d_name.name, retlen);
277
278 return retlen;
279}
280
281/**
282 * hmcdrv_dev_init() - creates a HMC drive CD/DVD device
283 *
284 * This function creates a HMC drive CD/DVD kernel device and an associated
285 * device under /dev, using a dynamically allocated major number.
286 *
287 * Return: 0 on success, else an error code.
288 */
289int hmcdrv_dev_init(void)
290{
291 int rc;
292
293#ifdef HMCDRV_DEV_CLASS
294 struct device *dev;
295
296 rc = alloc_chrdev_region(&hmcdrv_dev_no, 0, 1, HMCDRV_DEV_NAME);
297
298 if (rc)
299 goto out_err;
300
301 cdev_init(&hmcdrv_dev.dev, &hmcdrv_dev_fops);
302 hmcdrv_dev.dev.owner = THIS_MODULE;
303 rc = cdev_add(&hmcdrv_dev.dev, hmcdrv_dev_no, 1);
304
305 if (rc)
306 goto out_unreg;
307
308 /* At this point the character device exists in the kernel (see
309 * /proc/devices), but not under /dev nor /sys/devices/virtual. So
310 * we have to create an associated class (see /sys/class).
311 */
312 hmcdrv_dev_class = class_create(THIS_MODULE, HMCDRV_DEV_CLASS);
313
314 if (IS_ERR(hmcdrv_dev_class)) {
315 rc = PTR_ERR(hmcdrv_dev_class);
316 goto out_devdel;
317 }
318
319 /* Finally a device node in /dev has to be established (as 'mkdev'
320 * does from the command line). Notice that assignment of a device
321 * node name/mode function is optional (only for mode != 0600).
322 */
323 hmcdrv_dev.mode = 0; /* "unset" */
324 hmcdrv_dev_class->devnode = hmcdrv_dev_name;
325
326 dev = device_create(hmcdrv_dev_class, NULL, hmcdrv_dev_no, NULL,
327 "%s", HMCDRV_DEV_NAME);
328 if (!IS_ERR(dev))
329 return 0;
330
331 rc = PTR_ERR(dev);
332 class_destroy(hmcdrv_dev_class);
333 hmcdrv_dev_class = NULL;
334
335out_devdel:
336 cdev_del(&hmcdrv_dev.dev);
337
338out_unreg:
339 unregister_chrdev_region(hmcdrv_dev_no, 1);
340
341out_err:
342
343#else /* !HMCDRV_DEV_CLASS */
344 hmcdrv_dev.dev.minor = MISC_DYNAMIC_MINOR;
345 hmcdrv_dev.dev.name = HMCDRV_DEV_NAME;
346 hmcdrv_dev.dev.fops = &hmcdrv_dev_fops;
347 hmcdrv_dev.dev.mode = 0; /* finally produces 0600 */
348 rc = misc_register(&hmcdrv_dev.dev);
349#endif /* HMCDRV_DEV_CLASS */
350
351 return rc;
352}
353
354/**
355 * hmcdrv_dev_exit() - destroys a HMC drive CD/DVD device
356 */
357void hmcdrv_dev_exit(void)
358{
359#ifdef HMCDRV_DEV_CLASS
360 if (!IS_ERR_OR_NULL(hmcdrv_dev_class)) {
361 device_destroy(hmcdrv_dev_class, hmcdrv_dev_no);
362 class_destroy(hmcdrv_dev_class);
363 }
364
365 cdev_del(&hmcdrv_dev.dev);
366 unregister_chrdev_region(hmcdrv_dev_no, 1);
367#else /* !HMCDRV_DEV_CLASS */
368 misc_deregister(&hmcdrv_dev.dev);
369#endif /* HMCDRV_DEV_CLASS */
370}
diff --git a/drivers/s390/char/hmcdrv_dev.h b/drivers/s390/char/hmcdrv_dev.h
new file mode 100644
index 000000000000..cb17f07e02de
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_dev.h
@@ -0,0 +1,14 @@
1/*
2 * SE/HMC Drive FTP Device
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 */
7
8#ifndef __HMCDRV_DEV_H__
9#define __HMCDRV_DEV_H__
10
11int hmcdrv_dev_init(void);
12void hmcdrv_dev_exit(void);
13
14#endif /* __HMCDRV_DEV_H__ */
diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c
new file mode 100644
index 000000000000..4bd63322fc29
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_ftp.c
@@ -0,0 +1,343 @@
1/*
2 * HMC Drive FTP Services
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 */
7
8#define KMSG_COMPONENT "hmcdrv"
9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/uaccess.h>
14#include <linux/export.h>
15
16#include <linux/ctype.h>
17#include <linux/crc16.h>
18
19#include "hmcdrv_ftp.h"
20#include "hmcdrv_cache.h"
21#include "sclp_ftp.h"
22#include "diag_ftp.h"
23
24/**
25 * struct hmcdrv_ftp_ops - HMC drive FTP operations
26 * @startup: startup function
27 * @shutdown: shutdown function
28 * @cmd: FTP transfer function
29 */
30struct hmcdrv_ftp_ops {
31 int (*startup)(void);
32 void (*shutdown)(void);
33 ssize_t (*transfer)(const struct hmcdrv_ftp_cmdspec *ftp,
34 size_t *fsize);
35};
36
37static enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len);
38static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp);
39
40static struct hmcdrv_ftp_ops *hmcdrv_ftp_funcs; /* current operations */
41static DEFINE_MUTEX(hmcdrv_ftp_mutex); /* mutex for hmcdrv_ftp_funcs */
42static unsigned hmcdrv_ftp_refcnt; /* start/shutdown reference counter */
43
44/**
45 * hmcdrv_ftp_cmd_getid() - determine FTP command ID from a command string
46 * @cmd: FTP command string (NOT zero-terminated)
47 * @len: length of FTP command string in @cmd
48 */
49static enum hmcdrv_ftp_cmdid hmcdrv_ftp_cmd_getid(const char *cmd, int len)
50{
51 /* HMC FTP command descriptor */
52 struct hmcdrv_ftp_cmd_desc {
53 const char *str; /* command string */
54 enum hmcdrv_ftp_cmdid cmd; /* associated command as enum */
55 };
56
57 /* Description of all HMC drive FTP commands
58 *
59 * Notes:
60 * 1. Array size should be a prime number.
61 * 2. Do not change the order of commands in table (because the
62 * index is determined by CRC % ARRAY_SIZE).
63 * 3. Original command 'nlist' was renamed, else the CRC would
64 * collide with 'append' (see point 2).
65 */
66 static const struct hmcdrv_ftp_cmd_desc ftpcmds[7] = {
67
68 {.str = "get", /* [0] get (CRC = 0x68eb) */
69 .cmd = HMCDRV_FTP_GET},
70 {.str = "dir", /* [1] dir (CRC = 0x6a9e) */
71 .cmd = HMCDRV_FTP_DIR},
72 {.str = "delete", /* [2] delete (CRC = 0x53ae) */
73 .cmd = HMCDRV_FTP_DELETE},
74 {.str = "nls", /* [3] nls (CRC = 0xf87c) */
75 .cmd = HMCDRV_FTP_NLIST},
76 {.str = "put", /* [4] put (CRC = 0xac56) */
77 .cmd = HMCDRV_FTP_PUT},
78 {.str = "append", /* [5] append (CRC = 0xf56e) */
79 .cmd = HMCDRV_FTP_APPEND},
80 {.str = NULL} /* [6] unused */
81 };
82
83 const struct hmcdrv_ftp_cmd_desc *pdesc;
84
85 u16 crc = 0xffffU;
86
87 if (len == 0)
88 return HMCDRV_FTP_NOOP; /* error indiactor */
89
90 crc = crc16(crc, cmd, len);
91 pdesc = ftpcmds + (crc % ARRAY_SIZE(ftpcmds));
92 pr_debug("FTP command '%s' has CRC 0x%04x, at table pos. %lu\n",
93 cmd, crc, (crc % ARRAY_SIZE(ftpcmds)));
94
95 if (!pdesc->str || strncmp(pdesc->str, cmd, len))
96 return HMCDRV_FTP_NOOP;
97
98 pr_debug("FTP command '%s' found, with ID %d\n",
99 pdesc->str, pdesc->cmd);
100
101 return pdesc->cmd;
102}
103
104/**
105 * hmcdrv_ftp_parse() - HMC drive FTP command parser
106 * @cmd: FTP command string "<cmd> <filename>"
107 * @ftp: Pointer to FTP command specification buffer (output)
108 *
109 * Return: 0 on success, else a (negative) error code
110 */
111static int hmcdrv_ftp_parse(char *cmd, struct hmcdrv_ftp_cmdspec *ftp)
112{
113 char *start;
114 int argc = 0;
115
116 ftp->id = HMCDRV_FTP_NOOP;
117 ftp->fname = NULL;
118
119 while (*cmd != '\0') {
120
121 while (isspace(*cmd))
122 ++cmd;
123
124 if (*cmd == '\0')
125 break;
126
127 start = cmd;
128
129 switch (argc) {
130 case 0: /* 1st argument (FTP command) */
131 while ((*cmd != '\0') && !isspace(*cmd))
132 ++cmd;
133 ftp->id = hmcdrv_ftp_cmd_getid(start, cmd - start);
134 break;
135 case 1: /* 2nd / last argument (rest of line) */
136 while ((*cmd != '\0') && !iscntrl(*cmd))
137 ++cmd;
138 ftp->fname = start;
139 /* fall through */
140 default:
141 *cmd = '\0';
142 break;
143 } /* switch */
144
145 ++argc;
146 } /* while */
147
148 if (!ftp->fname || (ftp->id == HMCDRV_FTP_NOOP))
149 return -EINVAL;
150
151 return 0;
152}
153
154/**
155 * hmcdrv_ftp_do() - perform a HMC drive FTP, with data from kernel-space
156 * @ftp: pointer to FTP command specification
157 *
158 * Return: number of bytes read/written or a negative error code
159 */
160ssize_t hmcdrv_ftp_do(const struct hmcdrv_ftp_cmdspec *ftp)
161{
162 ssize_t len;
163
164 mutex_lock(&hmcdrv_ftp_mutex);
165
166 if (hmcdrv_ftp_funcs && hmcdrv_ftp_refcnt) {
167 pr_debug("starting transfer, cmd %d for '%s' at %lld with %zd bytes\n",
168 ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);
169 len = hmcdrv_cache_cmd(ftp, hmcdrv_ftp_funcs->transfer);
170 } else {
171 len = -ENXIO;
172 }
173
174 mutex_unlock(&hmcdrv_ftp_mutex);
175 return len;
176}
177EXPORT_SYMBOL(hmcdrv_ftp_do);
178
179/**
180 * hmcdrv_ftp_probe() - probe for the HMC drive FTP service
181 *
182 * Return: 0 if service is available, else an (negative) error code
183 */
184int hmcdrv_ftp_probe(void)
185{
186 int rc;
187
188 struct hmcdrv_ftp_cmdspec ftp = {
189 .id = HMCDRV_FTP_NOOP,
190 .ofs = 0,
191 .fname = "",
192 .len = PAGE_SIZE
193 };
194
195 ftp.buf = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
196
197 if (!ftp.buf)
198 return -ENOMEM;
199
200 rc = hmcdrv_ftp_startup();
201
202 if (rc)
203 return rc;
204
205 rc = hmcdrv_ftp_do(&ftp);
206 free_page((unsigned long) ftp.buf);
207 hmcdrv_ftp_shutdown();
208
209 switch (rc) {
210 case -ENOENT: /* no such file/media or currently busy, */
211 case -EBUSY: /* but service seems to be available */
212 rc = 0;
213 break;
214 default: /* leave 'rc' as it is for [0, -EPERM, -E...] */
215 if (rc > 0)
216 rc = 0; /* clear length (success) */
217 break;
218 } /* switch */
219
220 return rc;
221}
222EXPORT_SYMBOL(hmcdrv_ftp_probe);
223
224/**
225 * hmcdrv_ftp_cmd() - Perform a HMC drive FTP, with data from user-space
226 *
227 * @cmd: FTP command string "<cmd> <filename>"
228 * @offset: file position to read/write
229 * @buf: user-space buffer for read/written directory/file
230 * @len: size of @buf (read/dir) or number of bytes to write
231 *
232 * This function must not be called before hmcdrv_ftp_startup() was called.
233 *
234 * Return: number of bytes read/written or a negative error code
235 */
236ssize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset,
237 char __user *buf, size_t len)
238{
239 int order;
240
241 struct hmcdrv_ftp_cmdspec ftp = {.len = len, .ofs = offset};
242 ssize_t retlen = hmcdrv_ftp_parse(cmd, &ftp);
243
244 if (retlen)
245 return retlen;
246
247 order = get_order(ftp.len);
248 ftp.buf = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, order);
249
250 if (!ftp.buf)
251 return -ENOMEM;
252
253 switch (ftp.id) {
254 case HMCDRV_FTP_DIR:
255 case HMCDRV_FTP_NLIST:
256 case HMCDRV_FTP_GET:
257 retlen = hmcdrv_ftp_do(&ftp);
258
259 if ((retlen >= 0) &&
260 copy_to_user(buf, ftp.buf, retlen))
261 retlen = -EFAULT;
262 break;
263
264 case HMCDRV_FTP_PUT:
265 case HMCDRV_FTP_APPEND:
266 if (!copy_from_user(ftp.buf, buf, ftp.len))
267 retlen = hmcdrv_ftp_do(&ftp);
268 else
269 retlen = -EFAULT;
270 break;
271
272 case HMCDRV_FTP_DELETE:
273 retlen = hmcdrv_ftp_do(&ftp);
274 break;
275
276 default:
277 retlen = -EOPNOTSUPP;
278 break;
279 }
280
281 free_pages((unsigned long) ftp.buf, order);
282 return retlen;
283}
284
285/**
286 * hmcdrv_ftp_startup() - startup of HMC drive FTP functionality for a
287 * dedicated (owner) instance
288 *
289 * Return: 0 on success, else an (negative) error code
290 */
291int hmcdrv_ftp_startup(void)
292{
293 static struct hmcdrv_ftp_ops hmcdrv_ftp_zvm = {
294 .startup = diag_ftp_startup,
295 .shutdown = diag_ftp_shutdown,
296 .transfer = diag_ftp_cmd
297 };
298
299 static struct hmcdrv_ftp_ops hmcdrv_ftp_lpar = {
300 .startup = sclp_ftp_startup,
301 .shutdown = sclp_ftp_shutdown,
302 .transfer = sclp_ftp_cmd
303 };
304
305 int rc = 0;
306
307 mutex_lock(&hmcdrv_ftp_mutex); /* block transfers while start-up */
308
309 if (hmcdrv_ftp_refcnt == 0) {
310 if (MACHINE_IS_VM)
311 hmcdrv_ftp_funcs = &hmcdrv_ftp_zvm;
312 else if (MACHINE_IS_LPAR || MACHINE_IS_KVM)
313 hmcdrv_ftp_funcs = &hmcdrv_ftp_lpar;
314 else
315 rc = -EOPNOTSUPP;
316
317 if (hmcdrv_ftp_funcs)
318 rc = hmcdrv_ftp_funcs->startup();
319 }
320
321 if (!rc)
322 ++hmcdrv_ftp_refcnt;
323
324 mutex_unlock(&hmcdrv_ftp_mutex);
325 return rc;
326}
327EXPORT_SYMBOL(hmcdrv_ftp_startup);
328
329/**
330 * hmcdrv_ftp_shutdown() - shutdown of HMC drive FTP functionality for a
331 * dedicated (owner) instance
332 */
333void hmcdrv_ftp_shutdown(void)
334{
335 mutex_lock(&hmcdrv_ftp_mutex);
336 --hmcdrv_ftp_refcnt;
337
338 if ((hmcdrv_ftp_refcnt == 0) && hmcdrv_ftp_funcs)
339 hmcdrv_ftp_funcs->shutdown();
340
341 mutex_unlock(&hmcdrv_ftp_mutex);
342}
343EXPORT_SYMBOL(hmcdrv_ftp_shutdown);
diff --git a/drivers/s390/char/hmcdrv_ftp.h b/drivers/s390/char/hmcdrv_ftp.h
new file mode 100644
index 000000000000..f3643a7b3676
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_ftp.h
@@ -0,0 +1,63 @@
1/*
2 * SE/HMC Drive FTP Services
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 */
7
8#ifndef __HMCDRV_FTP_H__
9#define __HMCDRV_FTP_H__
10
11#include <linux/types.h> /* size_t, loff_t */
12
13/*
14 * HMC drive FTP Service max. length of path (w/ EOS)
15 */
16#define HMCDRV_FTP_FIDENT_MAX 192
17
18/**
19 * enum hmcdrv_ftp_cmdid - HMC drive FTP commands
20 * @HMCDRV_FTP_NOOP: do nothing (only for probing)
21 * @HMCDRV_FTP_GET: read a file
22 * @HMCDRV_FTP_PUT: (over-) write a file
23 * @HMCDRV_FTP_APPEND: append to a file
24 * @HMCDRV_FTP_DIR: list directory long (ls -l)
25 * @HMCDRV_FTP_NLIST: list files, no directories (name list)
26 * @HMCDRV_FTP_DELETE: delete a file
27 * @HMCDRV_FTP_CANCEL: cancel operation (SCLP/LPAR only)
28 */
29enum hmcdrv_ftp_cmdid {
30 HMCDRV_FTP_NOOP = 0,
31 HMCDRV_FTP_GET = 1,
32 HMCDRV_FTP_PUT = 2,
33 HMCDRV_FTP_APPEND = 3,
34 HMCDRV_FTP_DIR = 4,
35 HMCDRV_FTP_NLIST = 5,
36 HMCDRV_FTP_DELETE = 6,
37 HMCDRV_FTP_CANCEL = 7
38};
39
40/**
41 * struct hmcdrv_ftp_cmdspec - FTP command specification
42 * @id: FTP command ID
43 * @ofs: offset in file
44 * @fname: filename (ASCII), null-terminated
45 * @buf: kernel-space transfer data buffer, 4k aligned
46 * @len: (max) number of bytes to transfer from/to @buf
47 */
48struct hmcdrv_ftp_cmdspec {
49 enum hmcdrv_ftp_cmdid id;
50 loff_t ofs;
51 const char *fname;
52 void __kernel *buf;
53 size_t len;
54};
55
56int hmcdrv_ftp_startup(void);
57void hmcdrv_ftp_shutdown(void);
58int hmcdrv_ftp_probe(void);
59ssize_t hmcdrv_ftp_do(const struct hmcdrv_ftp_cmdspec *ftp);
60ssize_t hmcdrv_ftp_cmd(char __kernel *cmd, loff_t offset,
61 char __user *buf, size_t len);
62
63#endif /* __HMCDRV_FTP_H__ */
diff --git a/drivers/s390/char/hmcdrv_mod.c b/drivers/s390/char/hmcdrv_mod.c
new file mode 100644
index 000000000000..505c6a78ee1a
--- /dev/null
+++ b/drivers/s390/char/hmcdrv_mod.c
@@ -0,0 +1,64 @@
1/*
2 * HMC Drive DVD Module
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 */
7
8#define KMSG_COMPONENT "hmcdrv"
9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/version.h>
15#include <linux/stat.h>
16
17#include "hmcdrv_ftp.h"
18#include "hmcdrv_dev.h"
19#include "hmcdrv_cache.h"
20
21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Copyright 2013 IBM Corporation");
23MODULE_DESCRIPTION("HMC drive DVD access");
24
25/*
26 * module parameter 'cachesize'
27 */
28static size_t hmcdrv_mod_cachesize = HMCDRV_CACHE_SIZE_DFLT;
29module_param_named(cachesize, hmcdrv_mod_cachesize, ulong, S_IRUGO);
30
31/**
32 * hmcdrv_mod_init() - module init function
33 */
34static int __init hmcdrv_mod_init(void)
35{
36 int rc = hmcdrv_ftp_probe(); /* perform w/o cache */
37
38 if (rc)
39 return rc;
40
41 rc = hmcdrv_cache_startup(hmcdrv_mod_cachesize);
42
43 if (rc)
44 return rc;
45
46 rc = hmcdrv_dev_init();
47
48 if (rc)
49 hmcdrv_cache_shutdown();
50
51 return rc;
52}
53
54/**
55 * hmcdrv_mod_exit() - module exit function
56 */
57static void __exit hmcdrv_mod_exit(void)
58{
59 hmcdrv_dev_exit();
60 hmcdrv_cache_shutdown();
61}
62
63module_init(hmcdrv_mod_init);
64module_exit(hmcdrv_mod_exit);
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index a68b5ec7d042..a88069f8c677 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -19,6 +19,7 @@
19 19
20#define EVTYP_OPCMD 0x01 20#define EVTYP_OPCMD 0x01
21#define EVTYP_MSG 0x02 21#define EVTYP_MSG 0x02
22#define EVTYP_DIAG_TEST 0x07
22#define EVTYP_STATECHANGE 0x08 23#define EVTYP_STATECHANGE 0x08
23#define EVTYP_PMSGCMD 0x09 24#define EVTYP_PMSGCMD 0x09
24#define EVTYP_CNTLPROGOPCMD 0x20 25#define EVTYP_CNTLPROGOPCMD 0x20
@@ -32,6 +33,7 @@
32 33
33#define EVTYP_OPCMD_MASK 0x80000000 34#define EVTYP_OPCMD_MASK 0x80000000
34#define EVTYP_MSG_MASK 0x40000000 35#define EVTYP_MSG_MASK 0x40000000
36#define EVTYP_DIAG_TEST_MASK 0x02000000
35#define EVTYP_STATECHANGE_MASK 0x01000000 37#define EVTYP_STATECHANGE_MASK 0x01000000
36#define EVTYP_PMSGCMD_MASK 0x00800000 38#define EVTYP_PMSGCMD_MASK 0x00800000
37#define EVTYP_CTLPROGOPCMD_MASK 0x00000001 39#define EVTYP_CTLPROGOPCMD_MASK 0x00000001
diff --git a/drivers/s390/char/sclp_diag.h b/drivers/s390/char/sclp_diag.h
new file mode 100644
index 000000000000..59c4afa5e670
--- /dev/null
+++ b/drivers/s390/char/sclp_diag.h
@@ -0,0 +1,89 @@
1/*
2 * Copyright IBM Corp. 2013
3 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
4 */
5
6#ifndef _SCLP_DIAG_H
7#define _SCLP_DIAG_H
8
9#include <linux/types.h>
10
11/* return codes for Diagnostic Test FTP Service, as indicated in member
12 * sclp_diag_ftp::ldflg
13 */
14#define SCLP_DIAG_FTP_OK 0x80U /* success */
15#define SCLP_DIAG_FTP_LDFAIL 0x01U /* load failed */
16#define SCLP_DIAG_FTP_LDNPERM 0x02U /* not allowed */
17#define SCLP_DIAG_FTP_LDRUNS 0x03U /* LD runs */
18#define SCLP_DIAG_FTP_LDNRUNS 0x04U /* LD does not run */
19
20#define SCLP_DIAG_FTP_XPCX 0x80 /* PCX communication code */
21#define SCLP_DIAG_FTP_ROUTE 4 /* routing code for new FTP service */
22
23/*
24 * length of Diagnostic Test FTP Service event buffer
25 */
26#define SCLP_DIAG_FTP_EVBUF_LEN \
27 (offsetof(struct sclp_diag_evbuf, mdd) + \
28 sizeof(struct sclp_diag_ftp))
29
30/**
31 * struct sclp_diag_ftp - Diagnostic Test FTP Service model-dependent data
32 * @pcx: code for PCX communication (should be 0x80)
33 * @ldflg: load flag (see defines above)
34 * @cmd: FTP command
35 * @pgsize: page size (0 = 4kB, 1 = large page size)
36 * @srcflg: source flag
37 * @spare: reserved (zeroes)
38 * @offset: file offset
39 * @fsize: file size
40 * @length: buffer size resp. bytes transferred
41 * @failaddr: failing address
42 * @bufaddr: buffer address, virtual
43 * @asce: region or segment table designation
44 * @fident: file name (ASCII, zero-terminated)
45 */
46struct sclp_diag_ftp {
47 u8 pcx;
48 u8 ldflg;
49 u8 cmd;
50 u8 pgsize;
51 u8 srcflg;
52 u8 spare;
53 u64 offset;
54 u64 fsize;
55 u64 length;
56 u64 failaddr;
57 u64 bufaddr;
58 u64 asce;
59
60 u8 fident[256];
61} __packed;
62
63/**
64 * struct sclp_diag_evbuf - Diagnostic Test (ET7) Event Buffer
65 * @hdr: event buffer header
66 * @route: diagnostic route
67 * @mdd: model-dependent data (@route dependent)
68 */
69struct sclp_diag_evbuf {
70 struct evbuf_header hdr;
71 u16 route;
72
73 union {
74 struct sclp_diag_ftp ftp;
75 } mdd;
76} __packed;
77
78/**
79 * struct sclp_diag_sccb - Diagnostic Test (ET7) SCCB
80 * @hdr: SCCB header
81 * @evbuf: event buffer
82 */
83struct sclp_diag_sccb {
84
85 struct sccb_header hdr;
86 struct sclp_diag_evbuf evbuf;
87} __packed;
88
89#endif /* _SCLP_DIAG_H */
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 1918d9dff45d..5bd6cb145a87 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -281,7 +281,7 @@ out:
281 281
282static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb) 282static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb)
283{ 283{
284 if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK))) 284 if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK))
285 return 0; 285 return 0;
286 if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) 286 if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
287 return 0; 287 return 0;
diff --git a/drivers/s390/char/sclp_ftp.c b/drivers/s390/char/sclp_ftp.c
new file mode 100644
index 000000000000..6561cc5b2d5d
--- /dev/null
+++ b/drivers/s390/char/sclp_ftp.c
@@ -0,0 +1,275 @@
1/*
2 * SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
3 *
4 * Copyright IBM Corp. 2013
5 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
6 *
7 */
8
9#define KMSG_COMPONENT "hmcdrv"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
12#include <linux/kernel.h>
13#include <linux/mm.h>
14#include <linux/slab.h>
15#include <linux/io.h>
16#include <linux/wait.h>
17#include <linux/string.h>
18#include <linux/jiffies.h>
19#include <asm/sysinfo.h>
20#include <asm/ebcdic.h>
21
22#include "sclp.h"
23#include "sclp_diag.h"
24#include "sclp_ftp.h"
25
26static DECLARE_COMPLETION(sclp_ftp_rx_complete);
27static u8 sclp_ftp_ldflg;
28static u64 sclp_ftp_fsize;
29static u64 sclp_ftp_length;
30
31/**
32 * sclp_ftp_txcb() - Diagnostic Test FTP services SCLP command callback
33 */
34static void sclp_ftp_txcb(struct sclp_req *req, void *data)
35{
36 struct completion *completion = data;
37
38#ifdef DEBUG
39 pr_debug("SCLP (ET7) TX-IRQ, SCCB @ 0x%p: %*phN\n",
40 req->sccb, 24, req->sccb);
41#endif
42 complete(completion);
43}
44
45/**
46 * sclp_ftp_rxcb() - Diagnostic Test FTP services receiver event callback
47 */
48static void sclp_ftp_rxcb(struct evbuf_header *evbuf)
49{
50 struct sclp_diag_evbuf *diag = (struct sclp_diag_evbuf *) evbuf;
51
52 /*
53 * Check for Diagnostic Test FTP Service
54 */
55 if (evbuf->type != EVTYP_DIAG_TEST ||
56 diag->route != SCLP_DIAG_FTP_ROUTE ||
57 diag->mdd.ftp.pcx != SCLP_DIAG_FTP_XPCX ||
58 evbuf->length < SCLP_DIAG_FTP_EVBUF_LEN)
59 return;
60
61#ifdef DEBUG
62 pr_debug("SCLP (ET7) RX-IRQ, Event @ 0x%p: %*phN\n",
63 evbuf, 24, evbuf);
64#endif
65
66 /*
67 * Because the event buffer is located in a page which is owned
68 * by the SCLP core, all data of interest must be copied. The
69 * error indication is in 'sclp_ftp_ldflg'
70 */
71 sclp_ftp_ldflg = diag->mdd.ftp.ldflg;
72 sclp_ftp_fsize = diag->mdd.ftp.fsize;
73 sclp_ftp_length = diag->mdd.ftp.length;
74
75 complete(&sclp_ftp_rx_complete);
76}
77
78/**
79 * sclp_ftp_et7() - start a Diagnostic Test FTP Service SCLP request
80 * @ftp: pointer to FTP descriptor
81 *
82 * Return: 0 on success, else a (negative) error code
83 */
84static int sclp_ftp_et7(const struct hmcdrv_ftp_cmdspec *ftp)
85{
86 struct completion completion;
87 struct sclp_diag_sccb *sccb;
88 struct sclp_req *req;
89 size_t len;
90 int rc;
91
92 req = kzalloc(sizeof(*req), GFP_KERNEL);
93 sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
94 if (!req || !sccb) {
95 rc = -ENOMEM;
96 goto out_free;
97 }
98
99 sccb->hdr.length = SCLP_DIAG_FTP_EVBUF_LEN +
100 sizeof(struct sccb_header);
101 sccb->evbuf.hdr.type = EVTYP_DIAG_TEST;
102 sccb->evbuf.hdr.length = SCLP_DIAG_FTP_EVBUF_LEN;
103 sccb->evbuf.hdr.flags = 0; /* clear processed-buffer */
104 sccb->evbuf.route = SCLP_DIAG_FTP_ROUTE;
105 sccb->evbuf.mdd.ftp.pcx = SCLP_DIAG_FTP_XPCX;
106 sccb->evbuf.mdd.ftp.srcflg = 0;
107 sccb->evbuf.mdd.ftp.pgsize = 0;
108 sccb->evbuf.mdd.ftp.asce = _ASCE_REAL_SPACE;
109 sccb->evbuf.mdd.ftp.ldflg = SCLP_DIAG_FTP_LDFAIL;
110 sccb->evbuf.mdd.ftp.fsize = 0;
111 sccb->evbuf.mdd.ftp.cmd = ftp->id;
112 sccb->evbuf.mdd.ftp.offset = ftp->ofs;
113 sccb->evbuf.mdd.ftp.length = ftp->len;
114 sccb->evbuf.mdd.ftp.bufaddr = virt_to_phys(ftp->buf);
115
116 len = strlcpy(sccb->evbuf.mdd.ftp.fident, ftp->fname,
117 HMCDRV_FTP_FIDENT_MAX);
118 if (len >= HMCDRV_FTP_FIDENT_MAX) {
119 rc = -EINVAL;
120 goto out_free;
121 }
122
123 req->command = SCLP_CMDW_WRITE_EVENT_DATA;
124 req->sccb = sccb;
125 req->status = SCLP_REQ_FILLED;
126 req->callback = sclp_ftp_txcb;
127 req->callback_data = &completion;
128
129 init_completion(&completion);
130
131 rc = sclp_add_request(req);
132 if (rc)
133 goto out_free;
134
135 /* Wait for end of ftp sclp command. */
136 wait_for_completion(&completion);
137
138#ifdef DEBUG
139 pr_debug("status of SCLP (ET7) request is 0x%04x (0x%02x)\n",
140 sccb->hdr.response_code, sccb->evbuf.hdr.flags);
141#endif
142
143 /*
144 * Check if sclp accepted the request. The data transfer runs
145 * asynchronously and the completion is indicated with an
146 * sclp ET7 event.
147 */
148 if (req->status != SCLP_REQ_DONE ||
149 (sccb->evbuf.hdr.flags & 0x80) == 0 || /* processed-buffer */
150 (sccb->hdr.response_code & 0xffU) != 0x20U) {
151 rc = -EIO;
152 }
153
154out_free:
155 free_page((unsigned long) sccb);
156 kfree(req);
157 return rc;
158}
159
160/**
161 * sclp_ftp_cmd() - executes a HMC related SCLP Diagnose (ET7) FTP command
162 * @ftp: pointer to FTP command specification
163 * @fsize: return of file size (or NULL if undesirable)
164 *
165 * Attention: Notice that this function is not reentrant - so the caller
166 * must ensure locking.
167 *
168 * Return: number of bytes read/written or a (negative) error code
169 */
170ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize)
171{
172 ssize_t len;
173#ifdef DEBUG
174 unsigned long start_jiffies;
175
176 pr_debug("starting SCLP (ET7), cmd %d for '%s' at %lld with %zd bytes\n",
177 ftp->id, ftp->fname, (long long) ftp->ofs, ftp->len);
178 start_jiffies = jiffies;
179#endif
180
181 init_completion(&sclp_ftp_rx_complete);
182
183 /* Start ftp sclp command. */
184 len = sclp_ftp_et7(ftp);
185 if (len)
186 goto out_unlock;
187
188 /*
189 * There is no way to cancel the sclp ET7 request, the code
190 * needs to wait unconditionally until the transfer is complete.
191 */
192 wait_for_completion(&sclp_ftp_rx_complete);
193
194#ifdef DEBUG
195 pr_debug("completed SCLP (ET7) request after %lu ms (all)\n",
196 (jiffies - start_jiffies) * 1000 / HZ);
197 pr_debug("return code of SCLP (ET7) FTP Service is 0x%02x, with %lld/%lld bytes\n",
198 sclp_ftp_ldflg, sclp_ftp_length, sclp_ftp_fsize);
199#endif
200
201 switch (sclp_ftp_ldflg) {
202 case SCLP_DIAG_FTP_OK:
203 len = sclp_ftp_length;
204 if (fsize)
205 *fsize = sclp_ftp_fsize;
206 break;
207 case SCLP_DIAG_FTP_LDNPERM:
208 len = -EPERM;
209 break;
210 case SCLP_DIAG_FTP_LDRUNS:
211 len = -EBUSY;
212 break;
213 case SCLP_DIAG_FTP_LDFAIL:
214 len = -ENOENT;
215 break;
216 default:
217 len = -EIO;
218 break;
219 }
220
221out_unlock:
222 return len;
223}
224
225/*
226 * ET7 event listener
227 */
228static struct sclp_register sclp_ftp_event = {
229 .send_mask = EVTYP_DIAG_TEST_MASK, /* want tx events */
230 .receive_mask = EVTYP_DIAG_TEST_MASK, /* want rx events */
231 .receiver_fn = sclp_ftp_rxcb, /* async callback (rx) */
232 .state_change_fn = NULL,
233 .pm_event_fn = NULL,
234};
235
236/**
237 * sclp_ftp_startup() - startup of FTP services, when running on LPAR
238 */
239int sclp_ftp_startup(void)
240{
241#ifdef DEBUG
242 unsigned long info;
243#endif
244 int rc;
245
246 rc = sclp_register(&sclp_ftp_event);
247 if (rc)
248 return rc;
249
250#ifdef DEBUG
251 info = get_zeroed_page(GFP_KERNEL);
252
253 if (info != 0) {
254 struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
255
256 if (!stsi(info222, 2, 2, 2)) { /* get SYSIB 2.2.2 */
257 info222->name[sizeof(info222->name) - 1] = '\0';
258 EBCASC_500(info222->name, sizeof(info222->name) - 1);
259 pr_debug("SCLP (ET7) FTP Service working on LPAR %u (%s)\n",
260 info222->lpar_number, info222->name);
261 }
262
263 free_page(info);
264 }
265#endif /* DEBUG */
266 return 0;
267}
268
269/**
270 * sclp_ftp_shutdown() - shutdown of FTP services, when running on LPAR
271 */
272void sclp_ftp_shutdown(void)
273{
274 sclp_unregister(&sclp_ftp_event);
275}
diff --git a/drivers/s390/char/sclp_ftp.h b/drivers/s390/char/sclp_ftp.h
new file mode 100644
index 000000000000..98ba3183e7d9
--- /dev/null
+++ b/drivers/s390/char/sclp_ftp.h
@@ -0,0 +1,21 @@
1/*
2 * SCLP Event Type (ET) 7 - Diagnostic Test FTP Services, useable on LPAR
3 *
4 * Notice that all functions exported here are not reentrant.
5 * So usage should be exclusive, ensured by the caller (e.g. using a
6 * mutex).
7 *
8 * Copyright IBM Corp. 2013
9 * Author(s): Ralf Hoppe (rhoppe@de.ibm.com)
10 */
11
12#ifndef __SCLP_FTP_H__
13#define __SCLP_FTP_H__
14
15#include "hmcdrv_ftp.h"
16
17int sclp_ftp_startup(void);
18void sclp_ftp_shutdown(void);
19ssize_t sclp_ftp_cmd(const struct hmcdrv_ftp_cmdspec *ftp, size_t *fsize);
20
21#endif /* __SCLP_FTP_H__ */
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 3b13d58fe87b..35a84af875ee 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -33,7 +33,7 @@ static void sclp_rw_pm_event(struct sclp_register *reg,
33 33
34/* Event type structure for write message and write priority message */ 34/* Event type structure for write message and write priority message */
35static struct sclp_register sclp_rw_event = { 35static struct sclp_register sclp_rw_event = {
36 .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK, 36 .send_mask = EVTYP_MSG_MASK,
37 .pm_event_fn = sclp_rw_pm_event, 37 .pm_event_fn = sclp_rw_pm_event,
38}; 38};
39 39
@@ -456,14 +456,9 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
456 return -EIO; 456 return -EIO;
457 457
458 sccb = buffer->sccb; 458 sccb = buffer->sccb;
459 if (sclp_rw_event.sclp_receive_mask & EVTYP_MSG_MASK) 459 /* Use normal write message */
460 /* Use normal write message */ 460 sccb->msg_buf.header.type = EVTYP_MSG;
461 sccb->msg_buf.header.type = EVTYP_MSG; 461
462 else if (sclp_rw_event.sclp_receive_mask & EVTYP_PMSGCMD_MASK)
463 /* Use write priority message */
464 sccb->msg_buf.header.type = EVTYP_PMSGCMD;
465 else
466 return -EOPNOTSUPP;
467 buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; 462 buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
468 buffer->request.status = SCLP_REQ_FILLED; 463 buffer->request.status = SCLP_REQ_FILLED;
469 buffer->request.callback = sclp_writedata_callback; 464 buffer->request.callback = sclp_writedata_callback;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index b9a9f721716d..ae67386c03d3 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -206,10 +206,6 @@ sclp_vt220_callback(struct sclp_req *request, void *data)
206static int 206static int
207__sclp_vt220_emit(struct sclp_vt220_request *request) 207__sclp_vt220_emit(struct sclp_vt220_request *request)
208{ 208{
209 if (!(sclp_vt220_register.sclp_receive_mask & EVTYP_VT220MSG_MASK)) {
210 request->sclp_req.status = SCLP_REQ_FAILED;
211 return -EIO;
212 }
213 request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA; 209 request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
214 request->sclp_req.status = SCLP_REQ_FILLED; 210 request->sclp_req.status = SCLP_REQ_FILLED;
215 request->sclp_req.callback = sclp_vt220_callback; 211 request->sclp_req.callback = sclp_vt220_callback;
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 6dc60725de92..77f9b9c2f701 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -402,7 +402,9 @@ __tapechar_ioctl(struct tape_device *device,
402 memset(&get, 0, sizeof(get)); 402 memset(&get, 0, sizeof(get));
403 get.mt_type = MT_ISUNKNOWN; 403 get.mt_type = MT_ISUNKNOWN;
404 get.mt_resid = 0 /* device->devstat.rescnt */; 404 get.mt_resid = 0 /* device->devstat.rescnt */;
405 get.mt_dsreg = device->tape_state; 405 get.mt_dsreg =
406 ((device->char_data.block_size << MT_ST_BLKSIZE_SHIFT)
407 & MT_ST_BLKSIZE_MASK);
406 /* FIXME: mt_gstat, mt_erreg, mt_fileno */ 408 /* FIXME: mt_gstat, mt_erreg, mt_fileno */
407 get.mt_gstat = 0; 409 get.mt_gstat = 0;
408 get.mt_erreg = 0; 410 get.mt_erreg = 0;
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 1884653e4472..efcf48481c5f 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -28,6 +28,7 @@
28#include <asm/processor.h> 28#include <asm/processor.h>
29#include <asm/irqflags.h> 29#include <asm/irqflags.h>
30#include <asm/checksum.h> 30#include <asm/checksum.h>
31#include <asm/switch_to.h>
31#include "sclp.h" 32#include "sclp.h"
32 33
33#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) 34#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
@@ -149,18 +150,21 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
149 150
150static int __init init_cpu_info(enum arch_id arch) 151static int __init init_cpu_info(enum arch_id arch)
151{ 152{
152 struct save_area *sa; 153 struct save_area_ext *sa_ext;
153 154
154 /* get info for boot cpu from lowcore, stored in the HSA */ 155 /* get info for boot cpu from lowcore, stored in the HSA */
155 156
156 sa = dump_save_area_create(0); 157 sa_ext = dump_save_area_create(0);
157 if (!sa) 158 if (!sa_ext)
158 return -ENOMEM; 159 return -ENOMEM;
159 if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) { 160 if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base,
161 sys_info.sa_size) < 0) {
160 TRACE("could not copy from HSA\n"); 162 TRACE("could not copy from HSA\n");
161 kfree(sa); 163 kfree(sa_ext);
162 return -EIO; 164 return -EIO;
163 } 165 }
166 if (MACHINE_HAS_VX)
167 save_vx_regs_safe(sa_ext->vx_regs);
164 return 0; 168 return 0;
165} 169}
166 170
@@ -258,7 +262,7 @@ static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
258 unsigned long sa_start, sa_end; /* save area range */ 262 unsigned long sa_start, sa_end; /* save area range */
259 unsigned long prefix; 263 unsigned long prefix;
260 unsigned long sa_off, len, buf_off; 264 unsigned long sa_off, len, buf_off;
261 struct save_area *save_area = dump_save_areas.areas[i]; 265 struct save_area *save_area = &dump_save_areas.areas[i]->sa;
262 266
263 prefix = save_area->pref_reg; 267 prefix = save_area->pref_reg;
264 sa_start = prefix + sys_info.sa_base; 268 sa_start = prefix + sys_info.sa_base;
@@ -612,7 +616,7 @@ static void __init zcore_header_init(int arch, struct zcore_header *hdr,
612 hdr->tod = get_tod_clock(); 616 hdr->tod = get_tod_clock();
613 get_cpu_id(&hdr->cpu_id); 617 get_cpu_id(&hdr->cpu_id);
614 for (i = 0; i < dump_save_areas.count; i++) { 618 for (i = 0; i < dump_save_areas.count; i++) {
615 prefix = dump_save_areas.areas[i]->pref_reg; 619 prefix = dump_save_areas.areas[i]->sa.pref_reg;
616 hdr->real_cpu_cnt++; 620 hdr->real_cpu_cnt++;
617 if (!prefix) 621 if (!prefix)
618 continue; 622 continue;
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 00bfbee0af9e..56eb4ee4deba 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -87,7 +87,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
87 struct airq_struct *airq; 87 struct airq_struct *airq;
88 struct hlist_head *head; 88 struct hlist_head *head;
89 89
90 __this_cpu_write(s390_idle.nohz_delay, 1); 90 set_cpu_flag(CIF_NOHZ_DELAY);
91 tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; 91 tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
92 head = &airq_lists[tpi_info->isc]; 92 head = &airq_lists[tpi_info->isc];
93 rcu_read_lock(); 93 rcu_read_lock();
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 2905d8b0ec95..d5a6f287d2fe 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -561,7 +561,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
561 struct subchannel *sch; 561 struct subchannel *sch;
562 struct irb *irb; 562 struct irb *irb;
563 563
564 __this_cpu_write(s390_idle.nohz_delay, 1); 564 set_cpu_flag(CIF_NOHZ_DELAY);
565 tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; 565 tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
566 irb = &__get_cpu_var(cio_irb); 566 irb = &__get_cpu_var(cio_irb);
567 sch = (struct subchannel *)(unsigned long) tpi_info->intparm; 567 sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 4038437ff033..99485415dcc2 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -664,6 +664,17 @@ static ssize_t ap_hwtype_show(struct device *dev,
664} 664}
665 665
666static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); 666static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
667
668static ssize_t ap_raw_hwtype_show(struct device *dev,
669 struct device_attribute *attr, char *buf)
670{
671 struct ap_device *ap_dev = to_ap_dev(dev);
672
673 return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->raw_hwtype);
674}
675
676static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL);
677
667static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, 678static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
668 char *buf) 679 char *buf)
669{ 680{
@@ -734,6 +745,7 @@ static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL);
734 745
735static struct attribute *ap_dev_attrs[] = { 746static struct attribute *ap_dev_attrs[] = {
736 &dev_attr_hwtype.attr, 747 &dev_attr_hwtype.attr,
748 &dev_attr_raw_hwtype.attr,
737 &dev_attr_depth.attr, 749 &dev_attr_depth.attr,
738 &dev_attr_request_count.attr, 750 &dev_attr_request_count.attr,
739 &dev_attr_requestq_count.attr, 751 &dev_attr_requestq_count.attr,
@@ -1188,6 +1200,10 @@ static int ap_select_domain(void)
1188 ap_qid_t qid; 1200 ap_qid_t qid;
1189 int rc, i, j; 1201 int rc, i, j;
1190 1202
1203 /* IF APXA isn't installed, only 16 domains could be defined */
1204 if (!ap_configuration->ap_extended && (ap_domain_index > 15))
1205 return -EINVAL;
1206
1191 /* 1207 /*
1192 * We want to use a single domain. Either the one specified with 1208 * We want to use a single domain. Either the one specified with
1193 * the "domain=" parameter or the domain with the maximum number 1209 * the "domain=" parameter or the domain with the maximum number
@@ -1413,9 +1429,13 @@ static void ap_scan_bus(struct work_struct *unused)
1413 continue; 1429 continue;
1414 } 1430 }
1415 break; 1431 break;
1432 case 11:
1433 ap_dev->device_type = 10;
1434 break;
1416 default: 1435 default:
1417 ap_dev->device_type = device_type; 1436 ap_dev->device_type = device_type;
1418 } 1437 }
1438 ap_dev->raw_hwtype = device_type;
1419 1439
1420 rc = ap_query_functions(qid, &device_functions); 1440 rc = ap_query_functions(qid, &device_functions);
1421 if (!rc) 1441 if (!rc)
@@ -1900,9 +1920,15 @@ static void ap_reset_all(void)
1900{ 1920{
1901 int i, j; 1921 int i, j;
1902 1922
1903 for (i = 0; i < AP_DOMAINS; i++) 1923 for (i = 0; i < AP_DOMAINS; i++) {
1904 for (j = 0; j < AP_DEVICES; j++) 1924 if (!ap_test_config_domain(i))
1925 continue;
1926 for (j = 0; j < AP_DEVICES; j++) {
1927 if (!ap_test_config_card_id(j))
1928 continue;
1905 ap_reset_queue(AP_MKQID(j, i)); 1929 ap_reset_queue(AP_MKQID(j, i));
1930 }
1931 }
1906} 1932}
1907 1933
1908static struct reset_call ap_reset_call = { 1934static struct reset_call ap_reset_call = {
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 6405ae24a7a6..055a0f956d17 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -31,7 +31,7 @@
31#include <linux/types.h> 31#include <linux/types.h>
32 32
33#define AP_DEVICES 64 /* Number of AP devices. */ 33#define AP_DEVICES 64 /* Number of AP devices. */
34#define AP_DOMAINS 16 /* Number of AP domains. */ 34#define AP_DOMAINS 256 /* Number of AP domains. */
35#define AP_MAX_RESET 90 /* Maximum number of resets. */ 35#define AP_MAX_RESET 90 /* Maximum number of resets. */
36#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */ 36#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */
37#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ 37#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
@@ -45,9 +45,9 @@ extern int ap_domain_index;
45 */ 45 */
46typedef unsigned int ap_qid_t; 46typedef unsigned int ap_qid_t;
47 47
48#define AP_MKQID(_device,_queue) (((_device) & 63) << 8 | ((_queue) & 15)) 48#define AP_MKQID(_device, _queue) (((_device) & 63) << 8 | ((_queue) & 255))
49#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63) 49#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
50#define AP_QID_QUEUE(_qid) ((_qid) & 15) 50#define AP_QID_QUEUE(_qid) ((_qid) & 255)
51 51
52/** 52/**
53 * structy ap_queue_status - Holds the AP queue status. 53 * structy ap_queue_status - Holds the AP queue status.
@@ -161,6 +161,7 @@ struct ap_device {
161 ap_qid_t qid; /* AP queue id. */ 161 ap_qid_t qid; /* AP queue id. */
162 int queue_depth; /* AP queue depth.*/ 162 int queue_depth; /* AP queue depth.*/
163 int device_type; /* AP device type. */ 163 int device_type; /* AP device type. */
164 int raw_hwtype; /* AP raw hardware type. */
164 unsigned int functions; /* AP device function bitfield. */ 165 unsigned int functions; /* AP device function bitfield. */
165 int unregistered; /* marks AP device as unregistered */ 166 int unregistered; /* marks AP device as unregistered */
166 struct timer_list timeout; /* Timer for request timeouts. */ 167 struct timer_list timeout; /* Timer for request timeouts. */
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 0e18c5dcd91f..08f1830cbfc4 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -343,10 +343,11 @@ struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant)
343 break; 343 break;
344 } 344 }
345 } 345 }
346 if (!found || !try_module_get(zops->owner))
347 zops = NULL;
348
346 spin_unlock_bh(&zcrypt_ops_list_lock); 349 spin_unlock_bh(&zcrypt_ops_list_lock);
347 350
348 if (!found)
349 return NULL;
350 return zops; 351 return zops;
351} 352}
352 353
@@ -359,8 +360,6 @@ struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant)
359 request_module("%s", name); 360 request_module("%s", name);
360 zops = __ops_lookup(name, variant); 361 zops = __ops_lookup(name, variant);
361 } 362 }
362 if ((!zops) || (!try_module_get(zops->owner)))
363 return NULL;
364 return zops; 363 return zops;
365} 364}
366EXPORT_SYMBOL(zcrypt_msgtype_request); 365EXPORT_SYMBOL(zcrypt_msgtype_request);