mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (81 commits) [S390] remove duplicated #includes [S390] cpumask: use mm_cpumask() wrapper [S390] cpumask: Use accessors code. [S390] cpumask: prepare for iterators to only go to nr_cpu_ids/nr_cpumask_bits. [S390] cpumask: remove cpu_coregroup_map [S390] fix clock comparator save area usage [S390] Add hwcap flag for the etf3 enhancement facility [S390] Ensure that ipl panic notifier is called late. [S390] fix dfp elf hwcap/facility bit detection [S390] smp: perform initial cpu reset before starting a cpu [S390] smp: fix memory leak on __cpu_up [S390] ipl: Improve checking logic and remove switch defaults. [S390] s390dbf: Remove needless check for NULL pointer. [S390] s390dbf: Remove redundant initilizations. [S390] use kzfree() [S390] BUG to BUG_ON changes [S390] zfcpdump: Prevent zcore from beeing built as a kernel module. [S390] Use csum_partial in checksum.h [S390] cleanup lowcore.h [S390] eliminate ipl_device from lowcore ...
This commit is contained in:
commit
21cdbc1378
99 changed files with 4059 additions and 2917 deletions
|
|
@ -2,9 +2,6 @@
|
|||
# Makefile for the S/390 specific device drivers
|
||||
#
|
||||
|
||||
CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
|
||||
|
||||
obj-y += s390mach.o sysinfo.o
|
||||
obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/
|
||||
|
||||
drivers-y += drivers/s390/built-in.o
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
@ -22,6 +25,7 @@
|
|||
#include <asm/ebcdic.h>
|
||||
#include <asm/idals.h>
|
||||
#include <asm/todclk.h>
|
||||
#include <asm/itcw.h>
|
||||
|
||||
/* This is ugly... */
|
||||
#define PRINTK_HEADER "dasd:"
|
||||
|
|
@ -221,7 +225,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
|
|||
return rc;
|
||||
}
|
||||
/* register 'device' debug area, used for all DBF_DEV_XXX calls */
|
||||
device->debug_area = debug_register(dev_name(&device->cdev->dev), 1, 1,
|
||||
device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1,
|
||||
8 * sizeof(long));
|
||||
debug_register_view(device->debug_area, &debug_sprintf_view);
|
||||
debug_set_level(device->debug_area, DBF_WARNING);
|
||||
|
|
@ -762,7 +766,7 @@ static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
|
|||
return -EINVAL;
|
||||
device = cqr->startdev;
|
||||
if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device,
|
||||
DBF_DEV_EVENT(DBF_WARNING, device,
|
||||
" dasd_ccw_req 0x%08x magic doesn't match"
|
||||
" discipline 0x%08x",
|
||||
cqr->magic,
|
||||
|
|
@ -782,6 +786,7 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
|
|||
{
|
||||
struct dasd_device *device;
|
||||
int retries, rc;
|
||||
char errorstring[ERRORLENGTH];
|
||||
|
||||
/* Check the cqr */
|
||||
rc = dasd_check_cqr(cqr);
|
||||
|
|
@ -815,10 +820,10 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
|
|||
"device busy, retry later");
|
||||
break;
|
||||
default:
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"line %d unknown RC=%d, please "
|
||||
"report to [email protected]",
|
||||
__LINE__, rc);
|
||||
/* internal error 10 - unknown rc*/
|
||||
snprintf(errorstring, ERRORLENGTH, "10 %d", rc);
|
||||
dev_err(&device->cdev->dev, "An error occurred in the "
|
||||
"DASD device driver, reason=%s\n", errorstring);
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
|
@ -836,6 +841,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
|
|||
{
|
||||
struct dasd_device *device;
|
||||
int rc;
|
||||
char errorstring[ERRORLENGTH];
|
||||
|
||||
/* Check the cqr */
|
||||
rc = dasd_check_cqr(cqr);
|
||||
|
|
@ -843,17 +849,23 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
|
|||
return rc;
|
||||
device = (struct dasd_device *) cqr->startdev;
|
||||
if (cqr->retries < 0) {
|
||||
DEV_MESSAGE(KERN_DEBUG, device,
|
||||
"start_IO: request %p (%02x/%i) - no retry left.",
|
||||
cqr, cqr->status, cqr->retries);
|
||||
/* internal error 14 - start_IO run out of retries */
|
||||
sprintf(errorstring, "14 %p", cqr);
|
||||
dev_err(&device->cdev->dev, "An error occurred in the DASD "
|
||||
"device driver, reason=%s\n", errorstring);
|
||||
cqr->status = DASD_CQR_ERROR;
|
||||
return -EIO;
|
||||
}
|
||||
cqr->startclk = get_clock();
|
||||
cqr->starttime = jiffies;
|
||||
cqr->retries--;
|
||||
rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,
|
||||
cqr->lpm, 0);
|
||||
if (cqr->cpmode == 1) {
|
||||
rc = ccw_device_tm_start(device->cdev, cqr->cpaddr,
|
||||
(long) cqr, cqr->lpm);
|
||||
} else {
|
||||
rc = ccw_device_start(device->cdev, cqr->cpaddr,
|
||||
(long) cqr, cqr->lpm, 0);
|
||||
}
|
||||
switch (rc) {
|
||||
case 0:
|
||||
cqr->status = DASD_CQR_IN_IO;
|
||||
|
|
@ -862,11 +874,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
|
|||
cqr);
|
||||
break;
|
||||
case -EBUSY:
|
||||
DBF_DEV_EVENT(DBF_ERR, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
|
||||
"start_IO: device busy, retry later");
|
||||
break;
|
||||
case -ETIMEDOUT:
|
||||
DBF_DEV_EVENT(DBF_ERR, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
|
||||
"start_IO: request timeout, retry later");
|
||||
break;
|
||||
case -EACCES:
|
||||
|
|
@ -876,19 +888,24 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
|
|||
* Do a retry with all available pathes.
|
||||
*/
|
||||
cqr->lpm = LPM_ANYPATH;
|
||||
DBF_DEV_EVENT(DBF_ERR, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
|
||||
"start_IO: selected pathes gone,"
|
||||
" retry on all pathes");
|
||||
break;
|
||||
case -ENODEV:
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
|
||||
"start_IO: -ENODEV device gone, retry");
|
||||
break;
|
||||
case -EIO:
|
||||
DBF_DEV_EVENT(DBF_ERR, device, "%s",
|
||||
"start_IO: device gone, retry");
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
|
||||
"start_IO: -EIO device gone, retry");
|
||||
break;
|
||||
default:
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"line %d unknown RC=%d, please report"
|
||||
" to [email protected]", __LINE__, rc);
|
||||
/* internal error 11 - unknown rc */
|
||||
snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
|
||||
dev_err(&device->cdev->dev,
|
||||
"An error occurred in the DASD device driver, "
|
||||
"reason=%s\n", errorstring);
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
|
@ -945,7 +962,7 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
|
|||
return;
|
||||
cqr = (struct dasd_ccw_req *) intparm;
|
||||
if (cqr->status != DASD_CQR_IN_IO) {
|
||||
MESSAGE(KERN_DEBUG,
|
||||
DBF_EVENT(DBF_DEBUG,
|
||||
"invalid status in handle_killed_request: "
|
||||
"bus_id %s, status %02x",
|
||||
dev_name(&cdev->dev), cqr->status);
|
||||
|
|
@ -956,8 +973,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
|
|||
if (device == NULL ||
|
||||
device != dasd_device_from_cdev_locked(cdev) ||
|
||||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
|
||||
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
|
||||
dev_name(&cdev->dev));
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: "
|
||||
"bus_id %s", dev_name(&cdev->dev));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -996,11 +1013,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
case -EIO:
|
||||
break;
|
||||
case -ETIMEDOUT:
|
||||
printk(KERN_WARNING"%s(%s): request timed out\n",
|
||||
DBF_EVENT(DBF_WARNING, "%s(%s): request timed out\n",
|
||||
__func__, dev_name(&cdev->dev));
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING"%s(%s): unknown error %ld\n",
|
||||
DBF_EVENT(DBF_WARNING, "%s(%s): unknown error %ld\n",
|
||||
__func__, dev_name(&cdev->dev), PTR_ERR(irb));
|
||||
}
|
||||
dasd_handle_killed_request(cdev, intparm);
|
||||
|
|
@ -1009,15 +1026,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
|
||||
now = get_clock();
|
||||
|
||||
DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x",
|
||||
dev_name(&cdev->dev), ((irb->scsw.cmd.cstat << 8) |
|
||||
irb->scsw.cmd.dstat), (unsigned int) intparm);
|
||||
|
||||
/* check for unsolicited interrupts */
|
||||
cqr = (struct dasd_ccw_req *) intparm;
|
||||
if (!cqr || ((irb->scsw.cmd.cc == 1) &&
|
||||
(irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) &&
|
||||
(irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) {
|
||||
if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
|
||||
(scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
|
||||
(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) {
|
||||
if (cqr && cqr->status == DASD_CQR_IN_IO)
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
device = dasd_device_from_cdev_locked(cdev);
|
||||
|
|
@ -1033,14 +1046,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
device = (struct dasd_device *) cqr->startdev;
|
||||
if (!device ||
|
||||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
|
||||
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
|
||||
dev_name(&cdev->dev));
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: "
|
||||
"bus_id %s", dev_name(&cdev->dev));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for clear pending */
|
||||
if (cqr->status == DASD_CQR_CLEAR_PENDING &&
|
||||
irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) {
|
||||
scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {
|
||||
cqr->status = DASD_CQR_CLEARED;
|
||||
dasd_device_clear_timer(device);
|
||||
wake_up(&dasd_flush_wq);
|
||||
|
|
@ -1048,19 +1061,17 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
return;
|
||||
}
|
||||
|
||||
/* check status - the request might have been killed by dyn detach */
|
||||
/* check status - the request might have been killed by dyn detach */
|
||||
if (cqr->status != DASD_CQR_IN_IO) {
|
||||
MESSAGE(KERN_DEBUG,
|
||||
"invalid status: bus_id %s, status %02x",
|
||||
dev_name(&cdev->dev), cqr->status);
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "invalid status: bus_id %s, "
|
||||
"status %02x", dev_name(&cdev->dev), cqr->status);
|
||||
return;
|
||||
}
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
|
||||
((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr);
|
||||
|
||||
next = NULL;
|
||||
expires = 0;
|
||||
if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
|
||||
irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) {
|
||||
if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
|
||||
scsw_cstat(&irb->scsw) == 0) {
|
||||
/* request was completed successfully */
|
||||
cqr->status = DASD_CQR_SUCCESS;
|
||||
cqr->stopclk = now;
|
||||
|
|
@ -1071,18 +1082,23 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
}
|
||||
} else { /* error */
|
||||
memcpy(&cqr->irb, irb, sizeof(struct irb));
|
||||
/* log sense for every failed I/O to s390 debugfeature */
|
||||
dasd_log_sense_dbf(cqr, irb);
|
||||
if (device->features & DASD_FEATURE_ERPLOG) {
|
||||
dasd_log_sense(cqr, irb);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we don't want complex ERP for this request, then just
|
||||
* reset this and retry it in the fastpath
|
||||
*/
|
||||
if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
|
||||
cqr->retries > 0) {
|
||||
DEV_MESSAGE(KERN_DEBUG, device,
|
||||
"default ERP in fastpath (%i retries left)",
|
||||
cqr->retries);
|
||||
if (cqr->lpm == LPM_ANYPATH)
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device,
|
||||
"default ERP in fastpath "
|
||||
"(%i retries left)",
|
||||
cqr->retries);
|
||||
cqr->lpm = LPM_ANYPATH;
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
next = cqr;
|
||||
|
|
@ -1093,10 +1109,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
|||
(!device->stopped)) {
|
||||
if (device->discipline->start_IO(next) == 0)
|
||||
expires = next->expires;
|
||||
else
|
||||
DEV_MESSAGE(KERN_DEBUG, device, "%s",
|
||||
"Interrupt fastpath "
|
||||
"failed!");
|
||||
}
|
||||
if (expires != 0)
|
||||
dasd_device_set_timer(device, expires);
|
||||
|
|
@ -1169,6 +1181,7 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
|
|||
struct dasd_block *block;
|
||||
void (*callback)(struct dasd_ccw_req *, void *data);
|
||||
void *callback_data;
|
||||
char errorstring[ERRORLENGTH];
|
||||
|
||||
list_for_each_safe(l, n, final_queue) {
|
||||
cqr = list_entry(l, struct dasd_ccw_req, devlist);
|
||||
|
|
@ -1189,10 +1202,11 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
|
|||
cqr->status = DASD_CQR_TERMINATED;
|
||||
break;
|
||||
default:
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"wrong cqr status in __dasd_process_final_queue "
|
||||
"for cqr %p, status %x",
|
||||
cqr, cqr->status);
|
||||
/* internal error 12 - wrong cqr status*/
|
||||
snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status);
|
||||
dev_err(&device->cdev->dev,
|
||||
"An error occurred in the DASD device driver, "
|
||||
"reason=%s\n", errorstring);
|
||||
BUG();
|
||||
}
|
||||
if (cqr->callback != NULL)
|
||||
|
|
@ -1217,18 +1231,17 @@ static void __dasd_device_check_expire(struct dasd_device *device)
|
|||
(time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
|
||||
if (device->discipline->term_IO(cqr) != 0) {
|
||||
/* Hmpf, try again in 5 sec */
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"internal error - timeout (%is) expired "
|
||||
"for cqr %p, termination failed, "
|
||||
"retrying in 5s",
|
||||
(cqr->expires/HZ), cqr);
|
||||
dev_err(&device->cdev->dev,
|
||||
"cqr %p timed out (%is) but cannot be "
|
||||
"ended, retrying in 5 s\n",
|
||||
cqr, (cqr->expires/HZ));
|
||||
cqr->expires += 5*HZ;
|
||||
dasd_device_set_timer(device, 5*HZ);
|
||||
} else {
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"internal error - timeout (%is) expired "
|
||||
"for cqr %p (%i retries left)",
|
||||
(cqr->expires/HZ), cqr, cqr->retries);
|
||||
dev_err(&device->cdev->dev,
|
||||
"cqr %p timed out (%is), %i retries "
|
||||
"remaining\n", cqr, (cqr->expires/HZ),
|
||||
cqr->retries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1290,10 +1303,9 @@ int dasd_flush_device_queue(struct dasd_device *device)
|
|||
rc = device->discipline->term_IO(cqr);
|
||||
if (rc) {
|
||||
/* unable to terminate requeust */
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"dasd flush ccw_queue is unable "
|
||||
" to terminate request %p",
|
||||
cqr);
|
||||
dev_err(&device->cdev->dev,
|
||||
"Flushing the DASD request queue "
|
||||
"failed for request %p\n", cqr);
|
||||
/* stop flush processing */
|
||||
goto finished;
|
||||
}
|
||||
|
|
@ -1537,10 +1549,9 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
|
|||
/* request in IO - terminate IO and release again */
|
||||
rc = device->discipline->term_IO(cqr);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_ERR, device,
|
||||
"dasd_cancel_req is unable "
|
||||
" to terminate request %p, rc = %d",
|
||||
cqr, rc);
|
||||
dev_err(&device->cdev->dev,
|
||||
"Cancelling request %p failed with rc=%d\n",
|
||||
cqr, rc);
|
||||
} else {
|
||||
cqr->stopclk = get_clock();
|
||||
rc = 1;
|
||||
|
|
@ -1617,7 +1628,7 @@ static inline void __dasd_block_process_erp(struct dasd_block *block,
|
|||
if (cqr->status == DASD_CQR_DONE)
|
||||
DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
|
||||
else
|
||||
DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
|
||||
dev_err(&device->cdev->dev, "ERP failed for the DASD\n");
|
||||
erp_fn = device->discipline->erp_postaction(cqr);
|
||||
erp_fn(cqr);
|
||||
}
|
||||
|
|
@ -1991,8 +2002,11 @@ static void dasd_setup_queue(struct dasd_block *block)
|
|||
blk_queue_max_sectors(block->request_queue, max);
|
||||
blk_queue_max_phys_segments(block->request_queue, -1L);
|
||||
blk_queue_max_hw_segments(block->request_queue, -1L);
|
||||
blk_queue_max_segment_size(block->request_queue, -1L);
|
||||
blk_queue_segment_boundary(block->request_queue, -1L);
|
||||
/* with page sized segments we can translate each segement into
|
||||
* one idaw/tidaw
|
||||
*/
|
||||
blk_queue_max_segment_size(block->request_queue, PAGE_SIZE);
|
||||
blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1);
|
||||
blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -2043,8 +2057,9 @@ static int dasd_open(struct block_device *bdev, fmode_t mode)
|
|||
}
|
||||
|
||||
if (dasd_probeonly) {
|
||||
DEV_MESSAGE(KERN_INFO, base, "%s",
|
||||
"No access to device due to probeonly mode");
|
||||
dev_info(&base->cdev->dev,
|
||||
"Accessing the DASD failed because it is in "
|
||||
"probeonly mode\n");
|
||||
rc = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -2101,7 +2116,8 @@ dasd_device_operations = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = dasd_open,
|
||||
.release = dasd_release,
|
||||
.locked_ioctl = dasd_ioctl,
|
||||
.ioctl = dasd_ioctl,
|
||||
.compat_ioctl = dasd_ioctl,
|
||||
.getgeo = dasd_getgeo,
|
||||
};
|
||||
|
||||
|
|
@ -2143,14 +2159,14 @@ int dasd_generic_probe(struct ccw_device *cdev,
|
|||
|
||||
ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING
|
||||
DBF_EVENT(DBF_WARNING,
|
||||
"dasd_generic_probe: could not set ccw-device options "
|
||||
"for %s\n", dev_name(&cdev->dev));
|
||||
return ret;
|
||||
}
|
||||
ret = dasd_add_sysfs_files(cdev);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING
|
||||
DBF_EVENT(DBF_WARNING,
|
||||
"dasd_generic_probe: could not add sysfs entries "
|
||||
"for %s\n", dev_name(&cdev->dev));
|
||||
return ret;
|
||||
|
|
@ -2166,9 +2182,7 @@ int dasd_generic_probe(struct ccw_device *cdev,
|
|||
(dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0))
|
||||
ret = ccw_device_set_online(cdev);
|
||||
if (ret)
|
||||
printk(KERN_WARNING
|
||||
"dasd_generic_probe: could not initially "
|
||||
"online ccw-device %s; return code: %d\n",
|
||||
pr_warning("%s: Setting the DASD online failed with rc=%d\n",
|
||||
dev_name(&cdev->dev), ret);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2232,10 +2246,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,
|
|||
discipline = base_discipline;
|
||||
if (device->features & DASD_FEATURE_USEDIAG) {
|
||||
if (!dasd_diag_discipline_pointer) {
|
||||
printk (KERN_WARNING
|
||||
"dasd_generic couldn't online device %s "
|
||||
"- discipline DIAG not available\n",
|
||||
dev_name(&cdev->dev));
|
||||
pr_warning("%s Setting the DASD online failed because "
|
||||
"of missing DIAG discipline\n",
|
||||
dev_name(&cdev->dev));
|
||||
dasd_delete_device(device);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -2256,10 +2269,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,
|
|||
/* check_device will allocate block device if necessary */
|
||||
rc = discipline->check_device(device);
|
||||
if (rc) {
|
||||
printk (KERN_WARNING
|
||||
"dasd_generic couldn't online device %s "
|
||||
"with discipline %s rc=%i\n",
|
||||
dev_name(&cdev->dev), discipline->name, rc);
|
||||
pr_warning("%s Setting the DASD online with discipline %s "
|
||||
"failed with rc=%i\n",
|
||||
dev_name(&cdev->dev), discipline->name, rc);
|
||||
module_put(discipline->owner);
|
||||
module_put(base_discipline->owner);
|
||||
dasd_delete_device(device);
|
||||
|
|
@ -2268,9 +2280,8 @@ int dasd_generic_set_online(struct ccw_device *cdev,
|
|||
|
||||
dasd_set_target_state(device, DASD_STATE_ONLINE);
|
||||
if (device->state <= DASD_STATE_KNOWN) {
|
||||
printk (KERN_WARNING
|
||||
"dasd_generic discipline not found for %s\n",
|
||||
dev_name(&cdev->dev));
|
||||
pr_warning("%s Setting the DASD online failed because of a "
|
||||
"missing discipline\n", dev_name(&cdev->dev));
|
||||
rc = -ENODEV;
|
||||
dasd_set_target_state(device, DASD_STATE_NEW);
|
||||
if (device->block)
|
||||
|
|
@ -2314,13 +2325,13 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
|
|||
open_count = atomic_read(&device->block->open_count);
|
||||
if (open_count > max_count) {
|
||||
if (open_count > 0)
|
||||
printk(KERN_WARNING "Can't offline dasd "
|
||||
"device with open count = %i.\n",
|
||||
open_count);
|
||||
pr_warning("%s: The DASD cannot be set offline "
|
||||
"with open count %i\n",
|
||||
dev_name(&cdev->dev), open_count);
|
||||
else
|
||||
printk(KERN_WARNING "%s",
|
||||
"Can't offline dasd device due "
|
||||
"to internal use\n");
|
||||
pr_warning("%s: The DASD cannot be set offline "
|
||||
"while it is in use\n",
|
||||
dev_name(&cdev->dev));
|
||||
clear_bit(DASD_FLAG_OFFLINE, &device->flags);
|
||||
dasd_put_device(device);
|
||||
return -EBUSY;
|
||||
|
|
@ -2393,8 +2404,10 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
|
|||
cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);
|
||||
|
||||
if (IS_ERR(cqr)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"Could not allocate RDC request");
|
||||
/* internal error 13 - Allocating the RDC request failed*/
|
||||
dev_err(&device->cdev->dev,
|
||||
"An error occurred in the DASD device driver, "
|
||||
"reason=%s\n", "13");
|
||||
return cqr;
|
||||
}
|
||||
|
||||
|
|
@ -2431,6 +2444,40 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
|
||||
|
||||
/*
|
||||
* In command mode and transport mode we need to look for sense
|
||||
* data in different places. The sense data itself is allways
|
||||
* an array of 32 bytes, so we can unify the sense data access
|
||||
* for both modes.
|
||||
*/
|
||||
char *dasd_get_sense(struct irb *irb)
|
||||
{
|
||||
struct tsb *tsb = NULL;
|
||||
char *sense = NULL;
|
||||
|
||||
if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) {
|
||||
if (irb->scsw.tm.tcw)
|
||||
tsb = tcw_get_tsb((struct tcw *)(unsigned long)
|
||||
irb->scsw.tm.tcw);
|
||||
if (tsb && tsb->length == 64 && tsb->flags)
|
||||
switch (tsb->flags & 0x07) {
|
||||
case 1: /* tsa_iostat */
|
||||
sense = tsb->tsa.iostat.sense;
|
||||
break;
|
||||
case 2: /* tsa_ddpc */
|
||||
sense = tsb->tsa.ddpc.sense;
|
||||
break;
|
||||
default:
|
||||
/* currently we don't use interrogate data */
|
||||
break;
|
||||
}
|
||||
} else if (irb->esw.esw0.erw.cons) {
|
||||
sense = irb->ecw;
|
||||
}
|
||||
return sense;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dasd_get_sense);
|
||||
|
||||
static int __init dasd_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
|
@ -2472,7 +2519,7 @@ static int __init dasd_init(void)
|
|||
|
||||
return 0;
|
||||
failed:
|
||||
MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors");
|
||||
pr_info("The DASD device driver could not be initialized\n");
|
||||
dasd_exit();
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
|||
* Author(s): Stefan Weinhuber <wein@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include "dasd_int.h"
|
||||
|
|
@ -503,7 +505,7 @@ static void lcu_update_work(struct work_struct *work)
|
|||
*/
|
||||
spin_lock_irqsave(&lcu->lock, flags);
|
||||
if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "could not update"
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "could not update"
|
||||
" alias data in lcu (rc = %d), retry later", rc);
|
||||
schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
|
||||
} else {
|
||||
|
|
@ -646,14 +648,16 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,
|
|||
{
|
||||
struct dasd_ccw_req *cqr;
|
||||
int rc = 0;
|
||||
struct ccw1 *ccw;
|
||||
|
||||
cqr = lcu->rsu_cqr;
|
||||
strncpy((char *) &cqr->magic, "ECKD", 4);
|
||||
ASCEBC((char *) &cqr->magic, 4);
|
||||
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK;
|
||||
cqr->cpaddr->flags = 0 ;
|
||||
cqr->cpaddr->count = 16;
|
||||
cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
|
||||
ccw = cqr->cpaddr;
|
||||
ccw->cmd_code = DASD_ECKD_CCW_RSCK;
|
||||
ccw->flags = 0 ;
|
||||
ccw->count = 16;
|
||||
ccw->cda = (__u32)(addr_t) cqr->data;
|
||||
((char *)cqr->data)[0] = reason;
|
||||
|
||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||
|
|
@ -855,16 +859,25 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
|
|||
struct alias_lcu *lcu;
|
||||
char reason;
|
||||
struct dasd_eckd_private *private;
|
||||
char *sense;
|
||||
|
||||
private = (struct dasd_eckd_private *) device->private;
|
||||
|
||||
reason = irb->ecw[8];
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s %x",
|
||||
"eckd handle summary unit check: reason", reason);
|
||||
sense = dasd_get_sense(irb);
|
||||
if (sense) {
|
||||
reason = sense[8];
|
||||
DBF_DEV_EVENT(DBF_NOTICE, device, "%s %x",
|
||||
"eckd handle summary unit check: reason", reason);
|
||||
} else {
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"eckd handle summary unit check:"
|
||||
" no reason code available");
|
||||
return;
|
||||
}
|
||||
|
||||
lcu = private->lcu;
|
||||
if (!lcu) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"device not ready to handle summary"
|
||||
" unit check (no lcu structure)");
|
||||
return;
|
||||
|
|
@ -877,7 +890,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
|
|||
* the next interrupt on a different device
|
||||
*/
|
||||
if (list_empty(&device->alias_list)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"device is in offline processing,"
|
||||
" don't do summary unit check handling");
|
||||
spin_unlock(&lcu->lock);
|
||||
|
|
@ -885,7 +898,7 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
|
|||
}
|
||||
if (lcu->suc_data.device) {
|
||||
/* already scheduled or running */
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"previous instance of summary unit check worker"
|
||||
" still pending");
|
||||
spin_unlock(&lcu->lock);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -67,6 +69,8 @@ int dasd_probeonly = 0; /* is true, when probeonly mode is active */
|
|||
int dasd_autodetect = 0; /* is true, when autodetection is active */
|
||||
int dasd_nopav = 0; /* is true, when PAV is disabled */
|
||||
EXPORT_SYMBOL_GPL(dasd_nopav);
|
||||
int dasd_nofcx; /* disable High Performance Ficon */
|
||||
EXPORT_SYMBOL_GPL(dasd_nofcx);
|
||||
|
||||
/*
|
||||
* char *dasd[] is intended to hold the ranges supplied by the dasd= statement
|
||||
|
|
@ -125,6 +129,7 @@ __setup ("dasd=", dasd_call_setup);
|
|||
* Read a device busid/devno from a string.
|
||||
*/
|
||||
static int
|
||||
|
||||
dasd_busid(char **str, int *id0, int *id1, int *devno)
|
||||
{
|
||||
int val, old_style;
|
||||
|
|
@ -132,8 +137,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
|
|||
/* Interpret ipldev busid */
|
||||
if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) {
|
||||
if (ipl_info.type != IPL_TYPE_CCW) {
|
||||
MESSAGE(KERN_ERR, "%s", "ipl device is not a ccw "
|
||||
"device");
|
||||
pr_err("The IPL device is not a CCW device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
*id0 = 0;
|
||||
|
|
@ -209,9 +213,8 @@ dasd_feature_list(char *str, char **endp)
|
|||
else if (len == 8 && !strncmp(str, "failfast", 8))
|
||||
features |= DASD_FEATURE_FAILFAST;
|
||||
else {
|
||||
MESSAGE(KERN_WARNING,
|
||||
"unsupported feature: %*s, "
|
||||
"ignoring setting", len, str);
|
||||
pr_warning("%*s is not a supported device option\n",
|
||||
len, str);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
str += len;
|
||||
|
|
@ -220,8 +223,8 @@ dasd_feature_list(char *str, char **endp)
|
|||
str++;
|
||||
}
|
||||
if (*str != ')') {
|
||||
MESSAGE(KERN_WARNING, "%s",
|
||||
"missing ')' in dasd parameter string\n");
|
||||
pr_warning("A closing parenthesis ')' is missing in the "
|
||||
"dasd= parameter\n");
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
str++;
|
||||
|
|
@ -253,25 +256,29 @@ dasd_parse_keyword( char *parsestring ) {
|
|||
}
|
||||
if (strncmp("autodetect", parsestring, length) == 0) {
|
||||
dasd_autodetect = 1;
|
||||
MESSAGE (KERN_INFO, "%s",
|
||||
"turning to autodetection mode");
|
||||
pr_info("The autodetection mode has been activated\n");
|
||||
return residual_str;
|
||||
}
|
||||
if (strncmp("probeonly", parsestring, length) == 0) {
|
||||
dasd_probeonly = 1;
|
||||
MESSAGE(KERN_INFO, "%s",
|
||||
"turning to probeonly mode");
|
||||
pr_info("The probeonly mode has been activated\n");
|
||||
return residual_str;
|
||||
}
|
||||
if (strncmp("nopav", parsestring, length) == 0) {
|
||||
if (MACHINE_IS_VM)
|
||||
MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM");
|
||||
pr_info("'nopav' is not supported on z/VM\n");
|
||||
else {
|
||||
dasd_nopav = 1;
|
||||
MESSAGE(KERN_INFO, "%s", "disable PAV mode");
|
||||
pr_info("PAV support has be deactivated\n");
|
||||
}
|
||||
return residual_str;
|
||||
}
|
||||
if (strncmp("nofcx", parsestring, length) == 0) {
|
||||
dasd_nofcx = 1;
|
||||
pr_info("High Performance FICON support has been "
|
||||
"deactivated\n");
|
||||
return residual_str;
|
||||
}
|
||||
if (strncmp("fixedbuffers", parsestring, length) == 0) {
|
||||
if (dasd_page_cache)
|
||||
return residual_str;
|
||||
|
|
@ -280,10 +287,10 @@ dasd_parse_keyword( char *parsestring ) {
|
|||
PAGE_SIZE, SLAB_CACHE_DMA,
|
||||
NULL);
|
||||
if (!dasd_page_cache)
|
||||
MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
|
||||
DBF_EVENT(DBF_WARNING, "%s", "Failed to create slab, "
|
||||
"fixed buffer mode disabled.");
|
||||
else
|
||||
MESSAGE (KERN_INFO, "%s",
|
||||
DBF_EVENT(DBF_INFO, "%s",
|
||||
"turning on fixed buffer mode");
|
||||
return residual_str;
|
||||
}
|
||||
|
|
@ -321,7 +328,7 @@ dasd_parse_range( char *parsestring ) {
|
|||
(from_id0 != to_id0 || from_id1 != to_id1 || from > to))
|
||||
rc = -EINVAL;
|
||||
if (rc) {
|
||||
MESSAGE(KERN_ERR, "Invalid device range %s", parsestring);
|
||||
pr_err("%s is not a valid device range\n", parsestring);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
features = dasd_feature_list(str, &str);
|
||||
|
|
@ -340,8 +347,8 @@ dasd_parse_range( char *parsestring ) {
|
|||
return str + 1;
|
||||
if (*str == '\0')
|
||||
return str;
|
||||
MESSAGE(KERN_WARNING,
|
||||
"junk at end of dasd parameter string: %s\n", str);
|
||||
pr_warning("The dasd= parameter value %s has an invalid ending\n",
|
||||
str);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -144,8 +146,8 @@ dasd_diag_erp(struct dasd_device *device)
|
|||
mdsk_term_io(device);
|
||||
rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
|
||||
if (rc)
|
||||
DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
|
||||
"rc=%d", rc);
|
||||
dev_warn(&device->cdev->dev, "DIAG ERP failed with "
|
||||
"rc=%d\n", rc);
|
||||
}
|
||||
|
||||
/* Start a given request at the device. Return zero on success, non-zero
|
||||
|
|
@ -160,7 +162,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
|
|||
|
||||
device = cqr->startdev;
|
||||
if (cqr->retries < 0) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
|
||||
DBF_DEV_EVENT(DBF_ERR, device, "DIAG start_IO: request %p "
|
||||
"- no retry left)", cqr);
|
||||
cqr->status = DASD_CQR_ERROR;
|
||||
return -EIO;
|
||||
|
|
@ -195,7 +197,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
|
|||
break;
|
||||
default: /* Error condition */
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc);
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "dia250 returned rc=%d", rc);
|
||||
dasd_diag_erp(device);
|
||||
rc = -EIO;
|
||||
break;
|
||||
|
|
@ -243,13 +245,14 @@ dasd_ext_handler(__u16 code)
|
|||
return;
|
||||
}
|
||||
if (!ip) { /* no intparm: unsolicited interrupt */
|
||||
MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
|
||||
DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited "
|
||||
"interrupt");
|
||||
return;
|
||||
}
|
||||
cqr = (struct dasd_ccw_req *) ip;
|
||||
device = (struct dasd_device *) cqr->startdev;
|
||||
if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device,
|
||||
DBF_DEV_EVENT(DBF_WARNING, device,
|
||||
" magic number of dasd_ccw_req 0x%08X doesn't"
|
||||
" match discipline 0x%08X",
|
||||
cqr->magic, *(int *) (&device->discipline->name));
|
||||
|
|
@ -281,15 +284,11 @@ dasd_ext_handler(__u16 code)
|
|||
rc = dasd_start_diag(next);
|
||||
if (rc == 0)
|
||||
expires = next->expires;
|
||||
else if (rc != -EACCES)
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"Interrupt fastpath "
|
||||
"failed!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cqr->status = DASD_CQR_QUEUED;
|
||||
DEV_MESSAGE(KERN_WARNING, device, "interrupt status for "
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device, "interrupt status for "
|
||||
"request %p was %d (%d retries left)", cqr, status,
|
||||
cqr->retries);
|
||||
dasd_diag_erp(device);
|
||||
|
|
@ -322,8 +321,9 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
if (private == NULL) {
|
||||
private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
|
||||
if (private == NULL) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"memory allocation failed for private data");
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"Allocating memory for private DASD data "
|
||||
"failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ccw_device_get_id(device->cdev, &private->dev_id);
|
||||
|
|
@ -331,7 +331,7 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
}
|
||||
block = dasd_alloc_block();
|
||||
if (IS_ERR(block)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"could not allocate dasd block structure");
|
||||
device->private = NULL;
|
||||
kfree(private);
|
||||
|
|
@ -347,7 +347,7 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
|
||||
rc = diag210((struct diag210 *) rdc_data);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device "
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "failed to retrieve device "
|
||||
"information (rc=%d)", rc);
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
|
|
@ -362,8 +362,8 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
private->pt_block = 2;
|
||||
break;
|
||||
default:
|
||||
DEV_MESSAGE(KERN_WARNING, device, "unsupported device class "
|
||||
"(class=%d)", private->rdc_data.vdev_class);
|
||||
dev_warn(&device->cdev->dev, "Device type %d is not supported "
|
||||
"in DIAG mode\n", private->rdc_data.vdev_class);
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -380,7 +380,7 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
/* figure out blocksize of device */
|
||||
label = (struct vtoc_cms_label *) get_zeroed_page(GFP_KERNEL);
|
||||
if (label == NULL) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"No memory to allocate initialization request");
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
|
|
@ -404,8 +404,8 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
|
||||
rc = dia250(&private->iob, RW_BIO);
|
||||
if (rc == 3) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"DIAG call failed");
|
||||
dev_warn(&device->cdev->dev,
|
||||
"A 64-bit DIAG call failed\n");
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out_label;
|
||||
}
|
||||
|
|
@ -414,8 +414,8 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
break;
|
||||
}
|
||||
if (bsize > PAGE_SIZE) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "device access failed "
|
||||
"(rc=%d)", rc);
|
||||
dev_warn(&device->cdev->dev, "Accessing the DASD failed because"
|
||||
" of an incorrect format (rc=%d)\n", rc);
|
||||
rc = -EIO;
|
||||
goto out_label;
|
||||
}
|
||||
|
|
@ -433,15 +433,15 @@ dasd_diag_check_device(struct dasd_device *device)
|
|||
block->s2b_shift++;
|
||||
rc = mdsk_init_io(device, block->bp_block, 0, NULL);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
|
||||
"failed (rc=%d)", rc);
|
||||
dev_warn(&device->cdev->dev, "DIAG initialization "
|
||||
"failed with rc=%d\n", rc);
|
||||
rc = -EIO;
|
||||
} else {
|
||||
DEV_MESSAGE(KERN_INFO, device,
|
||||
"(%ld B/blk): %ldkB",
|
||||
(unsigned long) block->bp_block,
|
||||
(unsigned long) (block->blocks <<
|
||||
block->s2b_shift) >> 1);
|
||||
dev_info(&device->cdev->dev,
|
||||
"New DASD with %ld byte/block, total size %ld KB\n",
|
||||
(unsigned long) block->bp_block,
|
||||
(unsigned long) (block->blocks <<
|
||||
block->s2b_shift) >> 1);
|
||||
}
|
||||
out_label:
|
||||
free_page((long) label);
|
||||
|
|
@ -595,7 +595,7 @@ static void
|
|||
dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
||||
struct irb *stat)
|
||||
{
|
||||
DEV_MESSAGE(KERN_ERR, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"dump sense not available for DIAG data");
|
||||
}
|
||||
|
||||
|
|
@ -621,10 +621,8 @@ static int __init
|
|||
dasd_diag_init(void)
|
||||
{
|
||||
if (!MACHINE_IS_VM) {
|
||||
MESSAGE_LOG(KERN_INFO,
|
||||
"Machine is not VM: %s "
|
||||
"discipline not initializing",
|
||||
dasd_diag_discipline.name);
|
||||
pr_info("Discipline %s cannot be used without z/VM\n",
|
||||
dasd_diag_discipline.name);
|
||||
return -ENODEV;
|
||||
}
|
||||
ASCEBC(dasd_diag_discipline.ebcname, 4);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -38,8 +38,11 @@
|
|||
#define DASD_ECKD_CCW_RELEASE 0x94
|
||||
#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
|
||||
#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
|
||||
#define DASD_ECKD_CCW_WRITE_TRACK_DATA 0xA5
|
||||
#define DASD_ECKD_CCW_READ_TRACK_DATA 0xA6
|
||||
#define DASD_ECKD_CCW_RESERVE 0xB4
|
||||
#define DASD_ECKD_CCW_PFX 0xE7
|
||||
#define DASD_ECKD_CCW_PFX_READ 0xEA
|
||||
#define DASD_ECKD_CCW_RSCK 0xF9
|
||||
|
||||
/*
|
||||
|
|
@ -48,6 +51,11 @@
|
|||
#define PSF_ORDER_PRSSD 0x18
|
||||
#define PSF_ORDER_SSC 0x1D
|
||||
|
||||
/*
|
||||
* Size that is reportet for large volumes in the old 16-bit no_cyl field
|
||||
*/
|
||||
#define LV_COMPAT_CYL 0xFFFE
|
||||
|
||||
/*****************************************************************************
|
||||
* SECTION: Type Definitions
|
||||
****************************************************************************/
|
||||
|
|
@ -118,7 +126,9 @@ struct DE_eckd_data {
|
|||
unsigned long long ep_sys_time; /* Ext Parameter - System Time Stamp */
|
||||
__u8 ep_format; /* Extended Parameter format byte */
|
||||
__u8 ep_prio; /* Extended Parameter priority I/O byte */
|
||||
__u8 ep_reserved[6]; /* Extended Parameter Reserved */
|
||||
__u8 ep_reserved1; /* Extended Parameter Reserved */
|
||||
__u8 ep_rec_per_track; /* Number of records on a track */
|
||||
__u8 ep_reserved[4]; /* Extended Parameter Reserved */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct LO_eckd_data {
|
||||
|
|
@ -139,11 +149,37 @@ struct LO_eckd_data {
|
|||
__u16 length;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct LRE_eckd_data {
|
||||
struct {
|
||||
unsigned char orientation:2;
|
||||
unsigned char operation:6;
|
||||
} __attribute__ ((packed)) operation;
|
||||
struct {
|
||||
unsigned char length_valid:1;
|
||||
unsigned char length_scope:1;
|
||||
unsigned char imbedded_ccw_valid:1;
|
||||
unsigned char check_bytes:2;
|
||||
unsigned char imbedded_count_valid:1;
|
||||
unsigned char reserved:1;
|
||||
unsigned char read_count_suffix:1;
|
||||
} __attribute__ ((packed)) auxiliary;
|
||||
__u8 imbedded_ccw;
|
||||
__u8 count;
|
||||
struct ch_t seek_addr;
|
||||
struct chr_t search_arg;
|
||||
__u8 sector;
|
||||
__u16 length;
|
||||
__u8 imbedded_count;
|
||||
__u8 extended_operation;
|
||||
__u16 extended_parameter_length;
|
||||
__u8 extended_parameter[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Prefix data for format 0x00 and 0x01 */
|
||||
struct PFX_eckd_data {
|
||||
unsigned char format;
|
||||
struct {
|
||||
unsigned char define_extend:1;
|
||||
unsigned char define_extent:1;
|
||||
unsigned char time_stamp:1;
|
||||
unsigned char verify_base:1;
|
||||
unsigned char hyper_pav:1;
|
||||
|
|
@ -153,9 +189,8 @@ struct PFX_eckd_data {
|
|||
__u8 aux;
|
||||
__u8 base_lss;
|
||||
__u8 reserved[7];
|
||||
struct DE_eckd_data define_extend;
|
||||
struct LO_eckd_data locate_record;
|
||||
__u8 LO_extended_data[4];
|
||||
struct DE_eckd_data define_extent;
|
||||
struct LRE_eckd_data locate_record;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct dasd_eckd_characteristics {
|
||||
|
|
@ -228,7 +263,8 @@ struct dasd_eckd_characteristics {
|
|||
__u8 factor7;
|
||||
__u8 factor8;
|
||||
__u8 reserved2[3];
|
||||
__u8 reserved3[10];
|
||||
__u8 reserved3[6];
|
||||
__u32 long_no_cyl;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* elements of the configuration data */
|
||||
|
|
@ -406,6 +442,7 @@ struct dasd_eckd_private {
|
|||
int uses_cdl;
|
||||
struct attrib_data_t attrib; /* e.g. cache operations */
|
||||
struct dasd_rssd_features features;
|
||||
u32 real_cyl;
|
||||
|
||||
/* alias managemnet */
|
||||
struct dasd_uid uid;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
* Author(s): Stefan Weinhuber <wein@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -297,11 +299,12 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,
|
|||
struct dasd_eer_header header;
|
||||
unsigned long flags;
|
||||
struct eerbuffer *eerb;
|
||||
char *sense;
|
||||
|
||||
/* go through cqr chain and count the valid sense data sets */
|
||||
data_size = 0;
|
||||
for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers)
|
||||
if (temp_cqr->irb.esw.esw0.erw.cons)
|
||||
if (dasd_get_sense(&temp_cqr->irb))
|
||||
data_size += 32;
|
||||
|
||||
header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
|
||||
|
|
@ -316,9 +319,11 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device,
|
|||
list_for_each_entry(eerb, &bufferlist, list) {
|
||||
dasd_eer_start_record(eerb, header.total_size);
|
||||
dasd_eer_write_buffer(eerb, (char *) &header, sizeof(header));
|
||||
for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers)
|
||||
if (temp_cqr->irb.esw.esw0.erw.cons)
|
||||
dasd_eer_write_buffer(eerb, cqr->irb.ecw, 32);
|
||||
for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) {
|
||||
sense = dasd_get_sense(&temp_cqr->irb);
|
||||
if (sense)
|
||||
dasd_eer_write_buffer(eerb, sense, 32);
|
||||
}
|
||||
dasd_eer_write_buffer(eerb, "EOR", 4);
|
||||
}
|
||||
spin_unlock_irqrestore(&bufferlock, flags);
|
||||
|
|
@ -451,6 +456,7 @@ int dasd_eer_enable(struct dasd_device *device)
|
|||
{
|
||||
struct dasd_ccw_req *cqr;
|
||||
unsigned long flags;
|
||||
struct ccw1 *ccw;
|
||||
|
||||
if (device->eer_cqr)
|
||||
return 0;
|
||||
|
|
@ -468,10 +474,11 @@ int dasd_eer_enable(struct dasd_device *device)
|
|||
cqr->expires = 10 * HZ;
|
||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||
|
||||
cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS;
|
||||
cqr->cpaddr->count = SNSS_DATA_SIZE;
|
||||
cqr->cpaddr->flags = 0;
|
||||
cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
|
||||
ccw = cqr->cpaddr;
|
||||
ccw->cmd_code = DASD_ECKD_CCW_SNSS;
|
||||
ccw->count = SNSS_DATA_SIZE;
|
||||
ccw->flags = 0;
|
||||
ccw->cda = (__u32)(addr_t) cqr->data;
|
||||
|
||||
cqr->buildclk = get_clock();
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
|
|
@ -534,7 +541,7 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
|
|||
if (eerb->buffer_page_count < 1 ||
|
||||
eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
|
||||
kfree(eerb);
|
||||
MESSAGE(KERN_WARNING, "can't open device since module "
|
||||
DBF_EVENT(DBF_WARNING, "can't open device since module "
|
||||
"parameter eer_pages is smaller than 1 or"
|
||||
" bigger than %d", (int)(INT_MAX / PAGE_SIZE));
|
||||
unlock_kernel();
|
||||
|
|
@ -687,7 +694,7 @@ int __init dasd_eer_init(void)
|
|||
if (rc) {
|
||||
kfree(dasd_eer_dev);
|
||||
dasd_eer_dev = NULL;
|
||||
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
|
||||
DBF_EVENT(DBF_ERR, "%s", "dasd_eer_init could not "
|
||||
"register misc device");
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
|
|
@ -91,14 +93,14 @@ dasd_default_erp_action(struct dasd_ccw_req *cqr)
|
|||
|
||||
/* just retry - there is nothing to save ... I got no sense data.... */
|
||||
if (cqr->retries > 0) {
|
||||
DEV_MESSAGE (KERN_DEBUG, device,
|
||||
DBF_DEV_EVENT(DBF_DEBUG, device,
|
||||
"default ERP called (%i retries left)",
|
||||
cqr->retries);
|
||||
cqr->lpm = LPM_ANYPATH;
|
||||
cqr->status = DASD_CQR_FILLED;
|
||||
} else {
|
||||
DEV_MESSAGE (KERN_WARNING, device, "%s",
|
||||
"default ERP called (NO retry left)");
|
||||
dev_err(&device->cdev->dev,
|
||||
"default ERP has run out of retries and failed\n");
|
||||
cqr->status = DASD_CQR_FAILED;
|
||||
cqr->stopclk = get_clock();
|
||||
}
|
||||
|
|
@ -162,8 +164,21 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
|
|||
device->discipline->dump_sense(device, cqr, irb);
|
||||
}
|
||||
|
||||
void
|
||||
dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb)
|
||||
{
|
||||
struct dasd_device *device;
|
||||
|
||||
device = cqr->startdev;
|
||||
/* dump sense data to s390 debugfeature*/
|
||||
if (device->discipline && device->discipline->dump_sense_dbf)
|
||||
device->discipline->dump_sense_dbf(device, cqr, irb, "log");
|
||||
}
|
||||
EXPORT_SYMBOL(dasd_log_sense_dbf);
|
||||
|
||||
EXPORT_SYMBOL(dasd_default_erp_action);
|
||||
EXPORT_SYMBOL(dasd_default_erp_postaction);
|
||||
EXPORT_SYMBOL(dasd_alloc_erp_request);
|
||||
EXPORT_SYMBOL(dasd_free_erp_request);
|
||||
EXPORT_SYMBOL(dasd_log_sense);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/debug.h>
|
||||
|
|
@ -128,17 +130,18 @@ dasd_fba_check_characteristics(struct dasd_device *device)
|
|||
private = kzalloc(sizeof(struct dasd_fba_private),
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (private == NULL) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"memory allocation failed for private "
|
||||
"data");
|
||||
dev_warn(&device->cdev->dev,
|
||||
"Allocating memory for private DASD "
|
||||
"data failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
device->private = (void *) private;
|
||||
}
|
||||
block = dasd_alloc_block();
|
||||
if (IS_ERR(block)) {
|
||||
DEV_MESSAGE(KERN_WARNING, device, "%s",
|
||||
"could not allocate dasd block structure");
|
||||
DBF_EVENT(DBF_WARNING, "could not allocate dasd block "
|
||||
"structure for device: %s",
|
||||
dev_name(&device->cdev->dev));
|
||||
device->private = NULL;
|
||||
kfree(private);
|
||||
return PTR_ERR(block);
|
||||
|
|
@ -150,9 +153,9 @@ dasd_fba_check_characteristics(struct dasd_device *device)
|
|||
rdc_data = (void *) &(private->rdc_data);
|
||||
rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_WARNING, device,
|
||||
"Read device characteristics returned error %d",
|
||||
rc);
|
||||
DBF_EVENT(DBF_WARNING, "Read device characteristics returned "
|
||||
"error %d for device: %s",
|
||||
rc, dev_name(&device->cdev->dev));
|
||||
device->block = NULL;
|
||||
dasd_free_block(block);
|
||||
device->private = NULL;
|
||||
|
|
@ -160,15 +163,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)
|
|||
return rc;
|
||||
}
|
||||
|
||||
DEV_MESSAGE(KERN_INFO, device,
|
||||
"%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)",
|
||||
cdev->id.dev_type,
|
||||
cdev->id.dev_model,
|
||||
cdev->id.cu_type,
|
||||
cdev->id.cu_model,
|
||||
((private->rdc_data.blk_bdsa *
|
||||
(private->rdc_data.blk_size >> 9)) >> 11),
|
||||
private->rdc_data.blk_size);
|
||||
dev_info(&device->cdev->dev,
|
||||
"New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB "
|
||||
"and %d B/blk\n",
|
||||
cdev->id.dev_type,
|
||||
cdev->id.dev_model,
|
||||
cdev->id.cu_type,
|
||||
cdev->id.cu_model,
|
||||
((private->rdc_data.blk_bdsa *
|
||||
(private->rdc_data.blk_size >> 9)) >> 11),
|
||||
private->rdc_data.blk_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +184,7 @@ static int dasd_fba_do_analysis(struct dasd_block *block)
|
|||
private = (struct dasd_fba_private *) block->base->private;
|
||||
rc = dasd_check_blocksize(private->rdc_data.blk_size);
|
||||
if (rc) {
|
||||
DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
|
||||
DBF_DEV_EVENT(DBF_WARNING, block->base, "unknown blocksize %d",
|
||||
private->rdc_data.blk_size);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -215,7 +219,7 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
|
|||
if (cqr->function == dasd_default_erp_action)
|
||||
return dasd_default_erp_postaction;
|
||||
|
||||
DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
|
||||
DBF_DEV_EVENT(DBF_WARNING, cqr->startdev, "unknown ERP action %p",
|
||||
cqr->function);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -233,9 +237,9 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
|
|||
}
|
||||
|
||||
/* check for unsolicited interrupts */
|
||||
DEV_MESSAGE(KERN_DEBUG, device, "%s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"unsolicited interrupt received");
|
||||
device->discipline->dump_sense(device, NULL, irb);
|
||||
device->discipline->dump_sense_dbf(device, NULL, irb, "unsolicited");
|
||||
dasd_schedule_device_bh(device);
|
||||
return;
|
||||
};
|
||||
|
|
@ -436,6 +440,25 @@ dasd_fba_fill_info(struct dasd_device * device,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dasd_fba_dump_sense_dbf(struct dasd_device *device, struct dasd_ccw_req *req,
|
||||
struct irb *irb, char *reason)
|
||||
{
|
||||
int sl;
|
||||
if (irb->esw.esw0.erw.cons) {
|
||||
for (sl = 0; sl < 4; sl++) {
|
||||
DBF_DEV_EVENT(DBF_EMERG, device,
|
||||
"%s: %08x %08x %08x %08x",
|
||||
reason, irb->ecw[8 * 0], irb->ecw[8 * 1],
|
||||
irb->ecw[8 * 2], irb->ecw[8 * 3]);
|
||||
}
|
||||
} else {
|
||||
DBF_DEV_EVENT(DBF_EMERG, device, "%s",
|
||||
"SORRY - NO VALID SENSE AVAILABLE\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
||||
struct irb *irb)
|
||||
|
|
@ -446,7 +469,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
|||
|
||||
page = (char *) get_zeroed_page(GFP_ATOMIC);
|
||||
if (page == NULL) {
|
||||
DEV_MESSAGE(KERN_ERR, device, " %s",
|
||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
||||
"No memory to dump sense data");
|
||||
return;
|
||||
}
|
||||
|
|
@ -476,8 +499,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
|||
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
|
||||
" SORRY - NO VALID SENSE AVAILABLE\n");
|
||||
}
|
||||
MESSAGE_LOG(KERN_ERR, "%s",
|
||||
page + sizeof(KERN_ERR PRINTK_HEADER));
|
||||
printk(KERN_ERR "%s", page);
|
||||
|
||||
/* dump the Channel Program */
|
||||
/* print first CCWs (maximum 8) */
|
||||
|
|
@ -498,8 +520,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
|||
len += sprintf(page + len, "\n");
|
||||
act++;
|
||||
}
|
||||
MESSAGE_LOG(KERN_ERR, "%s",
|
||||
page + sizeof(KERN_ERR PRINTK_HEADER));
|
||||
printk(KERN_ERR "%s", page);
|
||||
|
||||
|
||||
/* print failing CCW area */
|
||||
|
|
@ -540,8 +561,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
|||
act++;
|
||||
}
|
||||
if (len > 0)
|
||||
MESSAGE_LOG(KERN_ERR, "%s",
|
||||
page + sizeof(KERN_ERR PRINTK_HEADER));
|
||||
printk(KERN_ERR "%s", page);
|
||||
free_page((unsigned long) page);
|
||||
}
|
||||
|
||||
|
|
@ -576,6 +596,7 @@ static struct dasd_discipline dasd_fba_discipline = {
|
|||
.build_cp = dasd_fba_build_cp,
|
||||
.free_cp = dasd_fba_free_cp,
|
||||
.dump_sense = dasd_fba_dump_sense,
|
||||
.dump_sense_dbf = dasd_fba_dump_sense_dbf,
|
||||
.fill_info = dasd_fba_fill_info,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/blkpg.h>
|
||||
|
|
@ -163,9 +165,8 @@ int dasd_gendisk_init(void)
|
|||
/* Register to static dasd major 94 */
|
||||
rc = register_blkdev(DASD_MAJOR, "dasd");
|
||||
if (rc != 0) {
|
||||
MESSAGE(KERN_WARNING,
|
||||
"Couldn't register successfully to "
|
||||
"major no %d", DASD_MAJOR);
|
||||
pr_warning("Registering the device driver with major number "
|
||||
"%d failed\n", DASD_MAJOR);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ do { \
|
|||
d_data); \
|
||||
} while(0)
|
||||
|
||||
/* limit size for an errorstring */
|
||||
#define ERRORLENGTH 30
|
||||
|
||||
/* definition of dbf debug levels */
|
||||
#define DBF_EMERG 0 /* system is unusable */
|
||||
#define DBF_ALERT 1 /* action must be taken immediately */
|
||||
|
|
@ -157,7 +160,8 @@ struct dasd_ccw_req {
|
|||
struct dasd_block *block; /* the originating block device */
|
||||
struct dasd_device *memdev; /* the device used to allocate this */
|
||||
struct dasd_device *startdev; /* device the request is started on */
|
||||
struct ccw1 *cpaddr; /* address of channel program */
|
||||
void *cpaddr; /* address of ccw or tcw */
|
||||
unsigned char cpmode; /* 0 = cmd mode, 1 = itcw */
|
||||
char status; /* status of this request */
|
||||
short retries; /* A retry counter */
|
||||
unsigned long flags; /* flags of this request */
|
||||
|
|
@ -280,6 +284,8 @@ struct dasd_discipline {
|
|||
dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
|
||||
void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
|
||||
struct irb *);
|
||||
void (*dump_sense_dbf) (struct dasd_device *, struct dasd_ccw_req *,
|
||||
struct irb *, char *);
|
||||
|
||||
void (*handle_unsolicited_interrupt) (struct dasd_device *,
|
||||
struct irb *);
|
||||
|
|
@ -378,7 +384,7 @@ struct dasd_block {
|
|||
struct block_device *bdev;
|
||||
atomic_t open_count;
|
||||
|
||||
unsigned long blocks; /* size of volume in blocks */
|
||||
unsigned long long blocks; /* size of volume in blocks */
|
||||
unsigned int bp_block; /* bytes per block */
|
||||
unsigned int s2b_shift; /* log2 (bp_block/512) */
|
||||
|
||||
|
|
@ -573,12 +579,14 @@ int dasd_generic_notify(struct ccw_device *, int);
|
|||
void dasd_generic_handle_state_change(struct dasd_device *);
|
||||
|
||||
int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
|
||||
char *dasd_get_sense(struct irb *);
|
||||
|
||||
/* externals in dasd_devmap.c */
|
||||
extern int dasd_max_devindex;
|
||||
extern int dasd_probeonly;
|
||||
extern int dasd_autodetect;
|
||||
extern int dasd_nopav;
|
||||
extern int dasd_nofcx;
|
||||
|
||||
int dasd_devmap_init(void);
|
||||
void dasd_devmap_exit(void);
|
||||
|
|
@ -623,6 +631,7 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
|
|||
struct dasd_device *);
|
||||
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
|
||||
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
|
||||
void dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb);
|
||||
|
||||
/* externals in dasd_3990_erp.c */
|
||||
struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
*
|
||||
* i/o controls for the dasd driver.
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/fs.h>
|
||||
|
|
@ -94,7 +97,8 @@ static int dasd_ioctl_quiesce(struct dasd_block *block)
|
|||
if (!capable (CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
|
||||
dev_info(&base->cdev->dev, "The DASD has been put in the quiesce "
|
||||
"state\n");
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
base->stopped |= DASD_STOPPED_QUIESCE;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
|
|
@ -103,7 +107,7 @@ static int dasd_ioctl_quiesce(struct dasd_block *block)
|
|||
|
||||
|
||||
/*
|
||||
* Quiesce device.
|
||||
* Resume device.
|
||||
*/
|
||||
static int dasd_ioctl_resume(struct dasd_block *block)
|
||||
{
|
||||
|
|
@ -114,7 +118,8 @@ static int dasd_ioctl_resume(struct dasd_block *block)
|
|||
if (!capable (CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
|
||||
DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
|
||||
dev_info(&base->cdev->dev, "I/O operations have been resumed "
|
||||
"on the DASD\n");
|
||||
spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
|
||||
base->stopped &= ~DASD_STOPPED_QUIESCE;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
|
||||
|
|
@ -140,13 +145,13 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
|||
return -EPERM;
|
||||
|
||||
if (base->state != DASD_STATE_BASIC) {
|
||||
DEV_MESSAGE(KERN_WARNING, base, "%s",
|
||||
"dasd_format: device is not disabled! ");
|
||||
dev_warn(&base->cdev->dev,
|
||||
"The DASD cannot be formatted while it is enabled\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
DBF_DEV_EVENT(DBF_NOTICE, base,
|
||||
"formatting units %d to %d (%d B blocks) flags %d",
|
||||
"formatting units %u to %u (%u B blocks) flags %u",
|
||||
fdata->start_unit,
|
||||
fdata->stop_unit, fdata->blksize, fdata->intensity);
|
||||
|
||||
|
|
@ -169,10 +174,9 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
|
|||
dasd_sfree_request(cqr, cqr->memdev);
|
||||
if (rc) {
|
||||
if (rc != -ERESTARTSYS)
|
||||
DEV_MESSAGE(KERN_ERR, base,
|
||||
" Formatting of unit %d failed "
|
||||
"with rc = %d",
|
||||
fdata->start_unit, rc);
|
||||
dev_err(&base->cdev->dev,
|
||||
"Formatting unit %d failed with "
|
||||
"rc=%d\n", fdata->start_unit, rc);
|
||||
return rc;
|
||||
}
|
||||
fdata->start_unit++;
|
||||
|
|
@ -199,8 +203,9 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
|
|||
if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
|
||||
return -EFAULT;
|
||||
if (bdev != bdev->bd_contains) {
|
||||
DEV_MESSAGE(KERN_WARNING, block->base, "%s",
|
||||
"Cannot low-level format a partition");
|
||||
dev_warn(&block->base->cdev->dev,
|
||||
"The specified DASD is a partition and cannot be "
|
||||
"formatted\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return dasd_format(block, &fdata);
|
||||
|
|
@ -365,9 +370,9 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int
|
||||
dasd_do_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct dasd_block *block = bdev->bd_disk->private_data;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
|
@ -420,3 +425,14 @@ dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int dasd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
lock_kernel();
|
||||
rc = dasd_do_ioctl(bdev, mode, cmd, arg);
|
||||
unlock_kernel();
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "dasd"
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
|
@ -112,7 +114,7 @@ dasd_devices_show(struct seq_file *m, void *v)
|
|||
seq_printf(m, "n/f ");
|
||||
else
|
||||
seq_printf(m,
|
||||
"at blocksize: %d, %ld blocks, %ld MB",
|
||||
"at blocksize: %d, %lld blocks, %lld MB",
|
||||
block->bp_block, block->blocks,
|
||||
((block->bp_block >> 9) *
|
||||
block->blocks) >> 11);
|
||||
|
|
@ -267,7 +269,7 @@ dasd_statistics_write(struct file *file, const char __user *user_buf,
|
|||
buffer = dasd_get_user_string(user_buf, user_len);
|
||||
if (IS_ERR(buffer))
|
||||
return PTR_ERR(buffer);
|
||||
MESSAGE_LOG(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer);
|
||||
DBF_EVENT(DBF_DEBUG, "/proc/dasd/statictics: '%s'\n", buffer);
|
||||
|
||||
/* check for valid verbs */
|
||||
for (str = buffer; isspace(*str); str++);
|
||||
|
|
@ -277,33 +279,33 @@ dasd_statistics_write(struct file *file, const char __user *user_buf,
|
|||
if (strcmp(str, "on") == 0) {
|
||||
/* switch on statistics profiling */
|
||||
dasd_profile_level = DASD_PROFILE_ON;
|
||||
MESSAGE(KERN_INFO, "%s", "Statistics switched on");
|
||||
pr_info("The statistics feature has been switched "
|
||||
"on\n");
|
||||
} else if (strcmp(str, "off") == 0) {
|
||||
/* switch off and reset statistics profiling */
|
||||
memset(&dasd_global_profile,
|
||||
0, sizeof (struct dasd_profile_info_t));
|
||||
dasd_profile_level = DASD_PROFILE_OFF;
|
||||
MESSAGE(KERN_INFO, "%s", "Statistics switched off");
|
||||
pr_info("The statistics feature has been switched "
|
||||
"off\n");
|
||||
} else
|
||||
goto out_error;
|
||||
} else if (strncmp(str, "reset", 5) == 0) {
|
||||
/* reset the statistics */
|
||||
memset(&dasd_global_profile, 0,
|
||||
sizeof (struct dasd_profile_info_t));
|
||||
MESSAGE(KERN_INFO, "%s", "Statistics reset");
|
||||
pr_info("The statistics have been reset\n");
|
||||
} else
|
||||
goto out_error;
|
||||
kfree(buffer);
|
||||
return user_len;
|
||||
out_error:
|
||||
MESSAGE(KERN_WARNING, "%s",
|
||||
"/proc/dasd/statistics: only 'set on', 'set off' "
|
||||
"and 'reset' are supported verbs");
|
||||
pr_warning("%s is not a supported value for /proc/dasd/statistics\n",
|
||||
str);
|
||||
kfree(buffer);
|
||||
return -EINVAL;
|
||||
#else
|
||||
MESSAGE(KERN_WARNING, "%s",
|
||||
"/proc/dasd/statistics: is not activated in this kernel");
|
||||
pr_warning("/proc/dasd/statistics: is not activated in this kernel\n");
|
||||
return user_len;
|
||||
#endif /* CONFIG_DASD_PROFILE */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,8 +324,6 @@ static inline void tape_proc_cleanup (void) {;}
|
|||
#endif
|
||||
|
||||
/* a function for dumping device sense info */
|
||||
extern void tape_dump_sense(struct tape_device *, struct tape_request *,
|
||||
struct irb *);
|
||||
extern void tape_dump_sense_dbf(struct tape_device *, struct tape_request *,
|
||||
struct irb *);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "tape"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bio.h>
|
||||
|
|
@ -18,8 +20,6 @@
|
|||
#include "tape.h"
|
||||
#include "tape_std.h"
|
||||
|
||||
#define PRINTK_HEADER "TAPE_34XX: "
|
||||
|
||||
/*
|
||||
* Pointer to debug area.
|
||||
*/
|
||||
|
|
@ -203,8 +203,7 @@ tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb)
|
|||
tape_34xx_schedule_work(device, TO_MSEN);
|
||||
} else {
|
||||
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
|
||||
PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
|
||||
tape_dump_sense(device, NULL, irb);
|
||||
tape_dump_sense_dbf(device, NULL, irb);
|
||||
}
|
||||
return TAPE_IO_SUCCESS;
|
||||
}
|
||||
|
|
@ -226,9 +225,7 @@ tape_34xx_erp_read_opposite(struct tape_device *device,
|
|||
tape_std_read_backward(device, request);
|
||||
return tape_34xx_erp_retry(request);
|
||||
}
|
||||
if (request->op != TO_RBA)
|
||||
PRINT_ERR("read_opposite called with state:%s\n",
|
||||
tape_op_verbose[request->op]);
|
||||
|
||||
/*
|
||||
* We tried to read forward and backward, but hat no
|
||||
* success -> failed.
|
||||
|
|
@ -241,13 +238,9 @@ tape_34xx_erp_bug(struct tape_device *device, struct tape_request *request,
|
|||
struct irb *irb, int no)
|
||||
{
|
||||
if (request->op != TO_ASSIGN) {
|
||||
PRINT_WARN("An unexpected condition #%d was caught in "
|
||||
"tape error recovery.\n", no);
|
||||
PRINT_WARN("Please report this incident.\n");
|
||||
if (request)
|
||||
PRINT_WARN("Operation of tape:%s\n",
|
||||
tape_op_verbose[request->op]);
|
||||
tape_dump_sense(device, request, irb);
|
||||
dev_err(&device->cdev->dev, "An unexpected condition %d "
|
||||
"occurred in tape error recovery\n", no);
|
||||
tape_dump_sense_dbf(device, request, irb);
|
||||
}
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
}
|
||||
|
|
@ -261,9 +254,8 @@ tape_34xx_erp_overrun(struct tape_device *device, struct tape_request *request,
|
|||
struct irb *irb)
|
||||
{
|
||||
if (irb->ecw[3] == 0x40) {
|
||||
PRINT_WARN ("Data overrun error between control-unit "
|
||||
"and drive. Use a faster channel connection, "
|
||||
"if possible! \n");
|
||||
dev_warn (&device->cdev->dev, "A data overrun occurred between"
|
||||
" the control unit and tape unit\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
}
|
||||
return tape_34xx_erp_bug(device, request, irb, -1);
|
||||
|
|
@ -280,7 +272,8 @@ tape_34xx_erp_sequence(struct tape_device *device,
|
|||
/*
|
||||
* cu detected incorrect block-id sequence on tape.
|
||||
*/
|
||||
PRINT_WARN("Illegal block-id sequence found!\n");
|
||||
dev_warn (&device->cdev->dev, "The block ID sequence on the "
|
||||
"tape is incorrect\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
}
|
||||
/*
|
||||
|
|
@ -393,8 +386,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
/* Writing at physical end of volume */
|
||||
return tape_34xx_erp_failed(request, -ENOSPC);
|
||||
default:
|
||||
PRINT_ERR("Invalid op in %s:%i\n",
|
||||
__func__, __LINE__);
|
||||
return tape_34xx_erp_failed(request, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -420,7 +411,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
irb, -4);
|
||||
|
||||
/* data check is permanent, CU recovery has failed */
|
||||
PRINT_WARN("Permanent read error\n");
|
||||
dev_warn (&device->cdev->dev, "A read error occurred "
|
||||
"that cannot be recovered\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x25:
|
||||
// a write data check occurred
|
||||
|
|
@ -433,22 +425,26 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
irb, -5);
|
||||
|
||||
// data check is permanent, cu-recovery has failed
|
||||
PRINT_WARN("Permanent write error\n");
|
||||
dev_warn (&device->cdev->dev, "A write error on the "
|
||||
"tape cannot be recovered\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x26:
|
||||
/* Data Check (read opposite) occurred. */
|
||||
return tape_34xx_erp_read_opposite(device, request);
|
||||
case 0x28:
|
||||
/* ID-Mark at tape start couldn't be written */
|
||||
PRINT_WARN("ID-Mark could not be written.\n");
|
||||
dev_warn (&device->cdev->dev, "Writing the ID-mark "
|
||||
"failed\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x31:
|
||||
/* Tape void. Tried to read beyond end of device. */
|
||||
PRINT_WARN("Read beyond end of recorded area.\n");
|
||||
dev_warn (&device->cdev->dev, "Reading the tape beyond"
|
||||
" the end of the recorded area failed\n");
|
||||
return tape_34xx_erp_failed(request, -ENOSPC);
|
||||
case 0x41:
|
||||
/* Record sequence error. */
|
||||
PRINT_WARN("Invalid block-id sequence found.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape contains an "
|
||||
"incorrect block ID sequence\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
default:
|
||||
/* all data checks for 3480 should result in one of
|
||||
|
|
@ -470,16 +466,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
switch (sense[3]) {
|
||||
case 0x00:
|
||||
/* Unit check with erpa code 0. Report and ignore. */
|
||||
PRINT_WARN("Non-error sense was found. "
|
||||
"Unit-check will be ignored.\n");
|
||||
return TAPE_IO_SUCCESS;
|
||||
case 0x21:
|
||||
/*
|
||||
* Data streaming not operational. CU will switch to
|
||||
* interlock mode. Reissue the command.
|
||||
*/
|
||||
PRINT_WARN("Data streaming not operational. "
|
||||
"Switching to interlock-mode.\n");
|
||||
return tape_34xx_erp_retry(request);
|
||||
case 0x22:
|
||||
/*
|
||||
|
|
@ -487,11 +479,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* error on the lower interface, internal path not usable,
|
||||
* or error during cartridge load.
|
||||
*/
|
||||
PRINT_WARN("A path equipment check occurred. One of the "
|
||||
"following conditions occurred:\n");
|
||||
PRINT_WARN("drive adapter error, buffer error on the lower "
|
||||
"interface, internal path not usable, error "
|
||||
"during cartridge load.\n");
|
||||
dev_warn (&device->cdev->dev, "A path equipment check occurred"
|
||||
" for the tape device\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x24:
|
||||
/*
|
||||
|
|
@ -514,7 +503,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* but the hardware isn't capable to do idrc, or a perform
|
||||
* subsystem func is issued and the CU is not on-line.
|
||||
*/
|
||||
PRINT_WARN ("Function incompatible. Try to switch off idrc\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x2a:
|
||||
/*
|
||||
|
|
@ -552,23 +540,26 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* reading the format id mark or that that format specified
|
||||
* is not supported by the drive.
|
||||
*/
|
||||
PRINT_WARN("Drive not capable processing the tape format!\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit cannot process "
|
||||
"the tape format\n");
|
||||
return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
|
||||
case 0x30:
|
||||
/* The medium is write protected. */
|
||||
PRINT_WARN("Medium is write protected!\n");
|
||||
dev_warn (&device->cdev->dev, "The tape medium is write-"
|
||||
"protected\n");
|
||||
return tape_34xx_erp_failed(request, -EACCES);
|
||||
case 0x32:
|
||||
// Tension loss. We cannot recover this, it's an I/O error.
|
||||
PRINT_WARN("The drive lost tape tension.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape does not have the "
|
||||
"required tape tension\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x33:
|
||||
/*
|
||||
* Load Failure. The cartridge was not inserted correctly or
|
||||
* the tape is not threaded correctly.
|
||||
*/
|
||||
PRINT_WARN("Cartridge load failure. Reload the cartridge "
|
||||
"and try again.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit failed to load"
|
||||
" the cartridge\n");
|
||||
tape_34xx_delete_sbid_from(device, 0);
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x34:
|
||||
|
|
@ -576,8 +567,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* Unload failure. The drive cannot maintain tape tension
|
||||
* and control tape movement during an unload operation.
|
||||
*/
|
||||
PRINT_WARN("Failure during cartridge unload. "
|
||||
"Please try manually.\n");
|
||||
dev_warn (&device->cdev->dev, "Automatic unloading of the tape"
|
||||
" cartridge failed\n");
|
||||
if (request->op == TO_RUN)
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
return tape_34xx_erp_bug(device, request, irb, sense[3]);
|
||||
|
|
@ -589,8 +580,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* - the cartridge loader does not respond correctly
|
||||
* - a failure occurs during an index, load, or unload cycle
|
||||
*/
|
||||
PRINT_WARN("Equipment check! Please check the drive and "
|
||||
"the cartridge loader.\n");
|
||||
dev_warn (&device->cdev->dev, "An equipment check has occurred"
|
||||
" on the tape unit\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x36:
|
||||
if (device->cdev->id.driver_info == tape_3490)
|
||||
|
|
@ -603,7 +594,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* Tape length error. The tape is shorter than reported in
|
||||
* the beginning-of-tape data.
|
||||
*/
|
||||
PRINT_WARN("Tape length error.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape information states an"
|
||||
" incorrect length\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x38:
|
||||
/*
|
||||
|
|
@ -620,12 +612,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x3a:
|
||||
/* Drive switched to not ready. */
|
||||
PRINT_WARN("Drive not ready. Turn the ready/not ready switch "
|
||||
"to ready position and try again.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit is not ready\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x3b:
|
||||
/* Manual rewind or unload. This causes an I/O error. */
|
||||
PRINT_WARN("Medium was rewound or unloaded manually.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape medium has been "
|
||||
"rewound or unloaded manually\n");
|
||||
tape_34xx_delete_sbid_from(device, 0);
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x42:
|
||||
|
|
@ -633,7 +625,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* Degraded mode. A condition that can cause degraded
|
||||
* performance is detected.
|
||||
*/
|
||||
PRINT_WARN("Subsystem is running in degraded mode.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape subsystem is running "
|
||||
"in degraded mode\n");
|
||||
return tape_34xx_erp_retry(request);
|
||||
case 0x43:
|
||||
/* Drive not ready. */
|
||||
|
|
@ -652,7 +645,6 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
break;
|
||||
}
|
||||
}
|
||||
PRINT_WARN("The drive is not ready.\n");
|
||||
return tape_34xx_erp_failed(request, -ENOMEDIUM);
|
||||
case 0x44:
|
||||
/* Locate Block unsuccessful. */
|
||||
|
|
@ -663,7 +655,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x45:
|
||||
/* The drive is assigned to a different channel path. */
|
||||
PRINT_WARN("The drive is assigned elsewhere.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit is already "
|
||||
"assigned\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x46:
|
||||
/*
|
||||
|
|
@ -671,11 +664,12 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* the power supply may be switched off or
|
||||
* the drive address may not be set correctly.
|
||||
*/
|
||||
PRINT_WARN("The drive is not on-line.");
|
||||
dev_warn (&device->cdev->dev, "The tape unit is not online\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x47:
|
||||
/* Volume fenced. CU reports volume integrity is lost. */
|
||||
PRINT_WARN("Volume fenced. The volume integrity is lost.\n");
|
||||
dev_warn (&device->cdev->dev, "The control unit has fenced "
|
||||
"access to the tape volume\n");
|
||||
tape_34xx_delete_sbid_from(device, 0);
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x48:
|
||||
|
|
@ -683,20 +677,21 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
return tape_34xx_erp_retry(request);
|
||||
case 0x49:
|
||||
/* Bus out check. A parity check error on the bus was found. */
|
||||
PRINT_WARN("Bus out check. A data transfer over the bus "
|
||||
"has been corrupted.\n");
|
||||
dev_warn (&device->cdev->dev, "A parity error occurred on the "
|
||||
"tape bus\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x4a:
|
||||
/* Control unit erp failed. */
|
||||
PRINT_WARN("The control unit I/O error recovery failed.\n");
|
||||
dev_warn (&device->cdev->dev, "I/O error recovery failed on "
|
||||
"the tape control unit\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x4b:
|
||||
/*
|
||||
* CU and drive incompatible. The drive requests micro-program
|
||||
* patches, which are not available on the CU.
|
||||
*/
|
||||
PRINT_WARN("The drive needs microprogram patches from the "
|
||||
"control unit, which are not available.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit requires a "
|
||||
"firmware update\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x4c:
|
||||
/*
|
||||
|
|
@ -721,8 +716,8 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* the block to be written is larger than allowed for
|
||||
* buffered mode.
|
||||
*/
|
||||
PRINT_WARN("Maximum block size for buffered "
|
||||
"mode exceeded.\n");
|
||||
dev_warn (&device->cdev->dev, "The maximum block size"
|
||||
" for buffered mode is exceeded\n");
|
||||
return tape_34xx_erp_failed(request, -ENOBUFS);
|
||||
}
|
||||
/* This erpa is reserved for 3480. */
|
||||
|
|
@ -759,22 +754,20 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
return tape_34xx_erp_retry(request);
|
||||
case 0x55:
|
||||
/* Channel interface recovery (permanent). */
|
||||
PRINT_WARN("A permanent channel interface error occurred.\n");
|
||||
dev_warn (&device->cdev->dev, "A channel interface error cannot be"
|
||||
" recovered\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x56:
|
||||
/* Channel protocol error. */
|
||||
PRINT_WARN("A channel protocol error occurred.\n");
|
||||
dev_warn (&device->cdev->dev, "A channel protocol error "
|
||||
"occurred\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x57:
|
||||
if (device->cdev->id.driver_info == tape_3480) {
|
||||
/* Attention intercept. */
|
||||
PRINT_WARN("An attention intercept occurred, "
|
||||
"which will be recovered.\n");
|
||||
return tape_34xx_erp_retry(request);
|
||||
} else {
|
||||
/* Global status intercept. */
|
||||
PRINT_WARN("An global status intercept was received, "
|
||||
"which will be recovered.\n");
|
||||
return tape_34xx_erp_retry(request);
|
||||
}
|
||||
case 0x5a:
|
||||
|
|
@ -782,42 +775,31 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* Tape length incompatible. The tape inserted is too long,
|
||||
* which could cause damage to the tape or the drive.
|
||||
*/
|
||||
PRINT_WARN("Tape Length Incompatible\n");
|
||||
PRINT_WARN("Tape length exceeds IBM enhanced capacity "
|
||||
"cartdridge length or a medium\n");
|
||||
PRINT_WARN("with EC-CST identification mark has been mounted "
|
||||
"in a device that writes\n");
|
||||
PRINT_WARN("3480 or 3480 XF format.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit does not support "
|
||||
"the tape length\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x5b:
|
||||
/* Format 3480 XF incompatible */
|
||||
if (sense[1] & SENSE_BEGINNING_OF_TAPE)
|
||||
/* The tape will get overwritten. */
|
||||
return tape_34xx_erp_retry(request);
|
||||
PRINT_WARN("Format 3480 XF Incompatible\n");
|
||||
PRINT_WARN("Medium has been created in 3480 format. "
|
||||
"To change the format writes\n");
|
||||
PRINT_WARN("must be issued at BOT.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit does not support"
|
||||
" format 3480 XF\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x5c:
|
||||
/* Format 3480-2 XF incompatible */
|
||||
PRINT_WARN("Format 3480-2 XF Incompatible\n");
|
||||
PRINT_WARN("Device can only read 3480 or 3480 XF format.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit does not support tape "
|
||||
"format 3480-2 XF\n");
|
||||
return tape_34xx_erp_failed(request, -EIO);
|
||||
case 0x5d:
|
||||
/* Tape length violation. */
|
||||
PRINT_WARN("Tape Length Violation\n");
|
||||
PRINT_WARN("The mounted tape exceeds IBM Enhanced Capacity "
|
||||
"Cartdridge System Tape length.\n");
|
||||
PRINT_WARN("This may cause damage to the drive or tape when "
|
||||
"processing to the EOV\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit does not support"
|
||||
" the current tape length\n");
|
||||
return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
|
||||
case 0x5e:
|
||||
/* Compaction algorithm incompatible. */
|
||||
PRINT_WARN("Compaction Algorithm Incompatible\n");
|
||||
PRINT_WARN("The volume is recorded using an incompatible "
|
||||
"compaction algorithm,\n");
|
||||
PRINT_WARN("which is not supported by the device.\n");
|
||||
dev_warn (&device->cdev->dev, "The tape unit does not support"
|
||||
" the compaction algorithm\n");
|
||||
return tape_34xx_erp_failed(request, -EMEDIUMTYPE);
|
||||
|
||||
/* The following erpas should have been covered earlier. */
|
||||
|
|
@ -848,7 +830,6 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request,
|
|||
(irb->scsw.cmd.dstat & DEV_STAT_DEV_END) &&
|
||||
(request->op == TO_WRI)) {
|
||||
/* Write at end of volume */
|
||||
PRINT_INFO("End of volume\n"); /* XXX */
|
||||
return tape_34xx_erp_failed(request, -ENOSPC);
|
||||
}
|
||||
|
||||
|
|
@ -869,9 +850,7 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request,
|
|||
}
|
||||
|
||||
DBF_EVENT(6, "xunknownirq\n");
|
||||
PRINT_ERR("Unexpected interrupt.\n");
|
||||
PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]);
|
||||
tape_dump_sense(device, request, irb);
|
||||
tape_dump_sense_dbf(device, request, irb);
|
||||
return TAPE_IO_STOP;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,15 @@
|
|||
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "tape"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bio.h>
|
||||
#include <asm/ebcdic.h>
|
||||
|
||||
#define TAPE_DBF_AREA tape_3590_dbf
|
||||
#define BUFSIZE 512 /* size of buffers for dynamic generated messages */
|
||||
|
||||
#include "tape.h"
|
||||
#include "tape_std.h"
|
||||
|
|
@ -36,7 +39,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);
|
|||
* - Read Alternate: implemented
|
||||
*******************************************************************/
|
||||
|
||||
#define PRINTK_HEADER "TAPE_3590: "
|
||||
#define KMSG_COMPONENT "tape"
|
||||
|
||||
static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {
|
||||
[0x00] = "",
|
||||
|
|
@ -661,8 +664,7 @@ tape_3590_bread(struct tape_device *device, struct request *req)
|
|||
ccw++;
|
||||
dst += TAPEBLOCK_HSEC_SIZE;
|
||||
}
|
||||
if (off > bv->bv_len)
|
||||
BUG();
|
||||
BUG_ON(off > bv->bv_len);
|
||||
}
|
||||
ccw = tape_ccw_end(ccw, NOP, 0, NULL);
|
||||
DBF_EVENT(6, "xBREDccwg\n");
|
||||
|
|
@ -726,7 +728,7 @@ static void tape_3590_med_state_set(struct tape_device *device,
|
|||
}
|
||||
c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
|
||||
if (sense->flags & MSENSE_CRYPT_MASK) {
|
||||
PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
|
||||
DBF_EVENT(6, "Medium is encrypted (%04x)\n", sense->flags);
|
||||
c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
|
||||
} else {
|
||||
DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
|
||||
|
|
@ -847,8 +849,7 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
|
|||
tape_3590_schedule_work(device, TO_READ_ATTMSG);
|
||||
} else {
|
||||
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
|
||||
PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
|
||||
tape_dump_sense(device, NULL, irb);
|
||||
tape_dump_sense_dbf(device, NULL, irb);
|
||||
}
|
||||
/* check medium state */
|
||||
tape_3590_schedule_work(device, TO_MSEN);
|
||||
|
|
@ -876,8 +877,6 @@ tape_3590_erp_basic(struct tape_device *device, struct tape_request *request,
|
|||
case SENSE_BRA_DRE:
|
||||
return tape_3590_erp_failed(device, request, irb, rc);
|
||||
default:
|
||||
PRINT_ERR("Unknown BRA %x - This should not happen!\n",
|
||||
sense->bra);
|
||||
BUG();
|
||||
return TAPE_IO_STOP;
|
||||
}
|
||||
|
|
@ -910,7 +909,8 @@ tape_3590_erp_swap(struct tape_device *device, struct tape_request *request,
|
|||
* should proceed with the new tape... this
|
||||
* should probably be done in user space!
|
||||
*/
|
||||
PRINT_WARN("(%s): Swap Tape Device!\n", dev_name(&device->cdev->dev));
|
||||
dev_warn (&device->cdev->dev, "The tape medium must be loaded into a "
|
||||
"different tape unit\n");
|
||||
return tape_3590_erp_basic(device, request, irb, -EIO);
|
||||
}
|
||||
|
||||
|
|
@ -985,8 +985,6 @@ tape_3590_erp_read_opposite(struct tape_device *device,
|
|||
return tape_3590_erp_failed(device, request, irb, -EIO);
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("read_opposite_recovery_called_with_op: %s\n",
|
||||
tape_op_verbose[request->op]);
|
||||
return tape_3590_erp_failed(device, request, irb, -EIO);
|
||||
}
|
||||
}
|
||||
|
|
@ -998,50 +996,61 @@ static void
|
|||
tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
|
||||
{
|
||||
struct tape_3590_sense *sense;
|
||||
char *exception, *service;
|
||||
|
||||
exception = kmalloc(BUFSIZE, GFP_ATOMIC);
|
||||
service = kmalloc(BUFSIZE, GFP_ATOMIC);
|
||||
|
||||
if (!exception || !service)
|
||||
goto out_nomem;
|
||||
|
||||
sense = (struct tape_3590_sense *) irb->ecw;
|
||||
/* Exception Message */
|
||||
switch (sense->fmt.f70.emc) {
|
||||
case 0x02:
|
||||
PRINT_WARN("(%s): Data degraded\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "Data degraded");
|
||||
break;
|
||||
case 0x03:
|
||||
PRINT_WARN("(%s): Data degraded in partion %i\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f70.mp);
|
||||
snprintf(exception, BUFSIZE, "Data degraded in partion %i",
|
||||
sense->fmt.f70.mp);
|
||||
break;
|
||||
case 0x04:
|
||||
PRINT_WARN("(%s): Medium degraded\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "Medium degraded");
|
||||
break;
|
||||
case 0x05:
|
||||
PRINT_WARN("(%s): Medium degraded in partition %i\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f70.mp);
|
||||
snprintf(exception, BUFSIZE, "Medium degraded in partition %i",
|
||||
sense->fmt.f70.mp);
|
||||
break;
|
||||
case 0x06:
|
||||
PRINT_WARN("(%s): Block 0 Error\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "Block 0 Error");
|
||||
break;
|
||||
case 0x07:
|
||||
PRINT_WARN("(%s): Medium Exception 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f70.md);
|
||||
snprintf(exception, BUFSIZE, "Medium Exception 0x%02x",
|
||||
sense->fmt.f70.md);
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("(%s): MIM ExMsg: 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f70.emc);
|
||||
snprintf(exception, BUFSIZE, "0x%02x",
|
||||
sense->fmt.f70.emc);
|
||||
break;
|
||||
}
|
||||
/* Service Message */
|
||||
switch (sense->fmt.f70.smc) {
|
||||
case 0x02:
|
||||
PRINT_WARN("(%s): Reference Media maintenance procedure %i\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f70.md);
|
||||
snprintf(service, BUFSIZE, "Reference Media maintenance "
|
||||
"procedure %i", sense->fmt.f70.md);
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("(%s): MIM ServiceMsg: 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f70.smc);
|
||||
snprintf(service, BUFSIZE, "0x%02x",
|
||||
sense->fmt.f70.smc);
|
||||
break;
|
||||
}
|
||||
|
||||
dev_warn (&device->cdev->dev, "Tape media information: exception %s, "
|
||||
"service %s\n", exception, service);
|
||||
|
||||
out_nomem:
|
||||
kfree(exception);
|
||||
kfree(service);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1051,108 +1060,108 @@ static void
|
|||
tape_3590_print_io_sim_msg_f1(struct tape_device *device, struct irb *irb)
|
||||
{
|
||||
struct tape_3590_sense *sense;
|
||||
char *exception, *service;
|
||||
|
||||
exception = kmalloc(BUFSIZE, GFP_ATOMIC);
|
||||
service = kmalloc(BUFSIZE, GFP_ATOMIC);
|
||||
|
||||
if (!exception || !service)
|
||||
goto out_nomem;
|
||||
|
||||
sense = (struct tape_3590_sense *) irb->ecw;
|
||||
/* Exception Message */
|
||||
switch (sense->fmt.f71.emc) {
|
||||
case 0x01:
|
||||
PRINT_WARN("(%s): Effect of failure is unknown\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "Effect of failure is unknown");
|
||||
break;
|
||||
case 0x02:
|
||||
PRINT_WARN("(%s): CU Exception - no performance impact\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "CU Exception - no performance "
|
||||
"impact");
|
||||
break;
|
||||
case 0x03:
|
||||
PRINT_WARN("(%s): CU Exception on channel interface 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "CU Exception on channel "
|
||||
"interface 0x%02x", sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x04:
|
||||
PRINT_WARN("(%s): CU Exception on device path 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "CU Exception on device path "
|
||||
"0x%02x", sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x05:
|
||||
PRINT_WARN("(%s): CU Exception on library path 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "CU Exception on library path "
|
||||
"0x%02x", sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x06:
|
||||
PRINT_WARN("(%s): CU Exception on node 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "CU Exception on node 0x%02x",
|
||||
sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x07:
|
||||
PRINT_WARN("(%s): CU Exception on partition 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "CU Exception on partition "
|
||||
"0x%02x", sense->fmt.f71.md[0]);
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("(%s): SIM ExMsg: 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.emc);
|
||||
snprintf(exception, BUFSIZE, "0x%02x",
|
||||
sense->fmt.f71.emc);
|
||||
}
|
||||
/* Service Message */
|
||||
switch (sense->fmt.f71.smc) {
|
||||
case 0x01:
|
||||
PRINT_WARN("(%s): Repair impact is unknown\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Repair impact is unknown");
|
||||
break;
|
||||
case 0x02:
|
||||
PRINT_WARN("(%s): Repair will not impact cu performance\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Repair will not impact cu "
|
||||
"performance");
|
||||
break;
|
||||
case 0x03:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable node "
|
||||
"0x%x on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable node "
|
||||
"0x%x on CU", sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable nodes "
|
||||
"(0x%x-0x%x) on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"nodes (0x%x-0x%x) on CU", sense->fmt.f71.md[1],
|
||||
sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x04:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable cannel path "
|
||||
"0x%x on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"channel path 0x%x on CU",
|
||||
sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable cannel paths "
|
||||
"(0x%x-0x%x) on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable cannel"
|
||||
" paths (0x%x-0x%x) on CU",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x05:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable device path "
|
||||
"0x%x on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable device"
|
||||
" path 0x%x on CU", sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable device paths "
|
||||
"(0x%x-0x%x) on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable device"
|
||||
" paths (0x%x-0x%x) on CU",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x06:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable library path "
|
||||
"0x%x on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"library path 0x%x on CU",
|
||||
sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable library paths "
|
||||
"(0x%x-0x%x) on CU\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"library paths (0x%x-0x%x) on CU",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x07:
|
||||
PRINT_WARN("(%s): Repair will disable access to CU\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Repair will disable access to CU");
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("(%s): SIM ServiceMsg: 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.smc);
|
||||
snprintf(service, BUFSIZE, "0x%02x",
|
||||
sense->fmt.f71.smc);
|
||||
}
|
||||
|
||||
dev_warn (&device->cdev->dev, "I/O subsystem information: exception"
|
||||
" %s, service %s\n", exception, service);
|
||||
out_nomem:
|
||||
kfree(exception);
|
||||
kfree(service);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1162,111 +1171,109 @@ static void
|
|||
tape_3590_print_dev_sim_msg_f2(struct tape_device *device, struct irb *irb)
|
||||
{
|
||||
struct tape_3590_sense *sense;
|
||||
char *exception, *service;
|
||||
|
||||
exception = kmalloc(BUFSIZE, GFP_ATOMIC);
|
||||
service = kmalloc(BUFSIZE, GFP_ATOMIC);
|
||||
|
||||
if (!exception || !service)
|
||||
goto out_nomem;
|
||||
|
||||
sense = (struct tape_3590_sense *) irb->ecw;
|
||||
/* Exception Message */
|
||||
switch (sense->fmt.f71.emc) {
|
||||
case 0x01:
|
||||
PRINT_WARN("(%s): Effect of failure is unknown\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "Effect of failure is unknown");
|
||||
break;
|
||||
case 0x02:
|
||||
PRINT_WARN("(%s): DV Exception - no performance impact\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "DV Exception - no performance"
|
||||
" impact");
|
||||
break;
|
||||
case 0x03:
|
||||
PRINT_WARN("(%s): DV Exception on channel interface 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "DV Exception on channel "
|
||||
"interface 0x%02x", sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x04:
|
||||
PRINT_WARN("(%s): DV Exception on loader 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "DV Exception on loader 0x%02x",
|
||||
sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x05:
|
||||
PRINT_WARN("(%s): DV Exception on message display 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.md[0]);
|
||||
snprintf(exception, BUFSIZE, "DV Exception on message display"
|
||||
" 0x%02x", sense->fmt.f71.md[0]);
|
||||
break;
|
||||
case 0x06:
|
||||
PRINT_WARN("(%s): DV Exception in tape path\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "DV Exception in tape path");
|
||||
break;
|
||||
case 0x07:
|
||||
PRINT_WARN("(%s): DV Exception in drive\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(exception, BUFSIZE, "DV Exception in drive");
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("(%s): DSIM ExMsg: 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.emc);
|
||||
snprintf(exception, BUFSIZE, "0x%02x",
|
||||
sense->fmt.f71.emc);
|
||||
}
|
||||
/* Service Message */
|
||||
switch (sense->fmt.f71.smc) {
|
||||
case 0x01:
|
||||
PRINT_WARN("(%s): Repair impact is unknown\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Repair impact is unknown");
|
||||
break;
|
||||
case 0x02:
|
||||
PRINT_WARN("(%s): Repair will not impact device performance\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Repair will not impact device "
|
||||
"performance");
|
||||
break;
|
||||
case 0x03:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable channel path "
|
||||
"0x%x on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"channel path 0x%x on DV",
|
||||
sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable channel path "
|
||||
"(0x%x-0x%x) on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"channel path (0x%x-0x%x) on DV",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x04:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable interface 0x%x "
|
||||
"on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"interface 0x%x on DV", sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable interfaces "
|
||||
"(0x%x-0x%x) on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"interfaces (0x%x-0x%x) on DV",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x05:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable loader 0x%x "
|
||||
"on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable loader"
|
||||
" 0x%x on DV", sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable loader "
|
||||
"(0x%x-0x%x) on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable loader"
|
||||
" (0x%x-0x%x) on DV",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x07:
|
||||
PRINT_WARN("(%s): Repair will disable access to DV\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Repair will disable access to DV");
|
||||
break;
|
||||
case 0x08:
|
||||
if (sense->fmt.f71.mdf == 0)
|
||||
PRINT_WARN("(%s): Repair will disable message "
|
||||
"display 0x%x on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"message display 0x%x on DV",
|
||||
sense->fmt.f71.md[1]);
|
||||
else
|
||||
PRINT_WARN("(%s): Repair will disable message "
|
||||
"displays (0x%x-0x%x) on DV\n",
|
||||
dev_name(&device->cdev->dev),
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
snprintf(service, BUFSIZE, "Repair will disable "
|
||||
"message displays (0x%x-0x%x) on DV",
|
||||
sense->fmt.f71.md[1], sense->fmt.f71.md[2]);
|
||||
break;
|
||||
case 0x09:
|
||||
PRINT_WARN("(%s): Clean DV\n", dev_name(&device->cdev->dev));
|
||||
snprintf(service, BUFSIZE, "Clean DV");
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("(%s): DSIM ServiceMsg: 0x%02x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.smc);
|
||||
snprintf(service, BUFSIZE, "0x%02x",
|
||||
sense->fmt.f71.smc);
|
||||
}
|
||||
|
||||
dev_warn (&device->cdev->dev, "Device subsystem information: exception"
|
||||
" %s, service %s\n", exception, service);
|
||||
out_nomem:
|
||||
kfree(exception);
|
||||
kfree(service);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1282,46 +1289,44 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
|
|||
return;
|
||||
if ((sense->mc > 0) && (sense->mc < TAPE_3590_MAX_MSG)) {
|
||||
if (tape_3590_msg[sense->mc] != NULL)
|
||||
PRINT_WARN("(%s): %s\n", dev_name(&device->cdev->dev),
|
||||
tape_3590_msg[sense->mc]);
|
||||
else {
|
||||
PRINT_WARN("(%s): Message Code 0x%x\n",
|
||||
dev_name(&device->cdev->dev), sense->mc);
|
||||
}
|
||||
dev_warn (&device->cdev->dev, "The tape unit has "
|
||||
"issued sense message %s\n",
|
||||
tape_3590_msg[sense->mc]);
|
||||
else
|
||||
dev_warn (&device->cdev->dev, "The tape unit has "
|
||||
"issued an unknown sense message code 0x%x\n",
|
||||
sense->mc);
|
||||
return;
|
||||
}
|
||||
if (sense->mc == 0xf0) {
|
||||
/* Standard Media Information Message */
|
||||
PRINT_WARN("(%s): MIM SEV=%i, MC=%02x, ES=%x/%x, "
|
||||
"RC=%02x-%04x-%02x\n", dev_name(&device->cdev->dev),
|
||||
sense->fmt.f70.sev, sense->mc,
|
||||
sense->fmt.f70.emc, sense->fmt.f70.smc,
|
||||
sense->fmt.f70.refcode, sense->fmt.f70.mid,
|
||||
sense->fmt.f70.fid);
|
||||
dev_warn (&device->cdev->dev, "MIM SEV=%i, MC=%02x, ES=%x/%x, "
|
||||
"RC=%02x-%04x-%02x\n", sense->fmt.f70.sev, sense->mc,
|
||||
sense->fmt.f70.emc, sense->fmt.f70.smc,
|
||||
sense->fmt.f70.refcode, sense->fmt.f70.mid,
|
||||
sense->fmt.f70.fid);
|
||||
tape_3590_print_mim_msg_f0(device, irb);
|
||||
return;
|
||||
}
|
||||
if (sense->mc == 0xf1) {
|
||||
/* Standard I/O Subsystem Service Information Message */
|
||||
PRINT_WARN("(%s): IOSIM SEV=%i, DEVTYPE=3590/%02x, "
|
||||
"MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.sev,
|
||||
device->cdev->id.dev_model,
|
||||
sense->mc, sense->fmt.f71.emc,
|
||||
sense->fmt.f71.smc, sense->fmt.f71.refcode1,
|
||||
sense->fmt.f71.refcode2, sense->fmt.f71.refcode3);
|
||||
dev_warn (&device->cdev->dev, "IOSIM SEV=%i, DEVTYPE=3590/%02x,"
|
||||
" MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
|
||||
sense->fmt.f71.sev, device->cdev->id.dev_model,
|
||||
sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc,
|
||||
sense->fmt.f71.refcode1, sense->fmt.f71.refcode2,
|
||||
sense->fmt.f71.refcode3);
|
||||
tape_3590_print_io_sim_msg_f1(device, irb);
|
||||
return;
|
||||
}
|
||||
if (sense->mc == 0xf2) {
|
||||
/* Standard Device Service Information Message */
|
||||
PRINT_WARN("(%s): DEVSIM SEV=%i, DEVTYPE=3590/%02x, "
|
||||
"MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
|
||||
dev_name(&device->cdev->dev), sense->fmt.f71.sev,
|
||||
device->cdev->id.dev_model,
|
||||
sense->mc, sense->fmt.f71.emc,
|
||||
sense->fmt.f71.smc, sense->fmt.f71.refcode1,
|
||||
sense->fmt.f71.refcode2, sense->fmt.f71.refcode3);
|
||||
dev_warn (&device->cdev->dev, "DEVSIM SEV=%i, DEVTYPE=3590/%02x"
|
||||
", MC=%02x, ES=%x/%x, REF=0x%04x-0x%04x-0x%04x\n",
|
||||
sense->fmt.f71.sev, device->cdev->id.dev_model,
|
||||
sense->mc, sense->fmt.f71.emc, sense->fmt.f71.smc,
|
||||
sense->fmt.f71.refcode1, sense->fmt.f71.refcode2,
|
||||
sense->fmt.f71.refcode3);
|
||||
tape_3590_print_dev_sim_msg_f2(device, irb);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1329,8 +1334,8 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
|
|||
/* Standard Library Service Information Message */
|
||||
return;
|
||||
}
|
||||
PRINT_WARN("(%s): Device Message(%x)\n",
|
||||
dev_name(&device->cdev->dev), sense->mc);
|
||||
dev_warn (&device->cdev->dev, "The tape unit has issued an unknown "
|
||||
"sense message code %x\n", sense->mc);
|
||||
}
|
||||
|
||||
static int tape_3590_crypt_error(struct tape_device *device,
|
||||
|
|
@ -1355,9 +1360,8 @@ static int tape_3590_crypt_error(struct tape_device *device,
|
|||
/* No connection to EKM */
|
||||
return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
|
||||
|
||||
PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id);
|
||||
PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc,
|
||||
drv_rc, ekm_rc1, ekm_rc2);
|
||||
dev_err (&device->cdev->dev, "The tape unit failed to obtain the "
|
||||
"encryption key from EKM\n");
|
||||
|
||||
return tape_3590_erp_basic(device, request, irb, -ENOKEY);
|
||||
}
|
||||
|
|
@ -1443,8 +1447,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
* print additional msg since default msg
|
||||
* "device intervention" is not very meaningfull
|
||||
*/
|
||||
PRINT_WARN("(%s): Tape operation when medium not loaded\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
tape_med_state_set(device, MS_UNLOADED);
|
||||
tape_3590_schedule_work(device, TO_CRYPT_OFF);
|
||||
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
|
||||
|
|
@ -1490,19 +1492,13 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
|
|||
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
|
||||
|
||||
case 0x6020:
|
||||
PRINT_WARN("(%s): Cartridge of wrong type ?\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
return tape_3590_erp_basic(device, request, irb, -EMEDIUMTYPE);
|
||||
|
||||
case 0x8011:
|
||||
PRINT_WARN("(%s): Another host has reserved the tape device\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
return tape_3590_erp_basic(device, request, irb, -EPERM);
|
||||
case 0x8013:
|
||||
PRINT_WARN("(%s): Another host has privileged access to the "
|
||||
"tape device\n", dev_name(&device->cdev->dev));
|
||||
PRINT_WARN("(%s): To solve the problem unload the current "
|
||||
"cartridge!\n", dev_name(&device->cdev->dev));
|
||||
dev_warn (&device->cdev->dev, "A different host has privileged"
|
||||
" access to the tape unit\n");
|
||||
return tape_3590_erp_basic(device, request, irb, -EPERM);
|
||||
default:
|
||||
return tape_3590_erp_basic(device, request, irb, -EIO);
|
||||
|
|
@ -1552,9 +1548,7 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request,
|
|||
}
|
||||
|
||||
DBF_EVENT(6, "xunknownirq\n");
|
||||
PRINT_ERR("Unexpected interrupt.\n");
|
||||
PRINT_ERR("Current op is: %s", tape_op_verbose[request->op]);
|
||||
tape_dump_sense(device, request, irb);
|
||||
tape_dump_sense_dbf(device, request, irb);
|
||||
return TAPE_IO_STOP;
|
||||
}
|
||||
|
||||
|
|
@ -1609,7 +1603,6 @@ tape_3590_setup_device(struct tape_device *device)
|
|||
if (rc)
|
||||
goto fail_rdc_data;
|
||||
if (rdc_data->data[31] == 0x13) {
|
||||
PRINT_INFO("Device has crypto support\n");
|
||||
data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
|
||||
tape_3592_disable_crypt(device);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
* Stefan Bader <shbader@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "tape"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/blkdev.h>
|
||||
|
|
@ -23,8 +25,6 @@
|
|||
|
||||
#include "tape.h"
|
||||
|
||||
#define PRINTK_HEADER "TAPE_BLOCK: "
|
||||
|
||||
#define TAPEBLOCK_MAX_SEC 100
|
||||
#define TAPEBLOCK_MIN_REQUEUE 3
|
||||
|
||||
|
|
@ -279,8 +279,6 @@ tapeblock_cleanup_device(struct tape_device *device)
|
|||
tape_put_device(device);
|
||||
|
||||
if (!device->blk_data.disk) {
|
||||
PRINT_ERR("(%s): No gendisk to clean up!\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
goto cleanup_queue;
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +312,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)
|
|||
if (!device->blk_data.medium_changed)
|
||||
return 0;
|
||||
|
||||
PRINT_INFO("Detecting media size...\n");
|
||||
dev_info(&device->cdev->dev, "Determining the size of the recorded "
|
||||
"area...\n");
|
||||
rc = tape_mtop(device, MTFSFM, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -341,7 +340,8 @@ tapeblock_revalidate_disk(struct gendisk *disk)
|
|||
device->bof = rc;
|
||||
nr_of_blks -= rc;
|
||||
|
||||
PRINT_INFO("Found %i blocks on media\n", nr_of_blks);
|
||||
dev_info(&device->cdev->dev, "The size of the recorded area is %i "
|
||||
"blocks\n", nr_of_blks);
|
||||
set_capacity(device->blk_data.disk,
|
||||
nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512));
|
||||
|
||||
|
|
@ -376,8 +376,8 @@ tapeblock_open(struct block_device *bdev, fmode_t mode)
|
|||
|
||||
if (device->required_tapemarks) {
|
||||
DBF_EVENT(2, "TBLOCK: missing tapemarks\n");
|
||||
PRINT_ERR("TBLOCK: Refusing to open tape with missing"
|
||||
" end of file marks.\n");
|
||||
dev_warn(&device->cdev->dev, "Opening the tape failed because"
|
||||
" of missing end-of-file marks\n");
|
||||
rc = -EPERM;
|
||||
goto put_device;
|
||||
}
|
||||
|
|
@ -452,7 +452,6 @@ tapeblock_ioctl(
|
|||
rc = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
PRINT_WARN("invalid ioctl 0x%x\n", command);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -474,7 +473,6 @@ tapeblock_init(void)
|
|||
|
||||
if (tapeblock_major == 0)
|
||||
tapeblock_major = rc;
|
||||
PRINT_INFO("tape gets major %d for block device\n", tapeblock_major);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@
|
|||
#include "tape_std.h"
|
||||
#include "tape_class.h"
|
||||
|
||||
#define PRINTK_HEADER "TAPE_CHAR: "
|
||||
|
||||
#define TAPECHAR_MAJOR 0 /* get dynamic major */
|
||||
|
||||
/*
|
||||
|
|
@ -102,8 +100,6 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
|
|||
if (block_size > MAX_BLOCKSIZE) {
|
||||
DBF_EVENT(3, "Invalid blocksize (%zd > %d)\n",
|
||||
block_size, MAX_BLOCKSIZE);
|
||||
PRINT_ERR("Invalid blocksize (%zd> %d)\n",
|
||||
block_size, MAX_BLOCKSIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -485,7 +481,6 @@ tapechar_init (void)
|
|||
return -1;
|
||||
|
||||
tapechar_major = MAJOR(dev);
|
||||
PRINT_INFO("tape gets major %d for character devices\n", MAJOR(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -496,7 +491,5 @@ tapechar_init (void)
|
|||
void
|
||||
tapechar_exit(void)
|
||||
{
|
||||
PRINT_INFO("tape releases major %d for character devices\n",
|
||||
tapechar_major);
|
||||
unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
* Stefan Bader <shbader@de.ibm.com>
|
||||
*/
|
||||
|
||||
#define KMSG_COMPONENT "tape"
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h> // for kernel parameters
|
||||
#include <linux/kmod.h> // for requesting modules
|
||||
|
|
@ -25,7 +26,6 @@
|
|||
#include "tape.h"
|
||||
#include "tape_std.h"
|
||||
|
||||
#define PRINTK_HEADER "TAPE_CORE: "
|
||||
#define LONG_BUSY_TIMEOUT 180 /* seconds */
|
||||
|
||||
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
|
||||
|
|
@ -214,13 +214,13 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
|
|||
switch(newstate){
|
||||
case MS_UNLOADED:
|
||||
device->tape_generic_status |= GMT_DR_OPEN(~0);
|
||||
PRINT_INFO("(%s): Tape is unloaded\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
dev_info(&device->cdev->dev, "The tape cartridge has been "
|
||||
"successfully unloaded\n");
|
||||
break;
|
||||
case MS_LOADED:
|
||||
device->tape_generic_status &= ~GMT_DR_OPEN(~0);
|
||||
PRINT_INFO("(%s): Tape has been mounted\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
dev_info(&device->cdev->dev, "A tape cartridge has been "
|
||||
"mounted\n");
|
||||
break;
|
||||
default:
|
||||
// print nothing
|
||||
|
|
@ -333,7 +333,6 @@ tape_generic_online(struct tape_device *device,
|
|||
/* Let the discipline have a go at the device. */
|
||||
device->discipline = discipline;
|
||||
if (!try_module_get(discipline->owner)) {
|
||||
PRINT_ERR("Cannot get module. Module gone.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -391,7 +390,6 @@ int
|
|||
tape_generic_offline(struct tape_device *device)
|
||||
{
|
||||
if (!device) {
|
||||
PRINT_ERR("tape_generic_offline: no such device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -413,9 +411,6 @@ tape_generic_offline(struct tape_device *device)
|
|||
DBF_EVENT(3, "(%08x): Set offline failed "
|
||||
"- drive in use.\n",
|
||||
device->cdev_id);
|
||||
PRINT_WARN("(%s): Set offline failed "
|
||||
"- drive in use.\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
spin_unlock_irq(get_ccwdev_lock(device->cdev));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
|
@ -435,14 +430,11 @@ tape_alloc_device(void)
|
|||
device = kzalloc(sizeof(struct tape_device), GFP_KERNEL);
|
||||
if (device == NULL) {
|
||||
DBF_EXCEPTION(2, "ti:no mem\n");
|
||||
PRINT_INFO ("can't allocate memory for "
|
||||
"tape info structure\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
device->modeset_byte = kmalloc(1, GFP_KERNEL | GFP_DMA);
|
||||
if (device->modeset_byte == NULL) {
|
||||
DBF_EXCEPTION(2, "ti:no mem\n");
|
||||
PRINT_INFO("can't allocate memory for modeset byte\n");
|
||||
kfree(device);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
|
@ -490,7 +482,6 @@ tape_put_device(struct tape_device *device)
|
|||
} else {
|
||||
if (remain < 0) {
|
||||
DBF_EVENT(4, "put device without reference\n");
|
||||
PRINT_ERR("put device without reference\n");
|
||||
} else {
|
||||
DBF_EVENT(4, "tape_free_device(%p)\n", device);
|
||||
kfree(device->modeset_byte);
|
||||
|
|
@ -538,8 +529,6 @@ tape_generic_probe(struct ccw_device *cdev)
|
|||
ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
|
||||
if (ret) {
|
||||
tape_put_device(device);
|
||||
PRINT_ERR("probe failed for tape device %s\n",
|
||||
dev_name(&cdev->dev));
|
||||
return ret;
|
||||
}
|
||||
cdev->dev.driver_data = device;
|
||||
|
|
@ -547,7 +536,6 @@ tape_generic_probe(struct ccw_device *cdev)
|
|||
device->cdev = cdev;
|
||||
ccw_device_get_id(cdev, &dev_id);
|
||||
device->cdev_id = devid_to_int(&dev_id);
|
||||
PRINT_INFO("tape device %s found\n", dev_name(&cdev->dev));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +572,6 @@ tape_generic_remove(struct ccw_device *cdev)
|
|||
|
||||
device = cdev->dev.driver_data;
|
||||
if (!device) {
|
||||
PRINT_ERR("No device pointer in tape_generic_remove!\n");
|
||||
return;
|
||||
}
|
||||
DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);
|
||||
|
|
@ -615,10 +602,8 @@ tape_generic_remove(struct ccw_device *cdev)
|
|||
*/
|
||||
DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
|
||||
device->cdev_id);
|
||||
PRINT_WARN("(%s): Drive in use vanished - "
|
||||
"expect trouble!\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
PRINT_WARN("State was %i\n", device->tape_state);
|
||||
dev_warn(&device->cdev->dev, "A tape unit was detached"
|
||||
" while in use\n");
|
||||
tape_state_set(device, TS_NOT_OPER);
|
||||
__tape_discard_requests(device);
|
||||
spin_unlock_irq(get_ccwdev_lock(device->cdev));
|
||||
|
|
@ -639,8 +624,7 @@ tape_alloc_request(int cplength, int datasize)
|
|||
{
|
||||
struct tape_request *request;
|
||||
|
||||
if (datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE)
|
||||
BUG();
|
||||
BUG_ON(datasize > PAGE_SIZE || (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
|
||||
|
||||
DBF_LH(6, "tape_alloc_request(%d, %d)\n", cplength, datasize);
|
||||
|
||||
|
|
@ -797,8 +781,7 @@ static void tape_long_busy_timeout(unsigned long data)
|
|||
device = (struct tape_device *) data;
|
||||
spin_lock_irq(get_ccwdev_lock(device->cdev));
|
||||
request = list_entry(device->req_queue.next, struct tape_request, list);
|
||||
if (request->status != TAPE_REQUEST_LONG_BUSY)
|
||||
BUG();
|
||||
BUG_ON(request->status != TAPE_REQUEST_LONG_BUSY);
|
||||
DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
|
||||
__tape_start_next_request(device);
|
||||
device->lb_timeout.data = (unsigned long) tape_put_device(device);
|
||||
|
|
@ -829,30 +812,6 @@ __tape_end_request(
|
|||
__tape_start_next_request(device);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write sense data to console/dbf
|
||||
*/
|
||||
void
|
||||
tape_dump_sense(struct tape_device* device, struct tape_request *request,
|
||||
struct irb *irb)
|
||||
{
|
||||
unsigned int *sptr;
|
||||
|
||||
PRINT_INFO("-------------------------------------------------\n");
|
||||
PRINT_INFO("DSTAT : %02x CSTAT: %02x CPA: %04x\n",
|
||||
irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa);
|
||||
PRINT_INFO("DEVICE: %s\n", dev_name(&device->cdev->dev));
|
||||
if (request != NULL)
|
||||
PRINT_INFO("OP : %s\n", tape_op_verbose[request->op]);
|
||||
|
||||
sptr = (unsigned int *) irb->ecw;
|
||||
PRINT_INFO("Sense data: %08X %08X %08X %08X \n",
|
||||
sptr[0], sptr[1], sptr[2], sptr[3]);
|
||||
PRINT_INFO("Sense data: %08X %08X %08X %08X \n",
|
||||
sptr[4], sptr[5], sptr[6], sptr[7]);
|
||||
PRINT_INFO("--------------------------------------------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Write sense data to dbf
|
||||
*/
|
||||
|
|
@ -1051,8 +1010,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
|||
|
||||
device = (struct tape_device *) cdev->dev.driver_data;
|
||||
if (device == NULL) {
|
||||
PRINT_ERR("could not get device structure for %s "
|
||||
"in interrupt\n", dev_name(&cdev->dev));
|
||||
return;
|
||||
}
|
||||
request = (struct tape_request *) intparm;
|
||||
|
|
@ -1064,13 +1021,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
|||
/* FIXME: What to do with the request? */
|
||||
switch (PTR_ERR(irb)) {
|
||||
case -ETIMEDOUT:
|
||||
PRINT_WARN("(%s): Request timed out\n",
|
||||
DBF_LH(1, "(%s): Request timed out\n",
|
||||
dev_name(&cdev->dev));
|
||||
case -EIO:
|
||||
__tape_end_request(device, request, -EIO);
|
||||
break;
|
||||
default:
|
||||
PRINT_ERR("(%s): Unexpected i/o error %li\n",
|
||||
DBF_LH(1, "(%s): Unexpected i/o error %li\n",
|
||||
dev_name(&cdev->dev),
|
||||
PTR_ERR(irb));
|
||||
}
|
||||
|
|
@ -1182,8 +1139,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
|||
default:
|
||||
if (rc > 0) {
|
||||
DBF_EVENT(6, "xunknownrc\n");
|
||||
PRINT_ERR("Invalid return code from discipline "
|
||||
"interrupt function.\n");
|
||||
__tape_end_request(device, request, -EIO);
|
||||
} else {
|
||||
__tape_end_request(device, request, rc);
|
||||
|
|
@ -1323,7 +1278,6 @@ EXPORT_SYMBOL(tape_state_set);
|
|||
EXPORT_SYMBOL(tape_med_state_set);
|
||||
EXPORT_SYMBOL(tape_alloc_request);
|
||||
EXPORT_SYMBOL(tape_free_request);
|
||||
EXPORT_SYMBOL(tape_dump_sense);
|
||||
EXPORT_SYMBOL(tape_dump_sense_dbf);
|
||||
EXPORT_SYMBOL(tape_do_io);
|
||||
EXPORT_SYMBOL(tape_do_io_async);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
#include "tape.h"
|
||||
|
||||
#define PRINTK_HEADER "TAPE_PROC: "
|
||||
|
||||
static const char *tape_med_st_verbose[MS_SIZE] =
|
||||
{
|
||||
[MS_UNKNOWN] = "UNKNOWN ",
|
||||
|
|
@ -128,7 +126,6 @@ tape_proc_init(void)
|
|||
proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL,
|
||||
&tape_proc_ops);
|
||||
if (tape_proc_devices == NULL) {
|
||||
PRINT_WARN("tape: Cannot register procfs entry tapedevices\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
#include "tape.h"
|
||||
#include "tape_std.h"
|
||||
|
||||
#define PRINTK_HEADER "TAPE_STD: "
|
||||
|
||||
/*
|
||||
* tape_std_assign
|
||||
*/
|
||||
|
|
@ -39,16 +37,15 @@ tape_std_assign_timeout(unsigned long data)
|
|||
int rc;
|
||||
|
||||
request = (struct tape_request *) data;
|
||||
if ((device = request->device) == NULL)
|
||||
BUG();
|
||||
device = request->device;
|
||||
BUG_ON(!device);
|
||||
|
||||
DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
|
||||
device->cdev_id);
|
||||
rc = tape_cancel_io(device, request);
|
||||
if(rc)
|
||||
PRINT_ERR("(%s): Assign timeout: Cancel failed with rc = %i\n",
|
||||
DBF_EVENT(3, "(%s): Assign timeout: Cancel failed with rc = %i\n",
|
||||
dev_name(&device->cdev->dev), rc);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -82,8 +79,6 @@ tape_std_assign(struct tape_device *device)
|
|||
del_timer(&timeout);
|
||||
|
||||
if (rc != 0) {
|
||||
PRINT_WARN("%s: assign failed - device might be busy\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
|
||||
device->cdev_id);
|
||||
} else {
|
||||
|
|
@ -105,8 +100,6 @@ tape_std_unassign (struct tape_device *device)
|
|||
if (device->tape_state == TS_NOT_OPER) {
|
||||
DBF_EVENT(3, "(%08x): Can't unassign device\n",
|
||||
device->cdev_id);
|
||||
PRINT_WARN("(%s): Can't unassign device - device gone\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -120,8 +113,6 @@ tape_std_unassign (struct tape_device *device)
|
|||
|
||||
if ((rc = tape_do_io(device, request)) != 0) {
|
||||
DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
|
||||
PRINT_WARN("%s: Unassign failed\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
} else {
|
||||
DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
|
||||
}
|
||||
|
|
@ -242,8 +233,6 @@ tape_std_mtsetblk(struct tape_device *device, int count)
|
|||
if (count > MAX_BLOCKSIZE) {
|
||||
DBF_EVENT(3, "Invalid block size (%d > %d) given.\n",
|
||||
count, MAX_BLOCKSIZE);
|
||||
PRINT_ERR("Invalid block size (%d > %d) given.\n",
|
||||
count, MAX_BLOCKSIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -633,14 +622,6 @@ tape_std_mtcompression(struct tape_device *device, int mt_count)
|
|||
|
||||
if (mt_count < 0 || mt_count > 1) {
|
||||
DBF_EXCEPTION(6, "xcom parm\n");
|
||||
if (*device->modeset_byte & 0x08)
|
||||
PRINT_INFO("(%s) Compression is currently on\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
else
|
||||
PRINT_INFO("(%s) Compression is currently off\n",
|
||||
dev_name(&device->cdev->dev));
|
||||
PRINT_INFO("Use 1 to switch compression on, 0 to "
|
||||
"switch it off\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
request = tape_alloc_request(2, 0);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* For more information please refer to Documentation/s390/zfcpdump.txt
|
||||
*
|
||||
* Copyright IBM Corp. 2003,2007
|
||||
* Copyright IBM Corp. 2003,2008
|
||||
* Author(s): Michael Holzheu
|
||||
*/
|
||||
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include <asm/debug.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/checksum.h>
|
||||
#include "sclp.h"
|
||||
|
||||
#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
|
||||
|
|
@ -48,12 +49,19 @@ struct sys_info {
|
|||
union save_area lc_mask;
|
||||
};
|
||||
|
||||
struct ipib_info {
|
||||
unsigned long ipib;
|
||||
u32 checksum;
|
||||
} __attribute__((packed));
|
||||
|
||||
static struct sys_info sys_info;
|
||||
static struct debug_info *zcore_dbf;
|
||||
static int hsa_available;
|
||||
static struct dentry *zcore_dir;
|
||||
static struct dentry *zcore_file;
|
||||
static struct dentry *zcore_memmap_file;
|
||||
static struct dentry *zcore_reipl_file;
|
||||
static struct ipl_parameter_block *ipl_block;
|
||||
|
||||
/*
|
||||
* Copy memory from HSA to kernel or user memory (not reentrant):
|
||||
|
|
@ -527,6 +535,33 @@ static const struct file_operations zcore_memmap_fops = {
|
|||
.release = zcore_memmap_release,
|
||||
};
|
||||
|
||||
static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
if (ipl_block) {
|
||||
diag308(DIAG308_SET, ipl_block);
|
||||
diag308(DIAG308_IPL, NULL);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int zcore_reipl_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zcore_reipl_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations zcore_reipl_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = zcore_reipl_write,
|
||||
.open = zcore_reipl_open,
|
||||
.release = zcore_reipl_release,
|
||||
};
|
||||
|
||||
|
||||
static void __init set_s390_lc_mask(union save_area *map)
|
||||
{
|
||||
|
|
@ -645,6 +680,40 @@ static int __init zcore_header_init(int arch, struct zcore_header *hdr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide IPL parameter information block from either HSA or memory
|
||||
* for future reipl
|
||||
*/
|
||||
static int __init zcore_reipl_init(void)
|
||||
{
|
||||
struct ipib_info ipib_info;
|
||||
int rc;
|
||||
|
||||
rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info));
|
||||
if (rc)
|
||||
return rc;
|
||||
if (ipib_info.ipib == 0)
|
||||
return 0;
|
||||
ipl_block = (void *) __get_free_page(GFP_KERNEL);
|
||||
if (!ipl_block)
|
||||
return -ENOMEM;
|
||||
if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE)
|
||||
rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
|
||||
else
|
||||
rc = memcpy_real(ipl_block, ipib_info.ipib, PAGE_SIZE);
|
||||
if (rc) {
|
||||
free_page((unsigned long) ipl_block);
|
||||
return rc;
|
||||
}
|
||||
if (csum_partial(ipl_block, ipl_block->hdr.len, 0) !=
|
||||
ipib_info.checksum) {
|
||||
TRACE("Checksum does not match\n");
|
||||
free_page((unsigned long) ipl_block);
|
||||
ipl_block = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init zcore_init(void)
|
||||
{
|
||||
unsigned char arch;
|
||||
|
|
@ -690,6 +759,10 @@ static int __init zcore_init(void)
|
|||
if (rc)
|
||||
goto fail;
|
||||
|
||||
rc = zcore_reipl_init();
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
zcore_dir = debugfs_create_dir("zcore" , NULL);
|
||||
if (!zcore_dir) {
|
||||
rc = -ENOMEM;
|
||||
|
|
@ -707,9 +780,17 @@ static int __init zcore_init(void)
|
|||
rc = -ENOMEM;
|
||||
goto fail_file;
|
||||
}
|
||||
zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
|
||||
NULL, &zcore_reipl_fops);
|
||||
if (!zcore_reipl_file) {
|
||||
rc = -ENOMEM;
|
||||
goto fail_memmap_file;
|
||||
}
|
||||
hsa_available = 1;
|
||||
return 0;
|
||||
|
||||
fail_memmap_file:
|
||||
debugfs_remove(zcore_memmap_file);
|
||||
fail_file:
|
||||
debugfs_remove(zcore_file);
|
||||
fail_dir:
|
||||
|
|
@ -723,10 +804,15 @@ static void __exit zcore_exit(void)
|
|||
{
|
||||
debug_unregister(zcore_dbf);
|
||||
sclp_sdias_exit();
|
||||
free_page((unsigned long) ipl_block);
|
||||
debugfs_remove(zcore_reipl_file);
|
||||
debugfs_remove(zcore_memmap_file);
|
||||
debugfs_remove(zcore_file);
|
||||
debugfs_remove(zcore_dir);
|
||||
diag308(DIAG308_REL_HSA, NULL);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Copyright IBM Corp. 2003,2007");
|
||||
MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");
|
||||
MODULE_DESCRIPTION("zcore module for zfcpdump support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
|
||||
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
|
||||
fcx.o itcw.o
|
||||
fcx.o itcw.o crw.o
|
||||
ccw_device-objs += device.o device_fsm.o device_ops.o
|
||||
ccw_device-objs += device_id.o device_pgid.o device_status.o
|
||||
obj-y += ccw_device.o cmf.o
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ struct airq_t {
|
|||
void *drv_data;
|
||||
};
|
||||
|
||||
static union indicator_t indicators[MAX_ISC];
|
||||
static struct airq_t *airqs[MAX_ISC][NR_AIRQS];
|
||||
static union indicator_t indicators[MAX_ISC+1];
|
||||
static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS];
|
||||
|
||||
static int register_airq(struct airq_t *airq, u8 isc)
|
||||
{
|
||||
|
|
@ -133,6 +133,8 @@ void do_adapter_IO(u8 isc)
|
|||
while (word) {
|
||||
if (word & INDICATOR_MASK) {
|
||||
airq = airqs[isc][i];
|
||||
/* Make sure gcc reads from airqs only once. */
|
||||
barrier();
|
||||
if (likely(airq))
|
||||
airq->handler(&indicators[isc].byte[i],
|
||||
airq->drv_data);
|
||||
|
|
|
|||
|
|
@ -336,8 +336,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
|
|||
size_t user_len, loff_t *offset)
|
||||
{
|
||||
char *buf;
|
||||
size_t i;
|
||||
ssize_t rc, ret;
|
||||
ssize_t rc, ret, i;
|
||||
|
||||
if (*offset)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -315,16 +315,32 @@ error:
|
|||
}
|
||||
EXPORT_SYMBOL(ccwgroup_create_from_string);
|
||||
|
||||
static int __init
|
||||
init_ccwgroup (void)
|
||||
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
|
||||
void *data);
|
||||
|
||||
static struct notifier_block ccwgroup_nb = {
|
||||
.notifier_call = ccwgroup_notifier
|
||||
};
|
||||
|
||||
static int __init init_ccwgroup(void)
|
||||
{
|
||||
return bus_register (&ccwgroup_bus_type);
|
||||
int ret;
|
||||
|
||||
ret = bus_register(&ccwgroup_bus_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
|
||||
if (ret)
|
||||
bus_unregister(&ccwgroup_bus_type);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
cleanup_ccwgroup (void)
|
||||
static void __exit cleanup_ccwgroup(void)
|
||||
{
|
||||
bus_unregister (&ccwgroup_bus_type);
|
||||
bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
|
||||
bus_unregister(&ccwgroup_bus_type);
|
||||
}
|
||||
|
||||
module_init(init_ccwgroup);
|
||||
|
|
@ -392,27 +408,28 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
|
|||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
gdev = to_ccwgroupdev(dev);
|
||||
if (!dev->driver)
|
||||
return count;
|
||||
return -ENODEV;
|
||||
|
||||
gdev = to_ccwgroupdev(dev);
|
||||
gdrv = to_ccwgroupdrv(dev->driver);
|
||||
|
||||
gdrv = to_ccwgroupdrv (gdev->dev.driver);
|
||||
if (!try_module_get(gdrv->owner))
|
||||
return -EINVAL;
|
||||
|
||||
ret = strict_strtoul(buf, 0, &value);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = count;
|
||||
|
||||
if (value == 1)
|
||||
ccwgroup_set_online(gdev);
|
||||
ret = ccwgroup_set_online(gdev);
|
||||
else if (value == 0)
|
||||
ccwgroup_set_offline(gdev);
|
||||
ret = ccwgroup_set_offline(gdev);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
out:
|
||||
module_put(gdrv->owner);
|
||||
return ret;
|
||||
return (ret == 0) ? count : ret;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -454,13 +471,18 @@ ccwgroup_remove (struct device *dev)
|
|||
struct ccwgroup_device *gdev;
|
||||
struct ccwgroup_driver *gdrv;
|
||||
|
||||
device_remove_file(dev, &dev_attr_online);
|
||||
device_remove_file(dev, &dev_attr_ungroup);
|
||||
|
||||
if (!dev->driver)
|
||||
return 0;
|
||||
|
||||
gdev = to_ccwgroupdev(dev);
|
||||
gdrv = to_ccwgroupdrv(dev->driver);
|
||||
|
||||
device_remove_file(dev, &dev_attr_online);
|
||||
|
||||
if (gdrv && gdrv->remove)
|
||||
if (gdrv->remove)
|
||||
gdrv->remove(gdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -469,9 +491,13 @@ static void ccwgroup_shutdown(struct device *dev)
|
|||
struct ccwgroup_device *gdev;
|
||||
struct ccwgroup_driver *gdrv;
|
||||
|
||||
if (!dev->driver)
|
||||
return;
|
||||
|
||||
gdev = to_ccwgroupdev(dev);
|
||||
gdrv = to_ccwgroupdrv(dev->driver);
|
||||
if (gdrv && gdrv->shutdown)
|
||||
|
||||
if (gdrv->shutdown)
|
||||
gdrv->shutdown(gdev);
|
||||
}
|
||||
|
||||
|
|
@ -484,6 +510,19 @@ static struct bus_type ccwgroup_bus_type = {
|
|||
.shutdown = ccwgroup_shutdown,
|
||||
};
|
||||
|
||||
|
||||
static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
|
||||
if (action == BUS_NOTIFY_UNBIND_DRIVER)
|
||||
device_schedule_callback(dev, ccwgroup_ungroup_callback);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ccwgroup_driver_register() - register a ccw group driver
|
||||
* @cdriver: driver to be registered
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
#include <linux/errno.h>
|
||||
#include <asm/chpid.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
#include "../s390mach.h"
|
||||
#include "cio.h"
|
||||
#include "css.h"
|
||||
#include "ioasm.h"
|
||||
|
|
@ -706,12 +706,12 @@ static int __init chp_init(void)
|
|||
struct chp_id chpid;
|
||||
int ret;
|
||||
|
||||
ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw);
|
||||
ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw);
|
||||
if (ret)
|
||||
return ret;
|
||||
chp_wq = create_singlethread_workqueue("cio_chp");
|
||||
if (!chp_wq) {
|
||||
s390_unregister_crw_handler(CRW_RSC_CPATH);
|
||||
crw_unregister_handler(CRW_RSC_CPATH);
|
||||
return -ENOMEM;
|
||||
}
|
||||
INIT_WORK(&cfg_work, cfg_func);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
#include <asm/cio.h>
|
||||
#include <asm/chpid.h>
|
||||
#include <asm/chsc.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
#include "../s390mach.h"
|
||||
#include "css.h"
|
||||
#include "cio.h"
|
||||
#include "cio_debug.h"
|
||||
|
|
@ -589,6 +589,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
|
|||
case 0x0102:
|
||||
case 0x0103:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
ret = chsc_error_from_response(secm_area->response.code);
|
||||
}
|
||||
|
|
@ -820,7 +821,7 @@ int __init chsc_alloc_sei_area(void)
|
|||
"chsc machine checks!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
|
||||
ret = crw_register_handler(CRW_RSC_CSS, chsc_process_crw);
|
||||
if (ret)
|
||||
kfree(sei_page);
|
||||
return ret;
|
||||
|
|
@ -828,7 +829,7 @@ int __init chsc_alloc_sei_area(void)
|
|||
|
||||
void __init chsc_free_sei_area(void)
|
||||
{
|
||||
s390_unregister_crw_handler(CRW_RSC_CSS);
|
||||
crw_unregister_handler(CRW_RSC_CSS);
|
||||
kfree(sei_page);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include <asm/isc.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/fcx.h>
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/crw.h>
|
||||
#include "cio.h"
|
||||
#include "css.h"
|
||||
#include "chsc.h"
|
||||
|
|
@ -38,7 +40,6 @@
|
|||
#include "blacklist.h"
|
||||
#include "cio_debug.h"
|
||||
#include "chp.h"
|
||||
#include "../s390mach.h"
|
||||
|
||||
debug_info_t *cio_debug_msg_id;
|
||||
debug_info_t *cio_debug_trace_id;
|
||||
|
|
@ -471,6 +472,7 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
|
|||
int cio_disable_subchannel(struct subchannel *sch)
|
||||
{
|
||||
char dbf_txt[15];
|
||||
int retry;
|
||||
int ret;
|
||||
|
||||
CIO_TRACE_EVENT (2, "dissch");
|
||||
|
|
@ -481,16 +483,17 @@ int cio_disable_subchannel(struct subchannel *sch)
|
|||
if (cio_update_schib(sch))
|
||||
return -ENODEV;
|
||||
|
||||
if (scsw_actl(&sch->schib.scsw) != 0)
|
||||
/*
|
||||
* the disable function must not be called while there are
|
||||
* requests pending for completion !
|
||||
*/
|
||||
return -EBUSY;
|
||||
|
||||
sch->config.ena = 0;
|
||||
ret = cio_commit_config(sch);
|
||||
|
||||
for (retry = 0; retry < 3; retry++) {
|
||||
ret = cio_commit_config(sch);
|
||||
if (ret == -EBUSY) {
|
||||
struct irb irb;
|
||||
if (tsch(sch->schid, &irb) != 0)
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
sprintf (dbf_txt, "ret:%d", ret);
|
||||
CIO_TRACE_EVENT (2, dbf_txt);
|
||||
return ret;
|
||||
|
|
|
|||
159
drivers/s390/cio/crw.c
Normal file
159
drivers/s390/cio/crw.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Channel report handling code
|
||||
*
|
||||
* Copyright IBM Corp. 2000,2009
|
||||
* Author(s): Ingo Adlung <adlung@de.ibm.com>,
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>,
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>,
|
||||
* Heiko Carstens <heiko.carstens@de.ibm.com>,
|
||||
*/
|
||||
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
static struct semaphore crw_semaphore;
|
||||
static DEFINE_MUTEX(crw_handler_mutex);
|
||||
static crw_handler_t crw_handlers[NR_RSCS];
|
||||
|
||||
/**
|
||||
* crw_register_handler() - register a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
* @handler: handler to be registered
|
||||
*
|
||||
* Returns %0 on success and a negative error value otherwise.
|
||||
*/
|
||||
int crw_register_handler(int rsc, crw_handler_t handler)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return -EINVAL;
|
||||
mutex_lock(&crw_handler_mutex);
|
||||
if (crw_handlers[rsc])
|
||||
rc = -EBUSY;
|
||||
else
|
||||
crw_handlers[rsc] = handler;
|
||||
mutex_unlock(&crw_handler_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* crw_unregister_handler() - unregister a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
*/
|
||||
void crw_unregister_handler(int rsc)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return;
|
||||
mutex_lock(&crw_handler_mutex);
|
||||
crw_handlers[rsc] = NULL;
|
||||
mutex_unlock(&crw_handler_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve CRWs and call function to handle event.
|
||||
*/
|
||||
static int crw_collect_info(void *unused)
|
||||
{
|
||||
struct crw crw[2];
|
||||
int ccode;
|
||||
unsigned int chain;
|
||||
int ignore;
|
||||
|
||||
repeat:
|
||||
ignore = down_interruptible(&crw_semaphore);
|
||||
chain = 0;
|
||||
while (1) {
|
||||
crw_handler_t handler;
|
||||
|
||||
if (unlikely(chain > 1)) {
|
||||
struct crw tmp_crw;
|
||||
|
||||
printk(KERN_WARNING"%s: Code does not support more "
|
||||
"than two chained crws; please report to "
|
||||
"[email protected]!\n", __func__);
|
||||
ccode = stcrw(&tmp_crw);
|
||||
printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
__func__, tmp_crw.slct, tmp_crw.oflw,
|
||||
tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
|
||||
tmp_crw.erc, tmp_crw.rsid);
|
||||
printk(KERN_WARNING"%s: This was crw number %x in the "
|
||||
"chain\n", __func__, chain);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
chain = tmp_crw.chn ? chain + 1 : 0;
|
||||
continue;
|
||||
}
|
||||
ccode = stcrw(&crw[chain]);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
crw[chain].slct, crw[chain].oflw, crw[chain].chn,
|
||||
crw[chain].rsc, crw[chain].anc, crw[chain].erc,
|
||||
crw[chain].rsid);
|
||||
/* Check for overflows. */
|
||||
if (crw[chain].oflw) {
|
||||
int i;
|
||||
|
||||
pr_debug("%s: crw overflow detected!\n", __func__);
|
||||
mutex_lock(&crw_handler_mutex);
|
||||
for (i = 0; i < NR_RSCS; i++) {
|
||||
if (crw_handlers[i])
|
||||
crw_handlers[i](NULL, NULL, 1);
|
||||
}
|
||||
mutex_unlock(&crw_handler_mutex);
|
||||
chain = 0;
|
||||
continue;
|
||||
}
|
||||
if (crw[0].chn && !chain) {
|
||||
chain++;
|
||||
continue;
|
||||
}
|
||||
mutex_lock(&crw_handler_mutex);
|
||||
handler = crw_handlers[crw[chain].rsc];
|
||||
if (handler)
|
||||
handler(&crw[0], chain ? &crw[1] : NULL, 0);
|
||||
mutex_unlock(&crw_handler_mutex);
|
||||
/* chain is always 0 or 1 here. */
|
||||
chain = crw[chain].chn ? chain + 1 : 0;
|
||||
}
|
||||
goto repeat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crw_handle_channel_report(void)
|
||||
{
|
||||
up(&crw_semaphore);
|
||||
}
|
||||
|
||||
/*
|
||||
* Separate initcall needed for semaphore initialization since
|
||||
* crw_handle_channel_report might be called before crw_machine_check_init.
|
||||
*/
|
||||
static int __init crw_init_semaphore(void)
|
||||
{
|
||||
init_MUTEX_LOCKED(&crw_semaphore);
|
||||
return 0;
|
||||
}
|
||||
pure_initcall(crw_init_semaphore);
|
||||
|
||||
/*
|
||||
* Machine checks for the channel subsystem must be enabled
|
||||
* after the channel subsystem is initialized
|
||||
*/
|
||||
static int __init crw_machine_check_init(void)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = kthread_run(crw_collect_info, NULL, "kmcheck");
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
ctl_set_bit(14, 28); /* enable channel report MCH */
|
||||
return 0;
|
||||
}
|
||||
device_initcall(crw_machine_check_init);
|
||||
|
|
@ -18,8 +18,8 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/isc.h>
|
||||
#include <asm/crw.h>
|
||||
|
||||
#include "../s390mach.h"
|
||||
#include "css.h"
|
||||
#include "cio.h"
|
||||
#include "cio_debug.h"
|
||||
|
|
@ -83,6 +83,25 @@ static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int call_fn_all_sch(struct subchannel_id schid, void *data)
|
||||
{
|
||||
struct cb_data *cb = data;
|
||||
struct subchannel *sch;
|
||||
int rc = 0;
|
||||
|
||||
sch = get_subchannel_by_schid(schid);
|
||||
if (sch) {
|
||||
if (cb->fn_known_sch)
|
||||
rc = cb->fn_known_sch(sch, cb->data);
|
||||
put_device(&sch->dev);
|
||||
} else {
|
||||
if (cb->fn_unknown_sch)
|
||||
rc = cb->fn_unknown_sch(schid, cb->data);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
|
||||
int (*fn_unknown)(struct subchannel_id,
|
||||
void *), void *data)
|
||||
|
|
@ -90,13 +109,17 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
|
|||
struct cb_data cb;
|
||||
int rc;
|
||||
|
||||
cb.set = idset_sch_new();
|
||||
if (!cb.set)
|
||||
return -ENOMEM;
|
||||
idset_fill(cb.set);
|
||||
cb.data = data;
|
||||
cb.fn_known_sch = fn_known;
|
||||
cb.fn_unknown_sch = fn_unknown;
|
||||
|
||||
cb.set = idset_sch_new();
|
||||
if (!cb.set)
|
||||
/* fall back to brute force scanning in case of oom */
|
||||
return for_each_subchannel(call_fn_all_sch, &cb);
|
||||
|
||||
idset_fill(cb.set);
|
||||
|
||||
/* Process registered subchannels. */
|
||||
rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
|
||||
if (rc)
|
||||
|
|
@ -510,6 +533,17 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void reprobe_after_idle(struct work_struct *unused)
|
||||
{
|
||||
/* Make sure initial subchannel scan is done. */
|
||||
wait_event(ccw_device_init_wq,
|
||||
atomic_read(&ccw_device_init_count) == 0);
|
||||
if (need_reprobe)
|
||||
css_schedule_reprobe();
|
||||
}
|
||||
|
||||
static DECLARE_WORK(reprobe_idle_work, reprobe_after_idle);
|
||||
|
||||
/* Work function used to reprobe all unregistered subchannels. */
|
||||
static void reprobe_all(struct work_struct *unused)
|
||||
{
|
||||
|
|
@ -517,10 +551,12 @@ static void reprobe_all(struct work_struct *unused)
|
|||
|
||||
CIO_MSG_EVENT(4, "reprobe start\n");
|
||||
|
||||
need_reprobe = 0;
|
||||
/* Make sure initial subchannel scan is done. */
|
||||
wait_event(ccw_device_init_wq,
|
||||
atomic_read(&ccw_device_init_count) == 0);
|
||||
if (atomic_read(&ccw_device_init_count) != 0) {
|
||||
queue_work(ccw_device_work, &reprobe_idle_work);
|
||||
return;
|
||||
}
|
||||
need_reprobe = 0;
|
||||
ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
|
||||
|
||||
CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
|
||||
|
|
@ -619,7 +655,7 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
|
|||
css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
|
||||
} else {
|
||||
#ifdef CONFIG_SMP
|
||||
css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id();
|
||||
css->global_pgid.pgid_high.cpu_addr = stap();
|
||||
#else
|
||||
css->global_pgid.pgid_high.cpu_addr = 0;
|
||||
#endif
|
||||
|
|
@ -765,7 +801,7 @@ init_channel_subsystem (void)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw);
|
||||
ret = crw_register_handler(CRW_RSC_SCH, css_process_crw);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
|
@ -845,7 +881,7 @@ out_unregister:
|
|||
out_bus:
|
||||
bus_unregister(&css_bus_type);
|
||||
out:
|
||||
s390_unregister_crw_handler(CRW_RSC_CSS);
|
||||
crw_unregister_handler(CRW_RSC_CSS);
|
||||
chsc_free_sei_area();
|
||||
kfree(slow_subchannel_set);
|
||||
pr_alert("The CSS device driver initialization failed with "
|
||||
|
|
|
|||
|
|
@ -457,12 +457,13 @@ int ccw_device_set_online(struct ccw_device *cdev)
|
|||
return (ret == 0) ? -ENODEV : ret;
|
||||
}
|
||||
|
||||
static void online_store_handle_offline(struct ccw_device *cdev)
|
||||
static int online_store_handle_offline(struct ccw_device *cdev)
|
||||
{
|
||||
if (cdev->private->state == DEV_STATE_DISCONNECTED)
|
||||
ccw_device_remove_disconnected(cdev);
|
||||
else if (cdev->drv && cdev->drv->set_offline)
|
||||
ccw_device_set_offline(cdev);
|
||||
else if (cdev->online && cdev->drv && cdev->drv->set_offline)
|
||||
return ccw_device_set_offline(cdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int online_store_recog_and_online(struct ccw_device *cdev)
|
||||
|
|
@ -530,13 +531,10 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
|
|||
goto out;
|
||||
switch (i) {
|
||||
case 0:
|
||||
online_store_handle_offline(cdev);
|
||||
ret = count;
|
||||
ret = online_store_handle_offline(cdev);
|
||||
break;
|
||||
case 1:
|
||||
ret = online_store_handle_online(cdev, force);
|
||||
if (!ret)
|
||||
ret = count;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
|
@ -545,7 +543,7 @@ out:
|
|||
if (cdev->drv)
|
||||
module_put(cdev->drv->owner);
|
||||
atomic_set(&cdev->private->onoff, 0);
|
||||
return ret;
|
||||
return (ret < 0) ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
@ -681,35 +679,22 @@ get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css,
|
|||
return dev ? to_ccwdev(dev) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ccw_device_add_changed(struct work_struct *work)
|
||||
{
|
||||
struct ccw_device_private *priv;
|
||||
struct ccw_device *cdev;
|
||||
|
||||
priv = container_of(work, struct ccw_device_private, kick_work);
|
||||
cdev = priv->cdev;
|
||||
if (device_add(&cdev->dev)) {
|
||||
put_device(&cdev->dev);
|
||||
return;
|
||||
}
|
||||
set_bit(1, &cdev->private->registered);
|
||||
}
|
||||
|
||||
void ccw_device_do_unreg_rereg(struct work_struct *work)
|
||||
void ccw_device_do_unbind_bind(struct work_struct *work)
|
||||
{
|
||||
struct ccw_device_private *priv;
|
||||
struct ccw_device *cdev;
|
||||
struct subchannel *sch;
|
||||
int ret;
|
||||
|
||||
priv = container_of(work, struct ccw_device_private, kick_work);
|
||||
cdev = priv->cdev;
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
|
||||
ccw_device_unregister(cdev);
|
||||
PREPARE_WORK(&cdev->private->kick_work,
|
||||
ccw_device_add_changed);
|
||||
queue_work(ccw_device_work, &cdev->private->kick_work);
|
||||
if (test_bit(1, &cdev->private->registered)) {
|
||||
device_release_driver(&cdev->dev);
|
||||
ret = device_attach(&cdev->dev);
|
||||
WARN_ON(ret == -ENODEV);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1035,8 +1020,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
|
|||
void
|
||||
io_subchannel_recog_done(struct ccw_device *cdev)
|
||||
{
|
||||
struct subchannel *sch;
|
||||
|
||||
if (css_init_done == 0) {
|
||||
cdev->private->flags.recog_done = 1;
|
||||
return;
|
||||
|
|
@ -1047,7 +1030,6 @@ io_subchannel_recog_done(struct ccw_device *cdev)
|
|||
/* Remove device found not operational. */
|
||||
if (!get_device(&cdev->dev))
|
||||
break;
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
PREPARE_WORK(&cdev->private->kick_work,
|
||||
ccw_device_call_sch_unregister);
|
||||
queue_work(slow_path_wq, &cdev->private->kick_work);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ void io_subchannel_init_config(struct subchannel *sch);
|
|||
|
||||
int ccw_device_cancel_halt_clear(struct ccw_device *);
|
||||
|
||||
void ccw_device_do_unreg_rereg(struct work_struct *);
|
||||
void ccw_device_do_unbind_bind(struct work_struct *);
|
||||
void ccw_device_move_to_orphanage(struct work_struct *);
|
||||
int ccw_device_is_orphan(struct ccw_device *);
|
||||
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)
|
|||
cdev->id.dev_type != cdev->private->senseid.dev_type ||
|
||||
cdev->id.dev_model != cdev->private->senseid.dev_model) {
|
||||
PREPARE_WORK(&cdev->private->kick_work,
|
||||
ccw_device_do_unreg_rereg);
|
||||
ccw_device_do_unbind_bind);
|
||||
queue_work(ccw_device_work, &cdev->private->kick_work);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -366,7 +366,7 @@ static void ccw_device_oper_notify(struct ccw_device *cdev)
|
|||
}
|
||||
/* Driver doesn't want device back. */
|
||||
ccw_device_set_notoper(cdev);
|
||||
PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unreg_rereg);
|
||||
PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind);
|
||||
queue_work(ccw_device_work, &cdev->private->kick_work);
|
||||
}
|
||||
|
||||
|
|
@ -728,7 +728,7 @@ static void ccw_device_generic_notoper(struct ccw_device *cdev,
|
|||
{
|
||||
struct subchannel *sch;
|
||||
|
||||
cdev->private->state = DEV_STATE_NOT_OPER;
|
||||
ccw_device_set_notoper(cdev);
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
css_schedule_eval(sch->schid);
|
||||
}
|
||||
|
|
@ -1052,7 +1052,7 @@ ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event)
|
|||
sch = to_subchannel(cdev->dev.parent);
|
||||
/*
|
||||
* An interrupt in state offline means a previous disable was not
|
||||
* successful. Try again.
|
||||
* successful - should not happen, but we try to disable again.
|
||||
*/
|
||||
cio_disable_subchannel(sch);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)
|
|||
if (cdev->private->state != DEV_STATE_ONLINE)
|
||||
return -EIO;
|
||||
if (!scsw_is_tm(&sch->schib.scsw) ||
|
||||
!(scsw_actl(&sch->schib.scsw) | SCSW_ACTL_START_PEND))
|
||||
!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_START_PEND))
|
||||
return -EINVAL;
|
||||
return cio_tm_intrg(sch);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,9 @@ struct qdio_input_q {
|
|||
/* input buffer acknowledgement flag */
|
||||
int polling;
|
||||
|
||||
/* first ACK'ed buffer */
|
||||
int ack_start;
|
||||
|
||||
/* how much sbals are acknowledged with qebsm */
|
||||
int ack_count;
|
||||
|
||||
|
|
@ -234,7 +237,7 @@ struct qdio_q {
|
|||
int first_to_check;
|
||||
|
||||
/* first_to_check of the last time */
|
||||
int last_move_ftc;
|
||||
int last_move;
|
||||
|
||||
/* beginning position for calling the program */
|
||||
int first_to_kick;
|
||||
|
|
@ -244,7 +247,6 @@ struct qdio_q {
|
|||
|
||||
struct qdio_irq *irq_ptr;
|
||||
struct tasklet_struct tasklet;
|
||||
spinlock_t lock;
|
||||
|
||||
/* error condition during a data transfer */
|
||||
unsigned int qdio_error;
|
||||
|
|
@ -354,7 +356,7 @@ int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state,
|
|||
int auto_ack);
|
||||
void qdio_check_outbound_after_thinint(struct qdio_q *q);
|
||||
int qdio_inbound_q_moved(struct qdio_q *q);
|
||||
void qdio_kick_inbound_handler(struct qdio_q *q);
|
||||
void qdio_kick_handler(struct qdio_q *q);
|
||||
void qdio_stop_polling(struct qdio_q *q);
|
||||
int qdio_siga_sync_q(struct qdio_q *q);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,8 +63,9 @@ static int qstat_show(struct seq_file *m, void *v)
|
|||
seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
|
||||
seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
|
||||
seq_printf(m, "ftc: %d\n", q->first_to_check);
|
||||
seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc);
|
||||
seq_printf(m, "last_move: %d\n", q->last_move);
|
||||
seq_printf(m, "polling: %d\n", q->u.in.polling);
|
||||
seq_printf(m, "ack start: %d\n", q->u.in.ack_start);
|
||||
seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
|
||||
seq_printf(m, "slsb buffer states:\n");
|
||||
seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n");
|
||||
|
|
|
|||
|
|
@ -380,11 +380,11 @@ inline void qdio_stop_polling(struct qdio_q *q)
|
|||
|
||||
/* show the card that we are not polling anymore */
|
||||
if (is_qebsm(q)) {
|
||||
set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
|
||||
set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,
|
||||
q->u.in.ack_count);
|
||||
q->u.in.ack_count = 0;
|
||||
} else
|
||||
set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
|
||||
set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
|
||||
}
|
||||
|
||||
static void announce_buffer_error(struct qdio_q *q, int count)
|
||||
|
|
@ -419,15 +419,15 @@ static inline void inbound_primed(struct qdio_q *q, int count)
|
|||
if (!q->u.in.polling) {
|
||||
q->u.in.polling = 1;
|
||||
q->u.in.ack_count = count;
|
||||
q->last_move_ftc = q->first_to_check;
|
||||
q->u.in.ack_start = q->first_to_check;
|
||||
return;
|
||||
}
|
||||
|
||||
/* delete the previous ACK's */
|
||||
set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT,
|
||||
set_buf_states(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT,
|
||||
q->u.in.ack_count);
|
||||
q->u.in.ack_count = count;
|
||||
q->last_move_ftc = q->first_to_check;
|
||||
q->u.in.ack_start = q->first_to_check;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -439,14 +439,13 @@ static inline void inbound_primed(struct qdio_q *q, int count)
|
|||
if (q->u.in.polling) {
|
||||
/* reset the previous ACK but first set the new one */
|
||||
set_buf_state(q, new, SLSB_P_INPUT_ACK);
|
||||
set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT);
|
||||
}
|
||||
else {
|
||||
set_buf_state(q, q->u.in.ack_start, SLSB_P_INPUT_NOT_INIT);
|
||||
} else {
|
||||
q->u.in.polling = 1;
|
||||
set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK);
|
||||
set_buf_state(q, new, SLSB_P_INPUT_ACK);
|
||||
}
|
||||
|
||||
q->last_move_ftc = new;
|
||||
q->u.in.ack_start = new;
|
||||
count--;
|
||||
if (!count)
|
||||
return;
|
||||
|
|
@ -455,7 +454,7 @@ static inline void inbound_primed(struct qdio_q *q, int count)
|
|||
* Need to change all PRIMED buffers to NOT_INIT, otherwise
|
||||
* we're loosing initiative in the thinint code.
|
||||
*/
|
||||
set_buf_states(q, next_buf(q->first_to_check), SLSB_P_INPUT_NOT_INIT,
|
||||
set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT,
|
||||
count);
|
||||
}
|
||||
|
||||
|
|
@ -523,7 +522,8 @@ int qdio_inbound_q_moved(struct qdio_q *q)
|
|||
|
||||
bufnr = get_inbound_buffer_frontier(q);
|
||||
|
||||
if ((bufnr != q->last_move_ftc) || q->qdio_error) {
|
||||
if ((bufnr != q->last_move) || q->qdio_error) {
|
||||
q->last_move = bufnr;
|
||||
if (!need_siga_sync(q) && !pci_out_supported(q))
|
||||
q->u.in.timestamp = get_usecs();
|
||||
|
||||
|
|
@ -570,29 +570,30 @@ static int qdio_inbound_q_done(struct qdio_q *q)
|
|||
}
|
||||
}
|
||||
|
||||
void qdio_kick_inbound_handler(struct qdio_q *q)
|
||||
void qdio_kick_handler(struct qdio_q *q)
|
||||
{
|
||||
int count, start, end;
|
||||
|
||||
qdio_perf_stat_inc(&perf_stats.inbound_handler);
|
||||
|
||||
start = q->first_to_kick;
|
||||
end = q->first_to_check;
|
||||
if (end >= start)
|
||||
count = end - start;
|
||||
else
|
||||
count = end + QDIO_MAX_BUFFERS_PER_Q - start;
|
||||
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count);
|
||||
int start = q->first_to_kick;
|
||||
int end = q->first_to_check;
|
||||
int count;
|
||||
|
||||
if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
|
||||
return;
|
||||
|
||||
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr,
|
||||
start, count, q->irq_ptr->int_parm);
|
||||
count = sub_buf(end, start);
|
||||
|
||||
if (q->is_input_q) {
|
||||
qdio_perf_stat_inc(&perf_stats.inbound_handler);
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count);
|
||||
} else {
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: nr:%1d", q->nr);
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count);
|
||||
}
|
||||
|
||||
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
|
||||
q->irq_ptr->int_parm);
|
||||
|
||||
/* for the next time */
|
||||
q->first_to_kick = q->first_to_check;
|
||||
q->first_to_kick = end;
|
||||
q->qdio_error = 0;
|
||||
}
|
||||
|
||||
|
|
@ -603,7 +604,7 @@ again:
|
|||
if (!qdio_inbound_q_moved(q))
|
||||
return;
|
||||
|
||||
qdio_kick_inbound_handler(q);
|
||||
qdio_kick_handler(q);
|
||||
|
||||
if (!qdio_inbound_q_done(q))
|
||||
/* means poll time is not yet over */
|
||||
|
|
@ -698,21 +699,21 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q)
|
|||
|
||||
bufnr = get_outbound_buffer_frontier(q);
|
||||
|
||||
if ((bufnr != q->last_move_ftc) || q->qdio_error) {
|
||||
q->last_move_ftc = bufnr;
|
||||
if ((bufnr != q->last_move) || q->qdio_error) {
|
||||
q->last_move = bufnr;
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qdio_kick_outbound_q(struct qdio_q *q)
|
||||
static int qdio_kick_outbound_q(struct qdio_q *q)
|
||||
{
|
||||
unsigned int busy_bit;
|
||||
int cc;
|
||||
|
||||
if (!need_siga_out(q))
|
||||
return;
|
||||
return 0;
|
||||
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr);
|
||||
qdio_perf_stat_inc(&perf_stats.siga_out);
|
||||
|
|
@ -724,75 +725,37 @@ static void qdio_kick_outbound_q(struct qdio_q *q)
|
|||
case 2:
|
||||
if (busy_bit) {
|
||||
DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr);
|
||||
q->qdio_error = cc | QDIO_ERROR_SIGA_BUSY;
|
||||
} else {
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d",
|
||||
q->nr);
|
||||
q->qdio_error = cc;
|
||||
}
|
||||
cc |= QDIO_ERROR_SIGA_BUSY;
|
||||
} else
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr);
|
||||
break;
|
||||
case 1:
|
||||
case 3:
|
||||
DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc);
|
||||
q->qdio_error = cc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void qdio_kick_outbound_handler(struct qdio_q *q)
|
||||
{
|
||||
int start, end, count;
|
||||
|
||||
start = q->first_to_kick;
|
||||
end = q->last_move_ftc;
|
||||
if (end >= start)
|
||||
count = end - start;
|
||||
else
|
||||
count = end + QDIO_MAX_BUFFERS_PER_Q - start;
|
||||
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kickouth: %1d", q->nr);
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "s:%3d c:%3d", start, count);
|
||||
|
||||
if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE))
|
||||
return;
|
||||
|
||||
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
|
||||
q->irq_ptr->int_parm);
|
||||
|
||||
/* for the next time: */
|
||||
q->first_to_kick = q->last_move_ftc;
|
||||
q->qdio_error = 0;
|
||||
return cc;
|
||||
}
|
||||
|
||||
static void __qdio_outbound_processing(struct qdio_q *q)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
qdio_perf_stat_inc(&perf_stats.tasklet_outbound);
|
||||
spin_lock_irqsave(&q->lock, flags);
|
||||
|
||||
BUG_ON(atomic_read(&q->nr_buf_used) < 0);
|
||||
|
||||
if (qdio_outbound_q_moved(q))
|
||||
qdio_kick_outbound_handler(q);
|
||||
qdio_kick_handler(q);
|
||||
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
|
||||
if (queue_type(q) == QDIO_ZFCP_QFMT) {
|
||||
if (queue_type(q) == QDIO_ZFCP_QFMT)
|
||||
if (!pci_out_supported(q) && !qdio_outbound_q_done(q))
|
||||
tasklet_schedule(&q->tasklet);
|
||||
return;
|
||||
}
|
||||
goto sched;
|
||||
|
||||
/* bail out for HiperSockets unicast queues */
|
||||
if (queue_type(q) == QDIO_IQDIO_QFMT && !multicast_outbound(q))
|
||||
return;
|
||||
|
||||
if ((queue_type(q) == QDIO_IQDIO_QFMT) &&
|
||||
(atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL) {
|
||||
tasklet_schedule(&q->tasklet);
|
||||
return;
|
||||
}
|
||||
(atomic_read(&q->nr_buf_used)) > QDIO_IQDIO_POLL_LVL)
|
||||
goto sched;
|
||||
|
||||
if (q->u.out.pci_out_enabled)
|
||||
return;
|
||||
|
|
@ -810,6 +773,12 @@ static void __qdio_outbound_processing(struct qdio_q *q)
|
|||
qdio_perf_stat_inc(&perf_stats.debug_tl_out_timer);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
sched:
|
||||
if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
|
||||
return;
|
||||
tasklet_schedule(&q->tasklet);
|
||||
}
|
||||
|
||||
/* outbound tasklet */
|
||||
|
|
@ -822,6 +791,9 @@ void qdio_outbound_processing(unsigned long data)
|
|||
void qdio_outbound_timer(unsigned long data)
|
||||
{
|
||||
struct qdio_q *q = (struct qdio_q *)data;
|
||||
|
||||
if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
|
||||
return;
|
||||
tasklet_schedule(&q->tasklet);
|
||||
}
|
||||
|
||||
|
|
@ -863,6 +835,9 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
|
|||
int i;
|
||||
struct qdio_q *q;
|
||||
|
||||
if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED))
|
||||
return;
|
||||
|
||||
qdio_perf_stat_inc(&perf_stats.pci_int);
|
||||
|
||||
for_each_input_queue(irq_ptr, q, i)
|
||||
|
|
@ -1065,8 +1040,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc);
|
|||
* @cdev: associated ccw device
|
||||
* @how: use halt or clear to shutdown
|
||||
*
|
||||
* This function calls qdio_shutdown() for @cdev with method @how
|
||||
* and on success qdio_free() for @cdev.
|
||||
* This function calls qdio_shutdown() for @cdev with method @how.
|
||||
* and qdio_free(). The qdio_free() return value is ignored since
|
||||
* !irq_ptr is already checked.
|
||||
*/
|
||||
int qdio_cleanup(struct ccw_device *cdev, int how)
|
||||
{
|
||||
|
|
@ -1077,8 +1053,8 @@ int qdio_cleanup(struct ccw_device *cdev, int how)
|
|||
return -ENODEV;
|
||||
|
||||
rc = qdio_shutdown(cdev, how);
|
||||
if (rc == 0)
|
||||
rc = qdio_free(cdev);
|
||||
|
||||
qdio_free(cdev);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qdio_cleanup);
|
||||
|
|
@ -1090,11 +1066,11 @@ static void qdio_shutdown_queues(struct ccw_device *cdev)
|
|||
int i;
|
||||
|
||||
for_each_input_queue(irq_ptr, q, i)
|
||||
tasklet_disable(&q->tasklet);
|
||||
tasklet_kill(&q->tasklet);
|
||||
|
||||
for_each_output_queue(irq_ptr, q, i) {
|
||||
tasklet_disable(&q->tasklet);
|
||||
del_timer(&q->u.out.timer);
|
||||
tasklet_kill(&q->tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1112,6 +1088,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how)
|
|||
if (!irq_ptr)
|
||||
return -ENODEV;
|
||||
|
||||
BUG_ON(irqs_disabled());
|
||||
DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no);
|
||||
|
||||
mutex_lock(&irq_ptr->setup_mutex);
|
||||
|
|
@ -1124,6 +1101,12 @@ int qdio_shutdown(struct ccw_device *cdev, int how)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicate that the device is going down. Scheduling the queue
|
||||
* tasklets is forbidden from here on.
|
||||
*/
|
||||
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED);
|
||||
|
||||
tiqdio_remove_input_queues(irq_ptr);
|
||||
qdio_shutdown_queues(cdev);
|
||||
qdio_shutdown_debug_entries(irq_ptr, cdev);
|
||||
|
|
@ -1403,9 +1386,8 @@ int qdio_activate(struct ccw_device *cdev)
|
|||
switch (irq_ptr->state) {
|
||||
case QDIO_IRQ_STATE_STOPPED:
|
||||
case QDIO_IRQ_STATE_ERR:
|
||||
mutex_unlock(&irq_ptr->setup_mutex);
|
||||
qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
|
||||
return -EIO;
|
||||
rc = -EIO;
|
||||
break;
|
||||
default:
|
||||
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
|
||||
rc = 0;
|
||||
|
|
@ -1442,10 +1424,10 @@ static inline int buf_in_between(int bufnr, int start, int count)
|
|||
* @bufnr: first buffer to process
|
||||
* @count: how many buffers are emptied
|
||||
*/
|
||||
static void handle_inbound(struct qdio_q *q, unsigned int callflags,
|
||||
int bufnr, int count)
|
||||
static int handle_inbound(struct qdio_q *q, unsigned int callflags,
|
||||
int bufnr, int count)
|
||||
{
|
||||
int used, cc, diff;
|
||||
int used, diff;
|
||||
|
||||
if (!q->u.in.polling)
|
||||
goto set;
|
||||
|
|
@ -1456,19 +1438,18 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags,
|
|||
q->u.in.polling = 0;
|
||||
q->u.in.ack_count = 0;
|
||||
goto set;
|
||||
} else if (buf_in_between(q->last_move_ftc, bufnr, count)) {
|
||||
} else if (buf_in_between(q->u.in.ack_start, bufnr, count)) {
|
||||
if (is_qebsm(q)) {
|
||||
/* partial overwrite, just update last_move_ftc */
|
||||
/* partial overwrite, just update ack_start */
|
||||
diff = add_buf(bufnr, count);
|
||||
diff = sub_buf(diff, q->last_move_ftc);
|
||||
diff = sub_buf(diff, q->u.in.ack_start);
|
||||
q->u.in.ack_count -= diff;
|
||||
if (q->u.in.ack_count <= 0) {
|
||||
q->u.in.polling = 0;
|
||||
q->u.in.ack_count = 0;
|
||||
/* TODO: must we set last_move_ftc to something meaningful? */
|
||||
goto set;
|
||||
}
|
||||
q->last_move_ftc = add_buf(q->last_move_ftc, diff);
|
||||
q->u.in.ack_start = add_buf(q->u.in.ack_start, diff);
|
||||
}
|
||||
else
|
||||
/* the only ACK will be deleted, so stop polling */
|
||||
|
|
@ -1483,13 +1464,11 @@ set:
|
|||
|
||||
/* no need to signal as long as the adapter had free buffers */
|
||||
if (used)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (need_siga_in(q)) {
|
||||
cc = qdio_siga_input(q);
|
||||
if (cc)
|
||||
q->qdio_error = cc;
|
||||
}
|
||||
if (need_siga_in(q))
|
||||
return qdio_siga_input(q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1499,11 +1478,11 @@ set:
|
|||
* @bufnr: first buffer to process
|
||||
* @count: how many buffers are filled
|
||||
*/
|
||||
static void handle_outbound(struct qdio_q *q, unsigned int callflags,
|
||||
int bufnr, int count)
|
||||
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
|
||||
int bufnr, int count)
|
||||
{
|
||||
unsigned char state;
|
||||
int used;
|
||||
int used, rc = 0;
|
||||
|
||||
qdio_perf_stat_inc(&perf_stats.outbound_handler);
|
||||
|
||||
|
|
@ -1518,27 +1497,26 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
|
|||
|
||||
if (queue_type(q) == QDIO_IQDIO_QFMT) {
|
||||
if (multicast_outbound(q))
|
||||
qdio_kick_outbound_q(q);
|
||||
rc = qdio_kick_outbound_q(q);
|
||||
else
|
||||
if ((q->irq_ptr->ssqd_desc.mmwc > 1) &&
|
||||
(count > 1) &&
|
||||
(count <= q->irq_ptr->ssqd_desc.mmwc)) {
|
||||
/* exploit enhanced SIGA */
|
||||
q->u.out.use_enh_siga = 1;
|
||||
qdio_kick_outbound_q(q);
|
||||
rc = qdio_kick_outbound_q(q);
|
||||
} else {
|
||||
/*
|
||||
* One siga-w per buffer required for unicast
|
||||
* HiperSockets.
|
||||
*/
|
||||
q->u.out.use_enh_siga = 0;
|
||||
while (count--)
|
||||
qdio_kick_outbound_q(q);
|
||||
while (count--) {
|
||||
rc = qdio_kick_outbound_q(q);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* report CC=2 conditions synchronously */
|
||||
if (q->qdio_error)
|
||||
__qdio_outbound_processing(q);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -1550,14 +1528,14 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags,
|
|||
/* try to fast requeue buffers */
|
||||
get_buf_state(q, prev_buf(bufnr), &state, 0);
|
||||
if (state != SLSB_CU_OUTPUT_PRIMED)
|
||||
qdio_kick_outbound_q(q);
|
||||
rc = qdio_kick_outbound_q(q);
|
||||
else {
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req");
|
||||
qdio_perf_stat_inc(&perf_stats.fast_requeue);
|
||||
}
|
||||
out:
|
||||
/* Fixme: could wait forever if called from process context */
|
||||
tasklet_schedule(&q->tasklet);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1596,14 +1574,12 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
|
|||
return -EBUSY;
|
||||
|
||||
if (callflags & QDIO_FLAG_SYNC_INPUT)
|
||||
handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr,
|
||||
count);
|
||||
return handle_inbound(irq_ptr->input_qs[q_nr],
|
||||
callflags, bufnr, count);
|
||||
else if (callflags & QDIO_FLAG_SYNC_OUTPUT)
|
||||
handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr,
|
||||
count);
|
||||
else
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
return handle_outbound(irq_ptr->output_qs[q_nr],
|
||||
callflags, bufnr, count);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(do_QDIO);
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
|
|||
q->mask = 1 << (31 - i);
|
||||
q->nr = i;
|
||||
q->handler = handler;
|
||||
spin_lock_init(&q->lock);
|
||||
}
|
||||
|
||||
static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
/* list of thin interrupt input queues */
|
||||
static LIST_HEAD(tiq_list);
|
||||
DEFINE_MUTEX(tiq_list_lock);
|
||||
|
||||
/* adapter local summary indicator */
|
||||
static unsigned char *tiqdio_alsi;
|
||||
|
|
@ -95,12 +96,11 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
|
|||
if (!css_qdio_omit_svs && irq_ptr->siga_flag.sync)
|
||||
css_qdio_omit_svs = 1;
|
||||
|
||||
for_each_input_queue(irq_ptr, q, i) {
|
||||
mutex_lock(&tiq_list_lock);
|
||||
for_each_input_queue(irq_ptr, q, i)
|
||||
list_add_rcu(&q->entry, &tiq_list);
|
||||
synchronize_rcu();
|
||||
}
|
||||
mutex_unlock(&tiq_list_lock);
|
||||
xchg(irq_ptr->dsci, 1);
|
||||
tasklet_schedule(&tiqdio_tasklet);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -118,7 +118,10 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
|
|||
/* if establish triggered an error */
|
||||
if (!q || !q->entry.prev || !q->entry.next)
|
||||
continue;
|
||||
|
||||
mutex_lock(&tiq_list_lock);
|
||||
list_del_rcu(&q->entry);
|
||||
mutex_unlock(&tiq_list_lock);
|
||||
synchronize_rcu();
|
||||
}
|
||||
}
|
||||
|
|
@ -155,15 +158,15 @@ static void __tiqdio_inbound_processing(struct qdio_q *q)
|
|||
*/
|
||||
qdio_check_outbound_after_thinint(q);
|
||||
|
||||
again:
|
||||
if (!qdio_inbound_q_moved(q))
|
||||
return;
|
||||
|
||||
qdio_kick_inbound_handler(q);
|
||||
qdio_kick_handler(q);
|
||||
|
||||
if (!tiqdio_inbound_q_done(q)) {
|
||||
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop);
|
||||
goto again;
|
||||
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
|
||||
tasklet_schedule(&q->tasklet);
|
||||
}
|
||||
|
||||
qdio_stop_polling(q);
|
||||
|
|
@ -173,7 +176,8 @@ again:
|
|||
*/
|
||||
if (!tiqdio_inbound_q_done(q)) {
|
||||
qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2);
|
||||
goto again;
|
||||
if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
|
||||
tasklet_schedule(&q->tasklet);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,10 +370,11 @@ void qdio_shutdown_thinint(struct qdio_irq *irq_ptr)
|
|||
|
||||
void __exit tiqdio_unregister_thinints(void)
|
||||
{
|
||||
tasklet_disable(&tiqdio_tasklet);
|
||||
WARN_ON(!list_empty(&tiq_list));
|
||||
|
||||
if (tiqdio_alsi) {
|
||||
s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC);
|
||||
isc_unregister(QDIO_AIRQ_ISC);
|
||||
}
|
||||
tasklet_kill(&tiqdio_tasklet);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,8 +128,7 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
|
|||
if (l == zdev->list.prev)
|
||||
return;
|
||||
/* Move zdev behind l */
|
||||
list_del(&zdev->list);
|
||||
list_add(&zdev->list, l);
|
||||
list_move(&zdev->list, l);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,8 +156,7 @@ static void __zcrypt_decrease_preference(struct zcrypt_device *zdev)
|
|||
if (l == zdev->list.next)
|
||||
return;
|
||||
/* Move zdev before l */
|
||||
list_del(&zdev->list);
|
||||
list_add_tail(&zdev->list, l);
|
||||
list_move_tail(&zdev->list, l);
|
||||
}
|
||||
|
||||
static void zcrypt_device_release(struct kref *kref)
|
||||
|
|
|
|||
|
|
@ -781,8 +781,7 @@ static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
|
|||
/* Signal pending. */
|
||||
ap_cancel_message(zdev->ap_dev, &ap_msg);
|
||||
out_free:
|
||||
memset(ap_msg.message, 0x0, ap_msg.length);
|
||||
kfree(ap_msg.message);
|
||||
kzfree(ap_msg.message);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,246 +0,0 @@
|
|||
/*
|
||||
* arch/s390/kernel/ebcdic.c
|
||||
* ECBDIC -> ASCII, ASCII -> ECBDIC conversion tables.
|
||||
*
|
||||
* S390 version
|
||||
* Copyright (C) 1998 IBM Corporation
|
||||
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
/*
|
||||
* ASCII -> EBCDIC
|
||||
*/
|
||||
__u8 _ascebc[256] =
|
||||
{
|
||||
/*00 NL SH SX EX ET NQ AK BL */
|
||||
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
|
||||
/*08 BS HT LF VT FF CR SO SI */
|
||||
0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
/*10 DL D1 D2 D3 D4 NK SN EB */
|
||||
0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
|
||||
/*18 CN EM SB EC FS GS RS US */
|
||||
0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
/*20 SP ! " # $ % & ' */
|
||||
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
|
||||
/*28 ( ) * + , - . / */
|
||||
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
|
||||
/*30 0 1 2 3 4 5 6 7 */
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
|
||||
/*38 8 9 : ; < = > ? */
|
||||
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
|
||||
/*40 @ A B C D E F G */
|
||||
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
|
||||
/*48 H I J K L M N O */
|
||||
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
|
||||
/*50 P Q R S T U V W */
|
||||
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
|
||||
/*58 X Y Z [ \ ] ^ _ */
|
||||
0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
|
||||
/*60 ` a b c d e f g */
|
||||
0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
/*68 h i j k l m n o */
|
||||
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
|
||||
/*70 p q r s t u v w */
|
||||
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
|
||||
/*78 x y z { | } ~ DL */
|
||||
0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
|
||||
};
|
||||
|
||||
/*
|
||||
* EBCDIC -> ASCII
|
||||
*/
|
||||
__u8 _ebcasc[256] =
|
||||
{
|
||||
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
||||
-ENP ->LF */
|
||||
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
||||
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
||||
-IUS */
|
||||
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
||||
-INP */
|
||||
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
||||
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
||||
-SW */
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
||||
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
||||
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
||||
/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
||||
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
||||
/* 0x40 SP RSP ∽ ---- */
|
||||
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
||||
/* 0x48 . < ( + | */
|
||||
0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
||||
/* 0x50 & ---- */
|
||||
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
||||
/* 0x58 ≡ ! $ * ) ; */
|
||||
0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
||||
/* 0x60 - / ---- <20> ---- ---- ---- */
|
||||
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
||||
/* 0x68 ---- , % _ > ? */
|
||||
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
||||
/* 0x70 ---- ---- ---- ---- ---- ---- ---- */
|
||||
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
/* 0x78 * ` : # @ ' = " */
|
||||
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
||||
/* 0x80 * a b c d e f g */
|
||||
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
/* 0x88 h i ---- ---- ---- */
|
||||
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
||||
/* 0x90 <20> j k l m n o p */
|
||||
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
/* 0x98 q r ---- ---- */
|
||||
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
||||
/* 0xA0 ~ s t u v w x */
|
||||
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
/* 0xA8 y z ---- ---- ---- ---- */
|
||||
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
||||
/* 0xB0 ^ ---- 〒 ---- */
|
||||
0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
||||
/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
||||
0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
||||
/* 0xC0 { A B C D E F G */
|
||||
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
/* 0xC8 H I ---- ‡ ---- */
|
||||
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
||||
/* 0xD0 } J K L M N O P */
|
||||
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||||
/* 0xD8 Q R ---- ◯ */
|
||||
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
||||
/* 0xE0 \ S T U V W X */
|
||||
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
/* 0xE8 Y Z ---- <20> ---- ---- ---- */
|
||||
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
||||
/* 0xF0 0 1 2 3 4 5 6 7 */
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
/* 0xF8 8 9 ---- ---- ⌒ ---- ---- ---- */
|
||||
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||
};
|
||||
|
||||
/*
|
||||
* EBCDIC (capitals) -> ASCII (small case)
|
||||
*/
|
||||
__u8 _ebcasc_reduce_case[256] =
|
||||
{
|
||||
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
|
||||
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
|
||||
/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
||||
-ENP ->LF */
|
||||
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
||||
|
||||
/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
||||
-IUS */
|
||||
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
|
||||
/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
||||
-INP */
|
||||
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
||||
|
||||
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
||||
-SW */
|
||||
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
||||
|
||||
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
||||
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
||||
|
||||
/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
||||
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
||||
|
||||
/* 0x40 SP RSP ∽ ---- */
|
||||
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
||||
|
||||
/* 0x48 . < ( + | */
|
||||
0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
||||
|
||||
/* 0x50 & ---- */
|
||||
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
||||
|
||||
/* 0x58 ≡ ! $ * ) ; */
|
||||
0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
||||
|
||||
/* 0x60 - / ---- <20> ---- ---- ---- */
|
||||
0x2D, 0x2F, 0x07, 0x84, 0x07, 0x07, 0x07, 0x8F,
|
||||
|
||||
/* 0x68 ---- , % _ > ? */
|
||||
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
||||
|
||||
/* 0x70 ---- ---- ---- ---- ---- ---- ---- */
|
||||
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
|
||||
/* 0x78 * ` : # @ ' = " */
|
||||
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
||||
|
||||
/* 0x80 * a b c d e f g */
|
||||
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
|
||||
/* 0x88 h i ---- ---- ---- */
|
||||
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
||||
|
||||
/* 0x90 <20> j k l m n o p */
|
||||
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
|
||||
/* 0x98 q r ---- ---- */
|
||||
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
||||
|
||||
/* 0xA0 ~ s t u v w x */
|
||||
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
|
||||
/* 0xA8 y z ---- ---- ---- ---- */
|
||||
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
||||
|
||||
/* 0xB0 ^ ---- 〒 ---- */
|
||||
0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
||||
|
||||
/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
||||
0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
||||
|
||||
/* 0xC0 { A B C D E F G */
|
||||
0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
|
||||
/* 0xC8 H I ---- ‡ ---- */
|
||||
0x68, 0x69, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
||||
|
||||
/* 0xD0 } J K L M N O P */
|
||||
0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
|
||||
/* 0xD8 Q R ---- ◯ */
|
||||
0x71, 0x72, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
||||
|
||||
/* 0xE0 \ S T U V W X */
|
||||
0x5C, 0xF6, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
|
||||
/* 0xE8 Y Z ---- <20> ---- ---- ---- */
|
||||
0x79, 0x7A, 0xFD, 0x07, 0x94, 0x07, 0x07, 0x07,
|
||||
|
||||
/* 0xF0 0 1 2 3 4 5 6 7 */
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
|
||||
/* 0xF8 8 9 ---- ---- ⌒ ---- ---- ---- */
|
||||
0x38, 0x39, 0x07, 0x07, 0x81, 0x07, 0x07, 0x07
|
||||
};
|
||||
|
|
@ -2680,40 +2680,21 @@ static int qeth_handle_send_error(struct qeth_card *card,
|
|||
struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err)
|
||||
{
|
||||
int sbalf15 = buffer->buffer->element[15].flags & 0xff;
|
||||
int cc = qdio_err & 3;
|
||||
|
||||
QETH_DBF_TEXT(TRACE, 6, "hdsnderr");
|
||||
qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr");
|
||||
switch (cc) {
|
||||
case 0:
|
||||
if (qdio_err) {
|
||||
QETH_DBF_TEXT(TRACE, 1, "lnkfail");
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%04x %02x",
|
||||
(u16)qdio_err, (u8)sbalf15);
|
||||
return QETH_SEND_ERROR_LINK_FAILURE;
|
||||
}
|
||||
|
||||
if (!qdio_err)
|
||||
return QETH_SEND_ERROR_NONE;
|
||||
case 2:
|
||||
if (qdio_err & QDIO_ERROR_SIGA_BUSY) {
|
||||
QETH_DBF_TEXT(TRACE, 1, "SIGAcc2B");
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
|
||||
return QETH_SEND_ERROR_KICK_IT;
|
||||
}
|
||||
if ((sbalf15 >= 15) && (sbalf15 <= 31))
|
||||
return QETH_SEND_ERROR_RETRY;
|
||||
return QETH_SEND_ERROR_LINK_FAILURE;
|
||||
/* look at qdio_error and sbalf 15 */
|
||||
case 1:
|
||||
QETH_DBF_TEXT(TRACE, 1, "SIGAcc1");
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
|
||||
return QETH_SEND_ERROR_LINK_FAILURE;
|
||||
case 3:
|
||||
default:
|
||||
QETH_DBF_TEXT(TRACE, 1, "SIGAcc3");
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
|
||||
return QETH_SEND_ERROR_KICK_IT;
|
||||
}
|
||||
|
||||
if ((sbalf15 >= 15) && (sbalf15 <= 31))
|
||||
return QETH_SEND_ERROR_RETRY;
|
||||
|
||||
QETH_DBF_TEXT(TRACE, 1, "lnkfail");
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%s", CARD_BUS_ID(card));
|
||||
QETH_DBF_TEXT_(TRACE, 1, "%04x %02x",
|
||||
(u16)qdio_err, (u8)sbalf15);
|
||||
return QETH_SEND_ERROR_LINK_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2849,10 +2830,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index,
|
|||
qeth_get_micros() -
|
||||
queue->card->perf_stats.outbound_do_qdio_start_time;
|
||||
if (rc) {
|
||||
queue->card->stats.tx_errors += count;
|
||||
/* ignore temporary SIGA errors without busy condition */
|
||||
if (rc == QDIO_ERROR_SIGA_TARGET)
|
||||
return;
|
||||
QETH_DBF_TEXT(TRACE, 2, "flushbuf");
|
||||
QETH_DBF_TEXT_(TRACE, 2, " err%d", rc);
|
||||
QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_DDEV_ID(queue->card));
|
||||
queue->card->stats.tx_errors += count;
|
||||
|
||||
/* this must not happen under normal circumstances. if it
|
||||
* happens something is really wrong -> recover */
|
||||
qeth_schedule_recovery(queue->card);
|
||||
|
|
@ -2927,13 +2912,7 @@ void qeth_qdio_output_handler(struct ccw_device *ccwdev,
|
|||
}
|
||||
for (i = first_element; i < (first_element + count); ++i) {
|
||||
buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
|
||||
/*we only handle the KICK_IT error by doing a recovery */
|
||||
if (qeth_handle_send_error(card, buffer, qdio_error)
|
||||
== QETH_SEND_ERROR_KICK_IT){
|
||||
netif_stop_queue(card->dev);
|
||||
qeth_schedule_recovery(card);
|
||||
return;
|
||||
}
|
||||
qeth_handle_send_error(card, buffer, qdio_error);
|
||||
qeth_clear_output_buffer(queue, buffer);
|
||||
}
|
||||
atomic_sub(count, &queue->used_buffers);
|
||||
|
|
|
|||
|
|
@ -1,538 +0,0 @@
|
|||
/*
|
||||
* drivers/s390/s390mach.c
|
||||
* S/390 machine check handler
|
||||
*
|
||||
* Copyright IBM Corp. 2000,2008
|
||||
* Author(s): Ingo Adlung (adlung@de.ibm.com)
|
||||
* Martin Schwidefsky (schwidefsky@de.ibm.com)
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/etr.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/cio.h>
|
||||
#include <asm/cpu.h>
|
||||
#include "s390mach.h"
|
||||
|
||||
static struct semaphore m_sem;
|
||||
|
||||
static NORET_TYPE void
|
||||
s390_handle_damage(char *msg)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
smp_send_stop();
|
||||
#endif
|
||||
disabled_wait((unsigned long) __builtin_return_address(0));
|
||||
for(;;);
|
||||
}
|
||||
|
||||
static crw_handler_t crw_handlers[NR_RSCS];
|
||||
|
||||
/**
|
||||
* s390_register_crw_handler() - register a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
* @handler: handler to be registered
|
||||
*
|
||||
* Returns %0 on success and a negative error value otherwise.
|
||||
*/
|
||||
int s390_register_crw_handler(int rsc, crw_handler_t handler)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return -EINVAL;
|
||||
if (!cmpxchg(&crw_handlers[rsc], NULL, handler))
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* s390_unregister_crw_handler() - unregister a channel report word handler
|
||||
* @rsc: reporting source code to handle
|
||||
*/
|
||||
void s390_unregister_crw_handler(int rsc)
|
||||
{
|
||||
if ((rsc < 0) || (rsc >= NR_RSCS))
|
||||
return;
|
||||
xchg(&crw_handlers[rsc], NULL);
|
||||
synchronize_sched();
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve CRWs and call function to handle event.
|
||||
*/
|
||||
static int s390_collect_crw_info(void *param)
|
||||
{
|
||||
struct crw crw[2];
|
||||
int ccode;
|
||||
struct semaphore *sem;
|
||||
unsigned int chain;
|
||||
int ignore;
|
||||
|
||||
sem = (struct semaphore *)param;
|
||||
repeat:
|
||||
ignore = down_interruptible(sem);
|
||||
chain = 0;
|
||||
while (1) {
|
||||
if (unlikely(chain > 1)) {
|
||||
struct crw tmp_crw;
|
||||
|
||||
printk(KERN_WARNING"%s: Code does not support more "
|
||||
"than two chained crws; please report to "
|
||||
"[email protected]!\n", __func__);
|
||||
ccode = stcrw(&tmp_crw);
|
||||
printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
__func__, tmp_crw.slct, tmp_crw.oflw,
|
||||
tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc,
|
||||
tmp_crw.erc, tmp_crw.rsid);
|
||||
printk(KERN_WARNING"%s: This was crw number %x in the "
|
||||
"chain\n", __func__, chain);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
chain = tmp_crw.chn ? chain + 1 : 0;
|
||||
continue;
|
||||
}
|
||||
ccode = stcrw(&crw[chain]);
|
||||
if (ccode != 0)
|
||||
break;
|
||||
printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
|
||||
"chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
|
||||
crw[chain].slct, crw[chain].oflw, crw[chain].chn,
|
||||
crw[chain].rsc, crw[chain].anc, crw[chain].erc,
|
||||
crw[chain].rsid);
|
||||
/* Check for overflows. */
|
||||
if (crw[chain].oflw) {
|
||||
int i;
|
||||
|
||||
pr_debug("%s: crw overflow detected!\n", __func__);
|
||||
for (i = 0; i < NR_RSCS; i++) {
|
||||
if (crw_handlers[i])
|
||||
crw_handlers[i](NULL, NULL, 1);
|
||||
}
|
||||
chain = 0;
|
||||
continue;
|
||||
}
|
||||
if (crw[0].chn && !chain) {
|
||||
chain++;
|
||||
continue;
|
||||
}
|
||||
if (crw_handlers[crw[chain].rsc])
|
||||
crw_handlers[crw[chain].rsc](&crw[0],
|
||||
chain ? &crw[1] : NULL,
|
||||
0);
|
||||
/* chain is always 0 or 1 here. */
|
||||
chain = crw[chain].chn ? chain + 1 : 0;
|
||||
}
|
||||
goto repeat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mcck_struct {
|
||||
int kill_task;
|
||||
int channel_report;
|
||||
int warning;
|
||||
unsigned long long mcck_code;
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
|
||||
|
||||
/*
|
||||
* Main machine check handler function. Will be called with interrupts enabled
|
||||
* or disabled and machine checks enabled or disabled.
|
||||
*/
|
||||
void
|
||||
s390_handle_mcck(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct mcck_struct mcck;
|
||||
|
||||
/*
|
||||
* Disable machine checks and get the current state of accumulated
|
||||
* machine checks. Afterwards delete the old state and enable machine
|
||||
* checks again.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
local_mcck_disable();
|
||||
mcck = __get_cpu_var(cpu_mcck);
|
||||
memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
|
||||
clear_thread_flag(TIF_MCCK_PENDING);
|
||||
local_mcck_enable();
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (mcck.channel_report)
|
||||
up(&m_sem);
|
||||
|
||||
#ifdef CONFIG_MACHCHK_WARNING
|
||||
/*
|
||||
* The warning may remain for a prolonged period on the bare iron.
|
||||
* (actually till the machine is powered off, or until the problem is gone)
|
||||
* So we just stop listening for the WARNING MCH and prevent continuously
|
||||
* being interrupted. One caveat is however, that we must do this per
|
||||
* processor and cannot use the smp version of ctl_clear_bit().
|
||||
* On VM we only get one interrupt per virtally presented machinecheck.
|
||||
* Though one suffices, we may get one interrupt per (virtual) processor.
|
||||
*/
|
||||
if (mcck.warning) { /* WARNING pending ? */
|
||||
static int mchchk_wng_posted = 0;
|
||||
/*
|
||||
* Use single machine clear, as we cannot handle smp right now
|
||||
*/
|
||||
__ctl_clear_bit(14, 24); /* Disable WARNING MCH */
|
||||
if (xchg(&mchchk_wng_posted, 1) == 0)
|
||||
kill_cad_pid(SIGPWR, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mcck.kill_task) {
|
||||
local_irq_enable();
|
||||
printk(KERN_EMERG "mcck: Terminating task because of machine "
|
||||
"malfunction (code 0x%016llx).\n", mcck.mcck_code);
|
||||
printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
|
||||
current->comm, current->pid);
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s390_handle_mcck);
|
||||
|
||||
/*
|
||||
* returns 0 if all registers could be validated
|
||||
* returns 1 otherwise
|
||||
*/
|
||||
static int
|
||||
s390_revalidate_registers(struct mci *mci)
|
||||
{
|
||||
int kill_task;
|
||||
u64 tmpclock;
|
||||
u64 zero;
|
||||
void *fpt_save_area, *fpt_creg_save_area;
|
||||
|
||||
kill_task = 0;
|
||||
zero = 0;
|
||||
/* General purpose registers */
|
||||
if (!mci->gr)
|
||||
/*
|
||||
* General purpose registers couldn't be restored and have
|
||||
* unknown contents. Process needs to be terminated.
|
||||
*/
|
||||
kill_task = 1;
|
||||
|
||||
/* Revalidate floating point registers */
|
||||
if (!mci->fp)
|
||||
/*
|
||||
* Floating point registers can't be restored and
|
||||
* therefore the process needs to be terminated.
|
||||
*/
|
||||
kill_task = 1;
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
asm volatile(
|
||||
" ld 0,0(%0)\n"
|
||||
" ld 2,8(%0)\n"
|
||||
" ld 4,16(%0)\n"
|
||||
" ld 6,24(%0)"
|
||||
: : "a" (&S390_lowcore.floating_pt_save_area));
|
||||
#endif
|
||||
|
||||
if (MACHINE_HAS_IEEE) {
|
||||
#ifdef CONFIG_64BIT
|
||||
fpt_save_area = &S390_lowcore.floating_pt_save_area;
|
||||
fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
|
||||
#else
|
||||
fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
|
||||
fpt_creg_save_area = fpt_save_area+128;
|
||||
#endif
|
||||
/* Floating point control register */
|
||||
if (!mci->fc) {
|
||||
/*
|
||||
* Floating point control register can't be restored.
|
||||
* Task will be terminated.
|
||||
*/
|
||||
asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
|
||||
kill_task = 1;
|
||||
|
||||
} else
|
||||
asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
|
||||
|
||||
asm volatile(
|
||||
" ld 0,0(%0)\n"
|
||||
" ld 1,8(%0)\n"
|
||||
" ld 2,16(%0)\n"
|
||||
" ld 3,24(%0)\n"
|
||||
" ld 4,32(%0)\n"
|
||||
" ld 5,40(%0)\n"
|
||||
" ld 6,48(%0)\n"
|
||||
" ld 7,56(%0)\n"
|
||||
" ld 8,64(%0)\n"
|
||||
" ld 9,72(%0)\n"
|
||||
" ld 10,80(%0)\n"
|
||||
" ld 11,88(%0)\n"
|
||||
" ld 12,96(%0)\n"
|
||||
" ld 13,104(%0)\n"
|
||||
" ld 14,112(%0)\n"
|
||||
" ld 15,120(%0)\n"
|
||||
: : "a" (fpt_save_area));
|
||||
}
|
||||
|
||||
/* Revalidate access registers */
|
||||
asm volatile(
|
||||
" lam 0,15,0(%0)"
|
||||
: : "a" (&S390_lowcore.access_regs_save_area));
|
||||
if (!mci->ar)
|
||||
/*
|
||||
* Access registers have unknown contents.
|
||||
* Terminating task.
|
||||
*/
|
||||
kill_task = 1;
|
||||
|
||||
/* Revalidate control registers */
|
||||
if (!mci->cr)
|
||||
/*
|
||||
* Control registers have unknown contents.
|
||||
* Can't recover and therefore stopping machine.
|
||||
*/
|
||||
s390_handle_damage("invalid control registers.");
|
||||
else
|
||||
#ifdef CONFIG_64BIT
|
||||
asm volatile(
|
||||
" lctlg 0,15,0(%0)"
|
||||
: : "a" (&S390_lowcore.cregs_save_area));
|
||||
#else
|
||||
asm volatile(
|
||||
" lctl 0,15,0(%0)"
|
||||
: : "a" (&S390_lowcore.cregs_save_area));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We don't even try to revalidate the TOD register, since we simply
|
||||
* can't write something sensible into that register.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
/*
|
||||
* See if we can revalidate the TOD programmable register with its
|
||||
* old contents (should be zero) otherwise set it to zero.
|
||||
*/
|
||||
if (!mci->pr)
|
||||
asm volatile(
|
||||
" sr 0,0\n"
|
||||
" sckpf"
|
||||
: : : "0", "cc");
|
||||
else
|
||||
asm volatile(
|
||||
" l 0,0(%0)\n"
|
||||
" sckpf"
|
||||
: : "a" (&S390_lowcore.tod_progreg_save_area)
|
||||
: "0", "cc");
|
||||
#endif
|
||||
|
||||
/* Revalidate clock comparator register */
|
||||
asm volatile(
|
||||
" stck 0(%1)\n"
|
||||
" sckc 0(%1)"
|
||||
: "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
|
||||
|
||||
/* Check if old PSW is valid */
|
||||
if (!mci->wp)
|
||||
/*
|
||||
* Can't tell if we come from user or kernel mode
|
||||
* -> stopping machine.
|
||||
*/
|
||||
s390_handle_damage("old psw invalid.");
|
||||
|
||||
if (!mci->ms || !mci->pm || !mci->ia)
|
||||
kill_task = 1;
|
||||
|
||||
return kill_task;
|
||||
}
|
||||
|
||||
#define MAX_IPD_COUNT 29
|
||||
#define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */
|
||||
|
||||
/*
|
||||
* machine check handler.
|
||||
*/
|
||||
void
|
||||
s390_do_machine_check(struct pt_regs *regs)
|
||||
{
|
||||
static DEFINE_SPINLOCK(ipd_lock);
|
||||
static unsigned long long last_ipd;
|
||||
static int ipd_count;
|
||||
unsigned long long tmp;
|
||||
struct mci *mci;
|
||||
struct mcck_struct *mcck;
|
||||
int umode;
|
||||
|
||||
lockdep_off();
|
||||
|
||||
s390_idle_check();
|
||||
|
||||
mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
|
||||
mcck = &__get_cpu_var(cpu_mcck);
|
||||
umode = user_mode(regs);
|
||||
|
||||
if (mci->sd)
|
||||
/* System damage -> stopping machine */
|
||||
s390_handle_damage("received system damage machine check.");
|
||||
|
||||
if (mci->pd) {
|
||||
if (mci->b) {
|
||||
/* Processing backup -> verify if we can survive this */
|
||||
u64 z_mcic, o_mcic, t_mcic;
|
||||
#ifdef CONFIG_64BIT
|
||||
z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29);
|
||||
o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
|
||||
1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
|
||||
1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 |
|
||||
1ULL<<16);
|
||||
#else
|
||||
z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 |
|
||||
1ULL<<29);
|
||||
o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
|
||||
1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
|
||||
1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16);
|
||||
#endif
|
||||
t_mcic = *(u64 *)mci;
|
||||
|
||||
if (((t_mcic & z_mcic) != 0) ||
|
||||
((t_mcic & o_mcic) != o_mcic)) {
|
||||
s390_handle_damage("processing backup machine "
|
||||
"check with damage.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Nullifying exigent condition, therefore we might
|
||||
* retry this instruction.
|
||||
*/
|
||||
|
||||
spin_lock(&ipd_lock);
|
||||
|
||||
tmp = get_clock();
|
||||
|
||||
if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME)
|
||||
ipd_count++;
|
||||
else
|
||||
ipd_count = 1;
|
||||
|
||||
last_ipd = tmp;
|
||||
|
||||
if (ipd_count == MAX_IPD_COUNT)
|
||||
s390_handle_damage("too many ipd retries.");
|
||||
|
||||
spin_unlock(&ipd_lock);
|
||||
}
|
||||
else {
|
||||
/* Processing damage -> stopping machine */
|
||||
s390_handle_damage("received instruction processing "
|
||||
"damage machine check.");
|
||||
}
|
||||
}
|
||||
if (s390_revalidate_registers(mci)) {
|
||||
if (umode) {
|
||||
/*
|
||||
* Couldn't restore all register contents while in
|
||||
* user mode -> mark task for termination.
|
||||
*/
|
||||
mcck->kill_task = 1;
|
||||
mcck->mcck_code = *(unsigned long long *) mci;
|
||||
set_thread_flag(TIF_MCCK_PENDING);
|
||||
}
|
||||
else
|
||||
/*
|
||||
* Couldn't restore all register contents while in
|
||||
* kernel mode -> stopping machine.
|
||||
*/
|
||||
s390_handle_damage("unable to revalidate registers.");
|
||||
}
|
||||
|
||||
if (mci->cd) {
|
||||
/* Timing facility damage */
|
||||
s390_handle_damage("TOD clock damaged");
|
||||
}
|
||||
|
||||
if (mci->ed && mci->ec) {
|
||||
/* External damage */
|
||||
if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
|
||||
etr_sync_check();
|
||||
if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
|
||||
etr_switch_to_local();
|
||||
if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC))
|
||||
stp_sync_check();
|
||||
if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND))
|
||||
stp_island_check();
|
||||
}
|
||||
|
||||
if (mci->se)
|
||||
/* Storage error uncorrected */
|
||||
s390_handle_damage("received storage error uncorrected "
|
||||
"machine check.");
|
||||
|
||||
if (mci->ke)
|
||||
/* Storage key-error uncorrected */
|
||||
s390_handle_damage("received storage key-error uncorrected "
|
||||
"machine check.");
|
||||
|
||||
if (mci->ds && mci->fa)
|
||||
/* Storage degradation */
|
||||
s390_handle_damage("received storage degradation machine "
|
||||
"check.");
|
||||
|
||||
if (mci->cp) {
|
||||
/* Channel report word pending */
|
||||
mcck->channel_report = 1;
|
||||
set_thread_flag(TIF_MCCK_PENDING);
|
||||
}
|
||||
|
||||
if (mci->w) {
|
||||
/* Warning pending */
|
||||
mcck->warning = 1;
|
||||
set_thread_flag(TIF_MCCK_PENDING);
|
||||
}
|
||||
lockdep_on();
|
||||
}
|
||||
|
||||
/*
|
||||
* s390_init_machine_check
|
||||
*
|
||||
* initialize machine check handling
|
||||
*/
|
||||
static int
|
||||
machine_check_init(void)
|
||||
{
|
||||
init_MUTEX_LOCKED(&m_sem);
|
||||
ctl_set_bit(14, 25); /* enable external damage MCH */
|
||||
ctl_set_bit(14, 27); /* enable system recovery MCH */
|
||||
#ifdef CONFIG_MACHCHK_WARNING
|
||||
ctl_set_bit(14, 24); /* enable warning MCH */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the machine check handler really early to be able to
|
||||
* catch all machine checks that happen during boot
|
||||
*/
|
||||
arch_initcall(machine_check_init);
|
||||
|
||||
/*
|
||||
* Machine checks for the channel subsystem must be enabled
|
||||
* after the channel subsystem is initialized
|
||||
*/
|
||||
static int __init
|
||||
machine_check_crw_init (void)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
ctl_set_bit(14, 28); /* enable channel report MCH */
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_initcall (machine_check_crw_init);
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* drivers/s390/s390mach.h
|
||||
* S/390 data definitions for machine check processing
|
||||
*
|
||||
* S390 version
|
||||
* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
||||
* Author(s): Ingo Adlung (adlung@de.ibm.com)
|
||||
*/
|
||||
|
||||
#ifndef __s390mach_h
|
||||
#define __s390mach_h
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct mci {
|
||||
__u32 sd : 1; /* 00 system damage */
|
||||
__u32 pd : 1; /* 01 instruction-processing damage */
|
||||
__u32 sr : 1; /* 02 system recovery */
|
||||
__u32 to_be_defined_1 : 1; /* 03 */
|
||||
__u32 cd : 1; /* 04 timing-facility damage */
|
||||
__u32 ed : 1; /* 05 external damage */
|
||||
__u32 to_be_defined_2 : 1; /* 06 */
|
||||
__u32 dg : 1; /* 07 degradation */
|
||||
__u32 w : 1; /* 08 warning pending */
|
||||
__u32 cp : 1; /* 09 channel-report pending */
|
||||
__u32 sp : 1; /* 10 service-processor damage */
|
||||
__u32 ck : 1; /* 11 channel-subsystem damage */
|
||||
__u32 to_be_defined_3 : 2; /* 12-13 */
|
||||
__u32 b : 1; /* 14 backed up */
|
||||
__u32 to_be_defined_4 : 1; /* 15 */
|
||||
__u32 se : 1; /* 16 storage error uncorrected */
|
||||
__u32 sc : 1; /* 17 storage error corrected */
|
||||
__u32 ke : 1; /* 18 storage-key error uncorrected */
|
||||
__u32 ds : 1; /* 19 storage degradation */
|
||||
__u32 wp : 1; /* 20 psw mwp validity */
|
||||
__u32 ms : 1; /* 21 psw mask and key validity */
|
||||
__u32 pm : 1; /* 22 psw program mask and cc validity */
|
||||
__u32 ia : 1; /* 23 psw instruction address validity */
|
||||
__u32 fa : 1; /* 24 failing storage address validity */
|
||||
__u32 to_be_defined_5 : 1; /* 25 */
|
||||
__u32 ec : 1; /* 26 external damage code validity */
|
||||
__u32 fp : 1; /* 27 floating point register validity */
|
||||
__u32 gr : 1; /* 28 general register validity */
|
||||
__u32 cr : 1; /* 29 control register validity */
|
||||
__u32 to_be_defined_6 : 1; /* 30 */
|
||||
__u32 st : 1; /* 31 storage logical validity */
|
||||
__u32 ie : 1; /* 32 indirect storage error */
|
||||
__u32 ar : 1; /* 33 access register validity */
|
||||
__u32 da : 1; /* 34 delayed access exception */
|
||||
__u32 to_be_defined_7 : 7; /* 35-41 */
|
||||
__u32 pr : 1; /* 42 tod programmable register validity */
|
||||
__u32 fc : 1; /* 43 fp control register validity */
|
||||
__u32 ap : 1; /* 44 ancillary report */
|
||||
__u32 to_be_defined_8 : 1; /* 45 */
|
||||
__u32 ct : 1; /* 46 cpu timer validity */
|
||||
__u32 cc : 1; /* 47 clock comparator validity */
|
||||
__u32 to_be_defined_9 : 16; /* 47-63 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Channel Report Word
|
||||
*/
|
||||
struct crw {
|
||||
__u32 res1 : 1; /* reserved zero */
|
||||
__u32 slct : 1; /* solicited */
|
||||
__u32 oflw : 1; /* overflow */
|
||||
__u32 chn : 1; /* chained */
|
||||
__u32 rsc : 4; /* reporting source code */
|
||||
__u32 anc : 1; /* ancillary report */
|
||||
__u32 res2 : 1; /* reserved zero */
|
||||
__u32 erc : 6; /* error-recovery code */
|
||||
__u32 rsid : 16; /* reporting-source ID */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef void (*crw_handler_t)(struct crw *, struct crw *, int);
|
||||
|
||||
extern int s390_register_crw_handler(int rsc, crw_handler_t handler);
|
||||
extern void s390_unregister_crw_handler(int rsc);
|
||||
|
||||
#define NR_RSCS 16
|
||||
|
||||
#define CRW_RSC_MONITOR 0x2 /* monitoring facility */
|
||||
#define CRW_RSC_SCH 0x3 /* subchannel */
|
||||
#define CRW_RSC_CPATH 0x4 /* channel path */
|
||||
#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */
|
||||
#define CRW_RSC_CSS 0xB /* channel subsystem */
|
||||
|
||||
#define CRW_ERC_EVENT 0x00 /* event information pending */
|
||||
#define CRW_ERC_AVAIL 0x01 /* available */
|
||||
#define CRW_ERC_INIT 0x02 /* initialized */
|
||||
#define CRW_ERC_TERROR 0x03 /* temporary error */
|
||||
#define CRW_ERC_IPARM 0x04 /* installed parm initialized */
|
||||
#define CRW_ERC_TERM 0x05 /* terminal */
|
||||
#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */
|
||||
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
|
||||
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
|
||||
|
||||
static inline int stcrw(struct crw *pcrw )
|
||||
{
|
||||
int ccode;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"stcrw 0(%2)\n\t"
|
||||
"ipm %0\n\t"
|
||||
"srl %0,28\n\t"
|
||||
: "=d" (ccode), "=m" (*pcrw)
|
||||
: "a" (pcrw)
|
||||
: "cc" );
|
||||
return ccode;
|
||||
}
|
||||
|
||||
#define ED_ETR_SYNC 12 /* External damage ETR sync check */
|
||||
#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
|
||||
|
||||
#define ED_STP_SYNC 7 /* External damage STP sync check */
|
||||
#define ED_STP_ISLAND 6 /* External damage STP island check */
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
void s390_handle_mcck(void);
|
||||
void s390_do_machine_check(struct pt_regs *regs);
|
||||
#endif /* __s390mach */
|
||||
|
|
@ -1,469 +0,0 @@
|
|||
/*
|
||||
* drivers/s390/sysinfo.c
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2008
|
||||
* Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
|
||||
* Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/cpcmd.h>
|
||||
|
||||
/* Sigh, math-emu. Don't ask. */
|
||||
#include <asm/sfp-util.h>
|
||||
#include <math-emu/soft-fp.h>
|
||||
#include <math-emu/single.h>
|
||||
|
||||
static inline int stsi_0(void)
|
||||
{
|
||||
int rc = stsi (NULL, 0, 0, 0);
|
||||
return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
|
||||
}
|
||||
|
||||
static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
|
||||
{
|
||||
if (stsi(info, 1, 1, 1) == -ENOSYS)
|
||||
return len;
|
||||
|
||||
EBCASC(info->manufacturer, sizeof(info->manufacturer));
|
||||
EBCASC(info->type, sizeof(info->type));
|
||||
EBCASC(info->model, sizeof(info->model));
|
||||
EBCASC(info->sequence, sizeof(info->sequence));
|
||||
EBCASC(info->plant, sizeof(info->plant));
|
||||
EBCASC(info->model_capacity, sizeof(info->model_capacity));
|
||||
EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap));
|
||||
EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
|
||||
len += sprintf(page + len, "Manufacturer: %-16.16s\n",
|
||||
info->manufacturer);
|
||||
len += sprintf(page + len, "Type: %-4.4s\n",
|
||||
info->type);
|
||||
if (info->model[0] != '\0')
|
||||
/*
|
||||
* Sigh: the model field has been renamed with System z9
|
||||
* to model_capacity and a new model field has been added
|
||||
* after the plant field. To avoid confusing older programs
|
||||
* the "Model:" prints "model_capacity model" or just
|
||||
* "model_capacity" if the model string is empty .
|
||||
*/
|
||||
len += sprintf(page + len,
|
||||
"Model: %-16.16s %-16.16s\n",
|
||||
info->model_capacity, info->model);
|
||||
else
|
||||
len += sprintf(page + len, "Model: %-16.16s\n",
|
||||
info->model_capacity);
|
||||
len += sprintf(page + len, "Sequence Code: %-16.16s\n",
|
||||
info->sequence);
|
||||
len += sprintf(page + len, "Plant: %-4.4s\n",
|
||||
info->plant);
|
||||
len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n",
|
||||
info->model_capacity, *(u32 *) info->model_cap_rating);
|
||||
if (info->model_perm_cap[0] != '\0')
|
||||
len += sprintf(page + len,
|
||||
"Model Perm. Capacity: %-16.16s %08u\n",
|
||||
info->model_perm_cap,
|
||||
*(u32 *) info->model_perm_cap_rating);
|
||||
if (info->model_temp_cap[0] != '\0')
|
||||
len += sprintf(page + len,
|
||||
"Model Temp. Capacity: %-16.16s %08u\n",
|
||||
info->model_temp_cap,
|
||||
*(u32 *) info->model_temp_cap_rating);
|
||||
return len;
|
||||
}
|
||||
|
||||
#if 0 /* Currently unused */
|
||||
static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len)
|
||||
{
|
||||
if (stsi(info, 1, 2, 1) == -ENOSYS)
|
||||
return len;
|
||||
|
||||
len += sprintf(page + len, "\n");
|
||||
EBCASC(info->sequence, sizeof(info->sequence));
|
||||
EBCASC(info->plant, sizeof(info->plant));
|
||||
len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n",
|
||||
info->sequence);
|
||||
len += sprintf(page + len, "Plant of CPU: %-16.16s\n",
|
||||
info->plant);
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
|
||||
{
|
||||
struct sysinfo_1_2_2_extension *ext;
|
||||
int i;
|
||||
|
||||
if (stsi(info, 1, 2, 2) == -ENOSYS)
|
||||
return len;
|
||||
ext = (struct sysinfo_1_2_2_extension *)
|
||||
((unsigned long) info + info->acc_offset);
|
||||
|
||||
len += sprintf(page + len, "\n");
|
||||
len += sprintf(page + len, "CPUs Total: %d\n",
|
||||
info->cpus_total);
|
||||
len += sprintf(page + len, "CPUs Configured: %d\n",
|
||||
info->cpus_configured);
|
||||
len += sprintf(page + len, "CPUs Standby: %d\n",
|
||||
info->cpus_standby);
|
||||
len += sprintf(page + len, "CPUs Reserved: %d\n",
|
||||
info->cpus_reserved);
|
||||
|
||||
if (info->format == 1) {
|
||||
/*
|
||||
* Sigh 2. According to the specification the alternate
|
||||
* capability field is a 32 bit floating point number
|
||||
* if the higher order 8 bits are not zero. Printing
|
||||
* a floating point number in the kernel is a no-no,
|
||||
* always print the number as 32 bit unsigned integer.
|
||||
* The user-space needs to know about the strange
|
||||
* encoding of the alternate cpu capability.
|
||||
*/
|
||||
len += sprintf(page + len, "Capability: %u %u\n",
|
||||
info->capability, ext->alt_capability);
|
||||
for (i = 2; i <= info->cpus_total; i++)
|
||||
len += sprintf(page + len,
|
||||
"Adjustment %02d-way: %u %u\n",
|
||||
i, info->adjustment[i-2],
|
||||
ext->alt_adjustment[i-2]);
|
||||
|
||||
} else {
|
||||
len += sprintf(page + len, "Capability: %u\n",
|
||||
info->capability);
|
||||
for (i = 2; i <= info->cpus_total; i++)
|
||||
len += sprintf(page + len,
|
||||
"Adjustment %02d-way: %u\n",
|
||||
i, info->adjustment[i-2]);
|
||||
}
|
||||
|
||||
if (info->secondary_capability != 0)
|
||||
len += sprintf(page + len, "Secondary Capability: %d\n",
|
||||
info->secondary_capability);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#if 0 /* Currently unused */
|
||||
static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len)
|
||||
{
|
||||
if (stsi(info, 2, 2, 1) == -ENOSYS)
|
||||
return len;
|
||||
|
||||
len += sprintf(page + len, "\n");
|
||||
EBCASC (info->sequence, sizeof(info->sequence));
|
||||
EBCASC (info->plant, sizeof(info->plant));
|
||||
len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n",
|
||||
info->sequence);
|
||||
len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n",
|
||||
info->plant);
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
|
||||
{
|
||||
if (stsi(info, 2, 2, 2) == -ENOSYS)
|
||||
return len;
|
||||
|
||||
EBCASC (info->name, sizeof(info->name));
|
||||
|
||||
len += sprintf(page + len, "\n");
|
||||
len += sprintf(page + len, "LPAR Number: %d\n",
|
||||
info->lpar_number);
|
||||
|
||||
len += sprintf(page + len, "LPAR Characteristics: ");
|
||||
if (info->characteristics & LPAR_CHAR_DEDICATED)
|
||||
len += sprintf(page + len, "Dedicated ");
|
||||
if (info->characteristics & LPAR_CHAR_SHARED)
|
||||
len += sprintf(page + len, "Shared ");
|
||||
if (info->characteristics & LPAR_CHAR_LIMITED)
|
||||
len += sprintf(page + len, "Limited ");
|
||||
len += sprintf(page + len, "\n");
|
||||
|
||||
len += sprintf(page + len, "LPAR Name: %-8.8s\n",
|
||||
info->name);
|
||||
|
||||
len += sprintf(page + len, "LPAR Adjustment: %d\n",
|
||||
info->caf);
|
||||
|
||||
len += sprintf(page + len, "LPAR CPUs Total: %d\n",
|
||||
info->cpus_total);
|
||||
len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
|
||||
info->cpus_configured);
|
||||
len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
|
||||
info->cpus_standby);
|
||||
len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
|
||||
info->cpus_reserved);
|
||||
len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
|
||||
info->cpus_dedicated);
|
||||
len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
|
||||
info->cpus_shared);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (stsi(info, 3, 2, 2) == -ENOSYS)
|
||||
return len;
|
||||
for (i = 0; i < info->count; i++) {
|
||||
EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
|
||||
EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
|
||||
len += sprintf(page + len, "\n");
|
||||
len += sprintf(page + len, "VM%02d Name: %-8.8s\n",
|
||||
i, info->vm[i].name);
|
||||
len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
|
||||
i, info->vm[i].cpi);
|
||||
|
||||
len += sprintf(page + len, "VM%02d Adjustment: %d\n",
|
||||
i, info->vm[i].caf);
|
||||
|
||||
len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
|
||||
i, info->vm[i].cpus_total);
|
||||
len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
|
||||
i, info->vm[i].cpus_configured);
|
||||
len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
|
||||
i, info->vm[i].cpus_standby);
|
||||
len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
|
||||
i, info->vm[i].cpus_reserved);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int proc_read_sysinfo(char *page, char **start,
|
||||
off_t off, int count,
|
||||
int *eof, void *data)
|
||||
{
|
||||
unsigned long info = get_zeroed_page (GFP_KERNEL);
|
||||
int level, len;
|
||||
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
len = 0;
|
||||
level = stsi_0();
|
||||
if (level >= 1)
|
||||
len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
|
||||
|
||||
if (level >= 1)
|
||||
len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
|
||||
|
||||
if (level >= 2)
|
||||
len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
|
||||
|
||||
if (level >= 3)
|
||||
len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
|
||||
|
||||
free_page (info);
|
||||
return len;
|
||||
}
|
||||
|
||||
static __init int create_proc_sysinfo(void)
|
||||
{
|
||||
create_proc_read_entry("sysinfo", 0444, NULL,
|
||||
proc_read_sysinfo, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(create_proc_sysinfo);
|
||||
|
||||
/*
|
||||
* Service levels interface.
|
||||
*/
|
||||
|
||||
static DECLARE_RWSEM(service_level_sem);
|
||||
static LIST_HEAD(service_level_list);
|
||||
|
||||
int register_service_level(struct service_level *slr)
|
||||
{
|
||||
struct service_level *ptr;
|
||||
|
||||
down_write(&service_level_sem);
|
||||
list_for_each_entry(ptr, &service_level_list, list)
|
||||
if (ptr == slr) {
|
||||
up_write(&service_level_sem);
|
||||
return -EEXIST;
|
||||
}
|
||||
list_add_tail(&slr->list, &service_level_list);
|
||||
up_write(&service_level_sem);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(register_service_level);
|
||||
|
||||
int unregister_service_level(struct service_level *slr)
|
||||
{
|
||||
struct service_level *ptr, *next;
|
||||
int rc = -ENOENT;
|
||||
|
||||
down_write(&service_level_sem);
|
||||
list_for_each_entry_safe(ptr, next, &service_level_list, list) {
|
||||
if (ptr != slr)
|
||||
continue;
|
||||
list_del(&ptr->list);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
up_write(&service_level_sem);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_service_level);
|
||||
|
||||
static void *service_level_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
down_read(&service_level_sem);
|
||||
return seq_list_start(&service_level_list, *pos);
|
||||
}
|
||||
|
||||
static void *service_level_next(struct seq_file *m, void *p, loff_t *pos)
|
||||
{
|
||||
return seq_list_next(p, &service_level_list, pos);
|
||||
}
|
||||
|
||||
static void service_level_stop(struct seq_file *m, void *p)
|
||||
{
|
||||
up_read(&service_level_sem);
|
||||
}
|
||||
|
||||
static int service_level_show(struct seq_file *m, void *p)
|
||||
{
|
||||
struct service_level *slr;
|
||||
|
||||
slr = list_entry(p, struct service_level, list);
|
||||
slr->seq_print(m, slr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations service_level_seq_ops = {
|
||||
.start = service_level_start,
|
||||
.next = service_level_next,
|
||||
.stop = service_level_stop,
|
||||
.show = service_level_show
|
||||
};
|
||||
|
||||
static int service_level_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &service_level_seq_ops);
|
||||
}
|
||||
|
||||
static const struct file_operations service_level_ops = {
|
||||
.open = service_level_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release
|
||||
};
|
||||
|
||||
static void service_level_vm_print(struct seq_file *m,
|
||||
struct service_level *slr)
|
||||
{
|
||||
char *query_buffer, *str;
|
||||
|
||||
query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA);
|
||||
if (!query_buffer)
|
||||
return;
|
||||
cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL);
|
||||
str = strchr(query_buffer, '\n');
|
||||
if (str)
|
||||
*str = 0;
|
||||
seq_printf(m, "VM: %s\n", query_buffer);
|
||||
kfree(query_buffer);
|
||||
}
|
||||
|
||||
static struct service_level service_level_vm = {
|
||||
.seq_print = service_level_vm_print
|
||||
};
|
||||
|
||||
static __init int create_proc_service_level(void)
|
||||
{
|
||||
proc_create("service_levels", 0, NULL, &service_level_ops);
|
||||
if (MACHINE_IS_VM)
|
||||
register_service_level(&service_level_vm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(create_proc_service_level);
|
||||
|
||||
/*
|
||||
* Bogomips calculation based on cpu capability.
|
||||
*/
|
||||
|
||||
int get_cpu_capability(unsigned int *capability)
|
||||
{
|
||||
struct sysinfo_1_2_2 *info;
|
||||
int rc;
|
||||
|
||||
info = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
rc = stsi(info, 1, 2, 2);
|
||||
if (rc == -ENOSYS)
|
||||
goto out;
|
||||
rc = 0;
|
||||
*capability = info->capability;
|
||||
out:
|
||||
free_page((unsigned long) info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPU capability might have changed. Therefore recalculate loops_per_jiffy.
|
||||
*/
|
||||
void s390_adjust_jiffies(void)
|
||||
{
|
||||
struct sysinfo_1_2_2 *info;
|
||||
const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */
|
||||
FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
|
||||
FP_DECL_EX;
|
||||
unsigned int capability;
|
||||
|
||||
info = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (stsi(info, 1, 2, 2) != -ENOSYS) {
|
||||
/*
|
||||
* Major sigh. The cpu capability encoding is "special".
|
||||
* If the first 9 bits of info->capability are 0 then it
|
||||
* is a 32 bit unsigned integer in the range 0 .. 2^23.
|
||||
* If the first 9 bits are != 0 then it is a 32 bit float.
|
||||
* In addition a lower value indicates a proportionally
|
||||
* higher cpu capacity. Bogomips are the other way round.
|
||||
* To get to a halfway suitable number we divide 1e7
|
||||
* by the cpu capability number. Yes, that means a floating
|
||||
* point division .. math-emu here we come :-)
|
||||
*/
|
||||
FP_UNPACK_SP(SA, &fmil);
|
||||
if ((info->capability >> 23) == 0)
|
||||
FP_FROM_INT_S(SB, info->capability, 32, int);
|
||||
else
|
||||
FP_UNPACK_SP(SB, &info->capability);
|
||||
FP_DIV_S(SR, SA, SB);
|
||||
FP_TO_INT_S(capability, SR, 32, 0);
|
||||
} else
|
||||
/*
|
||||
* Really old machine without stsi block for basic
|
||||
* cpu information. Report 42.0 bogomips.
|
||||
*/
|
||||
capability = 42;
|
||||
loops_per_jiffy = capability * (500000/HZ);
|
||||
free_page((unsigned long) info);
|
||||
}
|
||||
|
||||
/*
|
||||
* calibrate the delay loop
|
||||
*/
|
||||
void __cpuinit calibrate_delay(void)
|
||||
{
|
||||
s390_adjust_jiffies();
|
||||
/* Print the good old Bogomips line .. */
|
||||
printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
|
||||
"%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
|
||||
(loops_per_jiffy/(5000/HZ)) % 100);
|
||||
}
|
||||
Loading…
Reference in a new issue