summaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/Kconfig2
-rw-r--r--drivers/s390/block/dasd.c23
-rw-r--r--drivers/s390/block/dasd_devmap.c8
-rw-r--r--drivers/s390/block/dasd_diag.c334
-rw-r--r--drivers/s390/block/dasd_diag.h105
-rw-r--r--drivers/s390/block/dasd_fba.c4
-rw-r--r--drivers/s390/block/dasd_genhd.c10
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/dasd_ioctl.c17
-rw-r--r--drivers/s390/block/dasd_proc.c8
-rw-r--r--drivers/s390/char/raw3270.c16
-rw-r--r--drivers/s390/char/tape.h7
-rw-r--r--drivers/s390/char/tape_core.c299
-rw-r--r--drivers/s390/char/vmcp.c6
-rw-r--r--drivers/s390/char/vmwatchdog.c6
-rw-r--r--drivers/s390/cio/chsc.c10
-rw-r--r--drivers/s390/cio/cio.c7
-rw-r--r--drivers/s390/cio/device_fsm.c6
-rw-r--r--drivers/s390/cio/device_ops.c4
-rw-r--r--drivers/s390/cio/device_status.c5
-rw-r--r--drivers/s390/cio/ioasm.h26
-rw-r--r--drivers/s390/cio/qdio.c24
-rw-r--r--drivers/s390/crypto/z90common.h3
-rw-r--r--drivers/s390/crypto/z90crypt.h9
-rw-r--r--drivers/s390/crypto/z90hardware.c127
-rw-r--r--drivers/s390/crypto/z90main.c246
-rw-r--r--drivers/s390/net/qeth.h26
-rw-r--r--drivers/s390/net/qeth_main.c26
-rw-r--r--drivers/s390/net/qeth_proc.c126
-rw-r--r--drivers/s390/s390mach.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c28
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c10
-rw-r--r--drivers/s390/scsi/zfcp_def.h2
-rw-r--r--drivers/s390/scsi/zfcp_erp.c25
-rw-r--r--drivers/s390/scsi/zfcp_ext.h2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c1
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c25
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_port.c2
38 files changed, 838 insertions, 752 deletions
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index dc1c89dbdb8f..6e7d7b06421d 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -49,7 +49,7 @@ config DASD_FBA
config DASD_DIAG
tristate "Support for DIAG access to Disks"
- depends on DASD && ARCH_S390X = 'n'
+ depends on DASD && ( ARCH_S390X = 'n' || EXPERIMENTAL)
help
Select this option if you want to use Diagnose250 command to access
Disks under VM. If you are not running under VM or unsure what it is,
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 6527ff6f4706..8fc891a9d47f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.164 $
+ * $Revision: 1.167 $
*/
#include <linux/config.h>
@@ -1131,17 +1131,13 @@ __dasd_process_blk_queue(struct dasd_device * device)
request_queue_t *queue;
struct request *req;
struct dasd_ccw_req *cqr;
- int nr_queued, feature_ro;
+ int nr_queued;
queue = device->request_queue;
/* No queue ? Then there is nothing to do. */
if (queue == NULL)
return;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0) /* no devmap */
- return;
-
/*
* We requeue request from the block device queue to the ccw
* queue only in two states. In state DASD_STATE_READY the
@@ -1162,7 +1158,8 @@ __dasd_process_blk_queue(struct dasd_device * device)
nr_queued < DASD_CHANQ_MAX_SIZE) {
req = elv_next_request(queue);
- if (feature_ro && rq_data_dir(req) == WRITE) {
+ if (device->features & DASD_FEATURE_READONLY &&
+ rq_data_dir(req) == WRITE) {
DBF_DEV_EVENT(DBF_ERR, device,
"Rejecting write request %p",
req);
@@ -1740,6 +1737,10 @@ dasd_exit(void)
dasd_proc_exit();
#endif
dasd_ioctl_exit();
+ if (dasd_page_cache != NULL) {
+ kmem_cache_destroy(dasd_page_cache);
+ dasd_page_cache = NULL;
+ }
dasd_gendisk_exit();
dasd_devmap_exit();
devfs_remove("dasd");
@@ -1810,17 +1811,13 @@ dasd_generic_set_online (struct ccw_device *cdev,
{
struct dasd_device *device;
- int feature_diag, rc;
+ int rc;
device = dasd_create_device(cdev);
if (IS_ERR(device))
return PTR_ERR(device);
- feature_diag = dasd_get_feature(cdev, DASD_FEATURE_USEDIAG);
- if (feature_diag < 0)
- return feature_diag;
-
- if (feature_diag) {
+ if (device->features & DASD_FEATURE_USEDIAG) {
if (!dasd_diag_discipline_pointer) {
printk (KERN_WARNING
"dasd_generic couldn't online device %s "
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index d948566bb24a..bda896d9d788 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -11,7 +11,7 @@
* functions may not be called from interrupt context. In particular
* dasd_get_device is a no-no from interrupt context.
*
- * $Revision: 1.40 $
+ * $Revision: 1.43 $
*/
#include <linux/config.h>
@@ -513,6 +513,7 @@ dasd_create_device(struct ccw_device *cdev)
if (!devmap->device) {
devmap->device = device;
device->devindex = devmap->devindex;
+ device->features = devmap->features;
get_device(&cdev->dev);
device->cdev = cdev;
rc = 0;
@@ -643,6 +644,8 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf
devmap->features |= DASD_FEATURE_READONLY;
else
devmap->features &= ~DASD_FEATURE_READONLY;
+ if (devmap->device)
+ devmap->device->features = devmap->features;
if (devmap->device && devmap->device->gdp)
set_disk_ro(devmap->device->gdp, ro_flag);
spin_unlock(&dasd_devmap_lock);
@@ -758,7 +761,8 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
devmap->features |= feature;
else
devmap->features &= ~feature;
-
+ if (devmap->device)
+ devmap->device->features = devmap->features;
spin_unlock(&dasd_devmap_lock);
return 0;
}
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 127699830fa1..7478423b53bb 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -6,17 +6,18 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.42 $
+ * $Revision: 1.49 $
*/
#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/hdreg.h> /* HDIO_GETGEO */
+#include <linux/hdreg.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <asm/dasd.h>
#include <asm/debug.h>
@@ -28,58 +29,89 @@
#include "dasd_int.h"
#include "dasd_diag.h"
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif /* PRINTK_HEADER */
#define PRINTK_HEADER "dasd(diag):"
MODULE_LICENSE("GPL");
+/* The maximum number of blocks per request (max_blocks) is dependent on the
+ * amount of storage that is available in the static I/O buffer for each
+ * device. Currently each device gets 2 pages. We want to fit two requests
+ * into the available memory so that we can immediately start the next if one
+ * finishes. */
+#define DIAG_MAX_BLOCKS (((2 * PAGE_SIZE - sizeof(struct dasd_ccw_req) - \
+ sizeof(struct dasd_diag_req)) / \
+ sizeof(struct dasd_diag_bio)) / 2)
+#define DIAG_MAX_RETRIES 32
+#define DIAG_TIMEOUT 50 * HZ
+
struct dasd_discipline dasd_diag_discipline;
struct dasd_diag_private {
struct dasd_diag_characteristics rdc_data;
struct dasd_diag_rw_io iob;
struct dasd_diag_init_io iib;
- unsigned int pt_block;
+ blocknum_t pt_block;
};
struct dasd_diag_req {
- int block_count;
+ unsigned int block_count;
struct dasd_diag_bio bio[0];
};
+static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
+
+/* Perform DIAG250 call with block I/O parameter list iob (input and output)
+ * and function code cmd.
+ * In case of an exception return 3. Otherwise return result of bitwise OR of
+ * resulting condition code and DIAG return code. */
static __inline__ int
dia250(void *iob, int cmd)
{
+ typedef struct {
+ char _[max(sizeof (struct dasd_diag_init_io),
+ sizeof (struct dasd_diag_rw_io))];
+ } addr_type;
int rc;
- __asm__ __volatile__(" lhi %0,3\n"
- " lr 0,%2\n"
- " diag 0,%1,0x250\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- " or %0,1\n"
- "1:\n"
-#ifndef CONFIG_ARCH_S390X
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous\n"
+ __asm__ __volatile__(
+#ifdef CONFIG_ARCH_S390X
+ " lghi %0,3\n"
+ " lgr 0,%3\n"
+ " diag 0,%2,0x250\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ " or %0,1\n"
+ "1:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 0b,1b\n"
+ ".previous\n"
#else
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous\n"
+ " lhi %0,3\n"
+ " lr 0,%3\n"
+ " diag 0,%2,0x250\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ " or %0,1\n"
+ "1:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,1b\n"
+ ".previous\n"
#endif
- : "=&d" (rc)
- : "d" (cmd), "d" ((void *) __pa(iob))
- : "0", "1", "cc");
+ : "=&d" (rc), "=m" (*(addr_type *) iob)
+ : "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
+ : "0", "1", "cc");
return rc;
}
+/* Initialize block I/O to DIAG device using the specified blocksize and
+ * block offset. On success, return zero and set end_block to contain the
+ * number of blocks on the device minus the specified offset. Return non-zero
+ * otherwise. */
static __inline__ int
-mdsk_init_io(struct dasd_device * device, int blocksize, int offset, int size)
+mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
+ blocknum_t offset, blocknum_t *end_block)
{
struct dasd_diag_private *private;
struct dasd_diag_init_io *iib;
@@ -92,14 +124,18 @@ mdsk_init_io(struct dasd_device * device, int blocksize, int offset, int size)
iib->dev_nr = _ccw_device_get_device_number(device->cdev);
iib->block_size = blocksize;
iib->offset = offset;
- iib->start_block = 0;
- iib->end_block = size;
+ iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
rc = dia250(iib, INIT_BIO);
- return rc & 3;
+ if ((rc & 3) == 0 && end_block)
+ *end_block = iib->end_block;
+
+ return rc;
}
+/* Remove block I/O environment for device. Return zero on success, non-zero
+ * otherwise. */
static __inline__ int
mdsk_term_io(struct dasd_device * device)
{
@@ -112,9 +148,25 @@ mdsk_term_io(struct dasd_device * device)
memset(iib, 0, sizeof (struct dasd_diag_init_io));
iib->dev_nr = _ccw_device_get_device_number(device->cdev);
rc = dia250(iib, TERM_BIO);
- return rc & 3;
+ return rc;
+}
+
+/* Error recovery for failed DIAG requests - try to reestablish the DIAG
+ * environment. */
+static void
+dasd_diag_erp(struct dasd_device *device)
+{
+ int rc;
+
+ mdsk_term_io(device);
+ rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+ if (rc)
+ DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
+ "rc=%d", rc);
}
+/* Start a given request at the device. Return zero on success, non-zero
+ * otherwise. */
static int
dasd_start_diag(struct dasd_ccw_req * cqr)
{
@@ -124,32 +176,66 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
int rc;
device = cqr->device;
+ if (cqr->retries < 0) {
+ DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
+ "- no retry left)", cqr);
+ cqr->status = DASD_CQR_FAILED;
+ return -EIO;
+ }
private = (struct dasd_diag_private *) device->private;
dreq = (struct dasd_diag_req *) cqr->data;
private->iob.dev_nr = _ccw_device_get_device_number(device->cdev);
private->iob.key = 0;
- private->iob.flags = 2; /* do asynchronous io */
+ private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
private->iob.block_count = dreq->block_count;
- private->iob.interrupt_params = (u32)(addr_t) cqr;
+ private->iob.interrupt_params = (addr_t) cqr;
private->iob.bio_list = __pa(dreq->bio);
+ private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
cqr->startclk = get_clock();
+ cqr->starttime = jiffies;
+ cqr->retries--;
rc = dia250(&private->iob, RW_BIO);
- if (rc > 8) {
- DEV_MESSAGE(KERN_WARNING, device, "dia250 returned CC %d", rc);
- cqr->status = DASD_CQR_ERROR;
- } else if (rc == 0) {
+ switch (rc) {
+ case 0: /* Synchronous I/O finished successfully */
+ cqr->stopclk = get_clock();
cqr->status = DASD_CQR_DONE;
- dasd_schedule_bh(device);
- } else {
+ /* Indicate to calling function that only a dasd_schedule_bh()
+ and no timer is needed */
+ rc = -EACCES;
+ break;
+ case 8: /* Asynchronous I/O was started */
cqr->status = DASD_CQR_IN_IO;
rc = 0;
+ break;
+ default: /* Error condition */
+ cqr->status = DASD_CQR_QUEUED;
+ DEV_MESSAGE(KERN_WARNING, device, "dia250 returned rc=%d", rc);
+ dasd_diag_erp(device);
+ rc = -EIO;
+ break;
}
return rc;
}
+/* Terminate given request at the device. */
+static int
+dasd_diag_term_IO(struct dasd_ccw_req * cqr)
+{
+ struct dasd_device *device;
+
+ device = cqr->device;
+ mdsk_term_io(device);
+ mdsk_init_io(device, device->bp_block, 0, NULL);
+ cqr->status = DASD_CQR_CLEAR;
+ cqr->stopclk = get_clock();
+ dasd_schedule_bh(device);
+ return 0;
+}
+
+/* Handle external interruption. */
static void
dasd_ext_handler(struct pt_regs *regs, __u16 code)
{
@@ -157,25 +243,27 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
struct dasd_device *device;
unsigned long long expires;
unsigned long flags;
- char status;
- int ip;
-
- /*
- * Get the external interruption subcode. VM stores
- * this in the 'cpu address' field associated with
- * the external interrupt. For diag 250 the subcode
- * needs to be 3.
- */
- if ((S390_lowcore.cpu_addr & 0xff00) != 0x0300)
- return;
- status = *((char *) &S390_lowcore.ext_params + 5);
- ip = S390_lowcore.ext_params;
+ u8 int_code, status;
+ addr_t ip;
+ int rc;
+ int_code = *((u8 *) DASD_DIAG_LC_INT_CODE);
+ status = *((u8 *) DASD_DIAG_LC_INT_STATUS);
+ switch (int_code) {
+ case DASD_DIAG_CODE_31BIT:
+ ip = (addr_t) *((u32 *) DASD_DIAG_LC_INT_PARM_31BIT);
+ break;
+ case DASD_DIAG_CODE_64BIT:
+ ip = (addr_t) *((u64 *) DASD_DIAG_LC_INT_PARM_64BIT);
+ break;
+ default:
+ return;
+ }
if (!ip) { /* no intparm: unsolicited interrupt */
MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
return;
}
- cqr = (struct dasd_ccw_req *)(addr_t) ip;
+ cqr = (struct dasd_ccw_req *) ip;
device = (struct dasd_device *) cqr->device;
if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
DEV_MESSAGE(KERN_WARNING, device,
@@ -188,6 +276,15 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
/* get irq lock to modify request queue */
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ /* Check for a pending clear operation */
+ if (cqr->status == DASD_CQR_CLEAR) {
+ cqr->status = DASD_CQR_QUEUED;
+ dasd_clear_timer(device);
+ dasd_schedule_bh(device);
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ return;
+ }
+
cqr->stopclk = get_clock();
expires = 0;
@@ -198,16 +295,22 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
next = list_entry(device->ccw_queue.next,
struct dasd_ccw_req, list);
if (next->status == DASD_CQR_QUEUED) {
- if (dasd_start_diag(next) == 0)
+ rc = dasd_start_diag(next);
+ if (rc == 0)
expires = next->expires;
- else
+ else if (rc != -EACCES)
DEV_MESSAGE(KERN_WARNING, device, "%s",
"Interrupt fastpath "
"failed!");
}
}
- } else
- cqr->status = DASD_CQR_FAILED;
+ } else {
+ cqr->status = DASD_CQR_QUEUED;
+ DEV_MESSAGE(KERN_WARNING, device, "interrupt status for "
+ "request %p was %d (%d retries left)", cqr, status,
+ cqr->retries);
+ dasd_diag_erp(device);
+ }
if (expires != 0)
dasd_set_timer(device, expires);
@@ -218,14 +321,17 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
}
+/* Check whether device can be controlled by DIAG discipline. Return zero on
+ * success, non-zero otherwise. */
static int
dasd_diag_check_device(struct dasd_device *device)
{
struct dasd_diag_private *private;
struct dasd_diag_characteristics *rdc_data;
struct dasd_diag_bio bio;
- long *label;
- int sb, bsize;
+ struct dasd_diag_cms_label *label;
+ blocknum_t end_block;
+ unsigned int sb, bsize;
int rc;
private = (struct dasd_diag_private *) device->private;
@@ -244,8 +350,11 @@ dasd_diag_check_device(struct dasd_device *device)
rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);
rc = diag210((struct diag210 *) rdc_data);
- if (rc)
+ if (rc) {
+ DEV_MESSAGE(KERN_WARNING, device, "failed to retrieve device "
+ "information (rc=%d)", rc);
return -ENOTSUPP;
+ }
/* Figure out position of label block */
switch (private->rdc_data.vdev_class) {
@@ -256,6 +365,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);
return -ENOTSUPP;
}
@@ -269,15 +380,17 @@ dasd_diag_check_device(struct dasd_device *device)
mdsk_term_io(device);
/* figure out blocksize of device */
- label = (long *) get_zeroed_page(GFP_KERNEL);
+ label = (struct dasd_diag_cms_label *) get_zeroed_page(GFP_KERNEL);
if (label == NULL) {
DEV_MESSAGE(KERN_WARNING, device, "%s",
"No memory to allocate initialization request");
return -ENOMEM;
}
+ rc = 0;
+ end_block = 0;
/* try all sizes - needed for ECKD devices */
for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
- mdsk_init_io(device, bsize, 0, 64);
+ mdsk_init_io(device, bsize, 0, &end_block);
memset(&bio, 0, sizeof (struct dasd_diag_bio));
bio.type = MDSK_READ_REQ;
bio.block_number = private->pt_block + 1;
@@ -289,37 +402,45 @@ dasd_diag_check_device(struct dasd_device *device)
private->iob.block_count = 1;
private->iob.interrupt_params = 0;
private->iob.bio_list = __pa(&bio);
- if (dia250(&private->iob, RW_BIO) == 0)
+ private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT;
+ rc = dia250(&private->iob, RW_BIO);
+ if (rc == 0 || rc == 3)
break;
mdsk_term_io(device);
}
- if (bsize <= PAGE_SIZE && label[0] == 0xc3d4e2f1) {
- /* get formatted blocksize from label block */
- bsize = (int) label[3];
- device->blocks = label[7];
+ if (rc == 3) {
+ DEV_MESSAGE(KERN_WARNING, device, "%s", "DIAG call failed");
+ rc = -EOPNOTSUPP;
+ } else if (rc != 0) {
+ DEV_MESSAGE(KERN_WARNING, device, "device access failed "
+ "(rc=%d)", rc);
+ rc = -EIO;
+ } else {
+ if (memcmp(label->label_id, DASD_DIAG_CMS1,
+ sizeof(DASD_DIAG_CMS1)) == 0) {
+ /* get formatted blocksize from label block */
+ bsize = (unsigned int) label->block_size;
+ device->blocks = (unsigned long) label->block_count;
+ } else
+ device->blocks = end_block;
device->bp_block = bsize;
device->s2b_shift = 0; /* bits to shift 512 to get a block */
for (sb = 512; sb < bsize; sb = sb << 1)
device->s2b_shift++;
DEV_MESSAGE(KERN_INFO, device,
- "capacity (%dkB blks): %ldkB",
- (device->bp_block >> 10),
- (device->blocks << device->s2b_shift) >> 1);
+ "(%ld B/blk): %ldkB",
+ (unsigned long) device->bp_block,
+ (unsigned long) (device->blocks <<
+ device->s2b_shift) >> 1);
rc = 0;
- } else {
- if (bsize > PAGE_SIZE)
- DEV_MESSAGE(KERN_WARNING, device, "%s",
- "DIAG access failed");
- else
- DEV_MESSAGE(KERN_WARNING, device, "%s",
- "volume is not CMS formatted");
- rc = -EMEDIUMTYPE;
}
free_page((long) label);
return rc;
}
+/* Fill in virtual disk geometry for device. Return zero on success, non-zero
+ * otherwise. */
static int
dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
{
@@ -349,6 +470,8 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
return dasd_default_erp_postaction;
}
+/* Create DASD request from block device request. Return pointer to new
+ * request on success, ERR_PTR otherwise. */
static struct dasd_ccw_req *
dasd_diag_build_cp(struct dasd_device * device, struct request *req)
{
@@ -358,9 +481,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
struct bio *bio;
struct bio_vec *bv;
char *dst;
- int count, datasize;
+ unsigned int count, datasize;
sector_t recid, first_rec, last_rec;
- unsigned blksize, off;
+ unsigned int blksize, off;
unsigned char rw_cmd;
int i;
@@ -413,13 +536,16 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
}
}
}
+ cqr->retries = DIAG_MAX_RETRIES;
cqr->buildclk = get_clock();
cqr->device = device;
- cqr->expires = 50 * HZ; /* 50 seconds */
+ cqr->expires = DIAG_TIMEOUT;
cqr->status = DASD_CQR_FILLED;
return cqr;
}
+/* Release DASD request. Return non-zero if request was successful, zero
+ * otherwise. */
static int
dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
@@ -430,6 +556,7 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
return status;
}
+/* Fill in IOCTL data for device. */
static int
dasd_diag_fill_info(struct dasd_device * device,
struct dasd_information2_t * info)
@@ -437,7 +564,7 @@ dasd_diag_fill_info(struct dasd_device * device,
struct dasd_diag_private *private;
private = (struct dasd_diag_private *) device->private;
- info->label_block = private->pt_block;
+ info->label_block = (unsigned int) private->pt_block;
info->FBA_layout = 1;
info->format = DASD_FORMAT_LDL;
info->characteristics_size = sizeof (struct dasd_diag_characteristics);
@@ -456,26 +583,15 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"dump sense not available for DIAG data");
}
-/*
- * max_blocks is dependent on the amount of storage that is available
- * in the static io buffer for each device. Currently each device has
- * 8192 bytes (=2 pages). dasd diag is only relevant for 31 bit.
- * The struct dasd_ccw_req has 96 bytes, the struct dasd_diag_req has
- * 8 bytes and the struct dasd_diag_bio for each block has 16 bytes.
- * That makes:
- * (8192 - 96 - 8) / 16 = 505.5 blocks at maximum.
- * We want to fit two into the available memory so that we can immediately
- * start the next request if one finishes off. That makes 252.75 blocks
- * for one request. Give a little safety and the result is 240.
- */
struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",
- .max_blocks = 240,
+ .max_blocks = DIAG_MAX_BLOCKS,
.check_device = dasd_diag_check_device,
.fill_geometry = dasd_diag_fill_geometry,
.start_IO = dasd_start_diag,
+ .term_IO = dasd_diag_term_IO,
.examine_error = dasd_diag_examine_error,
.erp_action = dasd_diag_erp_action,
.erp_postaction = dasd_diag_erp_postaction,
@@ -493,7 +609,7 @@ dasd_diag_init(void)
"Machine is not VM: %s "
"discipline not initializing",
dasd_diag_discipline.name);
- return -EINVAL;
+ return -ENODEV;
}
ASCEBC(dasd_diag_discipline.ebcname, 4);
@@ -506,13 +622,6 @@ dasd_diag_init(void)
static void __exit
dasd_diag_cleanup(void)
{
- if (!MACHINE_IS_VM) {
- MESSAGE_LOG(KERN_INFO,
- "Machine is not VM: %s "
- "discipline not cleaned",
- dasd_diag_discipline.name);
- return;
- }
unregister_external_interrupt(0x2603, dasd_ext_handler);
ctl_clear_bit(0, 9);
dasd_diag_discipline_pointer = NULL;
@@ -520,22 +629,3 @@ dasd_diag_cleanup(void)
module_init(dasd_diag_init);
module_exit(dasd_diag_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h
index a0c38e303979..b26eb28df4bf 100644
--- a/drivers/s390/block/dasd_diag.h
+++ b/drivers/s390/block/dasd_diag.h
@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.6 $
+ * $Revision: 1.7 $
*/
#define MDSK_WRITE_REQ 0x01
@@ -19,6 +19,18 @@
#define DEV_CLASS_FBA 0x01
#define DEV_CLASS_ECKD 0x04
+#define DASD_DIAG_LC_INT_CODE 132
+#define DASD_DIAG_LC_INT_STATUS 133
+#define DASD_DIAG_LC_INT_PARM_31BIT 128
+#define DASD_DIAG_LC_INT_PARM_64BIT 4536
+#define DASD_DIAG_CODE_31BIT 0x03
+#define DASD_DIAG_CODE_64BIT 0x07
+
+#define DASD_DIAG_RWFLAG_ASYNC 0x02
+#define DASD_DIAG_RWFLAG_NOCACHE 0x01
+
+#define DASD_DIAG_FLAGA_FORMAT_64BIT 0x80
+
struct dasd_diag_characteristics {
u16 dev_nr;
u16 rdc_len;
@@ -32,35 +44,106 @@ struct dasd_diag_characteristics {
u8 rdev_features;
} __attribute__ ((packed, aligned(4)));
+struct dasd_diag_cms_label {
+ u8 label_id[4];
+ u8 vol_id[6];
+ u16 version_id;
+ u32 block_size;
+ u32 origin_ptr;
+ u32 usable_count;
+ u32 formatted_count;
+ u32 block_count;
+ u32 used_count;
+ u32 fst_size;
+ u32 fst_count;
+ u8 format_date[6];
+ u8 reserved1[2];
+ u32 disk_offset;
+ u32 map_block;
+ u32 hblk_disp;
+ u32 user_disp;
+ u8 reserved2[4];
+ u8 segment_name[8];
+} __attribute__ ((packed));
+
+#ifdef CONFIG_ARCH_S390X
+#define DASD_DIAG_FLAGA_DEFAULT DASD_DIAG_FLAGA_FORMAT_64BIT
+
+typedef u64 blocknum_t;
+typedef s64 sblocknum_t;
+
+struct dasd_diag_bio {
+ u8 type;
+ u8 status;
+ u8 spare1[2];
+ u32 alet;
+ blocknum_t block_number;
+ u64 buffer;
+} __attribute__ ((packed, aligned(8)));
+
+struct dasd_diag_init_io {
+ u16 dev_nr;
+ u8 flaga;
+ u8 spare1[21];
+ u32 block_size;
+ u8 spare2[4];
+ blocknum_t offset;
+ sblocknum_t start_block;
+ blocknum_t end_block;
+ u8 spare3[8];
+} __attribute__ ((packed, aligned(8)));
+
+struct dasd_diag_rw_io {
+ u16 dev_nr;
+ u8 flaga;
+ u8 spare1[21];
+ u8 key;
+ u8 flags;
+ u8 spare2[2];
+ u32 block_count;
+ u32 alet;
+ u8 spare3[4];
+ u64 interrupt_params;
+ u64 bio_list;
+ u8 spare4[8];
+} __attribute__ ((packed, aligned(8)));
+#else /* CONFIG_ARCH_S390X */
+#define DASD_DIAG_FLAGA_DEFAULT 0x0
+
+typedef u32 blocknum_t;
+typedef s32 sblocknum_t;
+
struct dasd_diag_bio {
u8 type;
u8 status;
u16 spare1;
- u32 block_number;
+ blocknum_t block_number;
u32 alet;
u32 buffer;
} __attribute__ ((packed, aligned(8)));
struct dasd_diag_init_io {
u16 dev_nr;
- u16 spare1[11];
+ u8 flaga;
+ u8 spare1[21];
u32 block_size;
- u32 offset;
- u32 start_block;
- u32 end_block;
- u32 spare2[6];
+ blocknum_t offset;
+ sblocknum_t start_block;
+ blocknum_t end_block;
+ u8 spare2[24];
} __attribute__ ((packed, aligned(8)));
struct dasd_diag_rw_io {
u16 dev_nr;
- u16 spare1[11];
+ u8 flaga;
+ u8 spare1[21];
u8 key;
u8 flags;
- u16 spare2;
+ u8 spare2[2];
u32 block_count;
u32 alet;
u32 bio_list;
u32 interrupt_params;
- u32 spare3[5];
+ u8 spare3[20];
} __attribute__ ((packed, aligned(8)));
-
+#endif /* CONFIG_ARCH_S390X */
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 7963ae343eef..28cb4613b7f5 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -4,7 +4,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.39 $
+ * $Revision: 1.40 $
*/
#include <linux/config.h>
@@ -354,6 +354,8 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
}
cqr->device = device;
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
+ cqr->retries = 32;
+ cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
return cqr;
}
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 96c49349701f..a601c9a33541 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -9,7 +9,7 @@
*
* gendisk related functions for the dasd driver.
*
- * $Revision: 1.50 $
+ * $Revision: 1.51 $
*/
#include <linux/config.h>
@@ -31,16 +31,12 @@ int
dasd_gendisk_alloc(struct dasd_device *device)
{
struct gendisk *gdp;
- int len, feature_ro;
+ int len;
/* Make sure the minor for this device exists. */
if (device->devindex >= DASD_PER_MAJOR)
return -EBUSY;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0)
- return feature_ro;
-
gdp = alloc_disk(1 << DASD_PARTN_BITS);
if (!gdp)
return -ENOMEM;
@@ -75,7 +71,7 @@ dasd_gendisk_alloc(struct dasd_device *device)
sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
- if (feature_ro)
+ if (device->features & DASD_FEATURE_READONLY)
set_disk_ro(gdp, 1);
gdp->private_data = device;
gdp->queue = device->request_queue;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a9f38b235981..9fab04f3056d 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -6,7 +6,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
- * $Revision: 1.64 $
+ * $Revision: 1.65 $
*/
#ifndef DASD_INT_H
@@ -286,6 +286,7 @@ struct dasd_device {
unsigned int bp_block; /* bytes per block */
unsigned int s2b_shift; /* log2 (bp_block/512) */
unsigned long flags; /* per device flags */
+ unsigned short features; /* copy of devmap-features (read-only!) */
/* Device discipline stuff. */
struct dasd_discipline *discipline;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 980c555aa538..789595b3fa09 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -7,7 +7,7 @@
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
*
- * $Revision: 1.45 $
+ * $Revision: 1.47 $
*
* i/o controls for the dasd driver.
*/
@@ -296,7 +296,6 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
{
struct dasd_device *device;
struct format_data_t fdata;
- int feature_ro;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -308,10 +307,7 @@ dasd_ioctl_format(struct block_device *bdev, int no, long args)
if (device == NULL)
return -ENODEV;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0)
- return feature_ro;
- if (feature_ro)
+ if (device->features & DASD_FEATURE_READONLY)
return -EROFS;
if (copy_from_user(&fdata, (void __user *) args,
sizeof (struct format_data_t)))
@@ -384,7 +380,7 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
struct dasd_device *device;
struct dasd_information2_t *dasd_info;
unsigned long flags;
- int rc, feature_ro;
+ int rc;
struct ccw_device *cdev;
device = bdev->bd_disk->private_data;
@@ -394,10 +390,6 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
if (!device->discipline->fill_info)
return -EINVAL;
- feature_ro = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature_ro < 0)
- return feature_ro;
-
dasd_info = kmalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
if (dasd_info == NULL)
return -ENOMEM;
@@ -427,7 +419,8 @@ dasd_ioctl_information(struct block_device *bdev, int no, long args)
(dasd_check_blocksize(device->bp_block)))
dasd_info->format = DASD_FORMAT_NONE;
- dasd_info->features |= feature_ro;
+ dasd_info->features |=
+ ((device->features & DASD_FEATURE_READONLY) != 0);
if (device->discipline)
memcpy(dasd_info->type, device->discipline->name, 4);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 43c34f8c5e68..fff9020d4886 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -9,7 +9,7 @@
*
* /proc interface for the dasd driver.
*
- * $Revision: 1.32 $
+ * $Revision: 1.33 $
*/
#include <linux/config.h>
@@ -55,7 +55,6 @@ dasd_devices_show(struct seq_file *m, void *v)
{
struct dasd_device *device;
char *substr;
- int feature;
device = dasd_device_from_devindex((unsigned long) v - 1);
if (IS_ERR(device))
@@ -79,10 +78,7 @@ dasd_devices_show(struct seq_file *m, void *v)
else
seq_printf(m, " is ????????");
/* Print devices features. */
- feature = dasd_get_feature(device->cdev, DASD_FEATURE_READONLY);
- if (feature < 0)
- return 0;
- substr = feature ? "(ro)" : " ";
+ substr = (device->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
seq_printf(m, "%4s: ", substr);
/* Print device status information. */
switch ((device != NULL) ? device->state : -1) {
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index d5eefeaba50c..328d9cbc56a3 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -632,12 +632,9 @@ __raw3270_size_device(struct raw3270 *rp)
raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
- if (rc) {
+ if (rc)
/* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
- if (rc == -EOPNOTSUPP && MACHINE_IS_VM)
- return __raw3270_size_device_vm(rp);
return rc;
- }
/* Wait for attention interrupt. */
#ifdef CONFIG_TN3270_CONSOLE
@@ -695,7 +692,10 @@ raw3270_size_device(struct raw3270 *rp)
down(&raw3270_init_sem);
rp->view = &raw3270_init_view;
raw3270_init_view.dev = rp;
- rc = __raw3270_size_device(rp);
+ if (MACHINE_IS_VM)
+ rc = __raw3270_size_device_vm(rp);
+ else
+ rc = __raw3270_size_device(rp);
raw3270_init_view.dev = 0;
rp->view = 0;
up(&raw3270_init_sem);
@@ -710,6 +710,12 @@ raw3270_size_device(struct raw3270 *rp)
rp->model = 4;
if (rp->rows == 27 && rp->cols == 132)
rp->model = 5;
+ } else {
+ /* Couldn't detect size. Use default model 2. */
+ rp->model = 2;
+ rp->rows = 24;
+ rp->cols = 80;
+ return 0;
}
return rc;
}
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index d04e6c2c3cc1..01d865d93791 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -3,10 +3,11 @@
* tape device driver for 3480/3490E/3590 tapes.
*
* S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Stefan Bader <shbader@de.ibm.com>
*/
#ifndef _TAPE_H
@@ -111,6 +112,7 @@ enum tape_request_status {
TAPE_REQUEST_QUEUED, /* request is queued to be processed */
TAPE_REQUEST_IN_IO, /* request is currently in IO */
TAPE_REQUEST_DONE, /* request is completed. */
+ TAPE_REQUEST_CANCEL, /* request should be canceled. */
};
/* Tape CCW request */
@@ -237,6 +239,9 @@ struct tape_device {
/* Block dev frontend data */
struct tape_blk_data blk_data;
#endif
+
+ /* Function to start or stop the next request later. */
+ struct work_struct tape_dnr;
};
/* Externals from tape_core.c */
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 0597aa0e27ee..6c52e8307dc5 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -3,11 +3,12 @@
* basic function of the tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Stefan Bader <shbader@de.ibm.com>
*/
#include <linux/config.h>
@@ -28,7 +29,7 @@
#define PRINTK_HEADER "TAPE_CORE: "
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
-static void __tape_remove_request(struct tape_device *, struct tape_request *);
+static void tape_delayed_next_request(void * data);
/*
* One list to contain all tape devices of all disciplines, so
@@ -257,7 +258,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
* Stop running ccw. Has to be called with the device lock held.
*/
static inline int
-__tape_halt_io(struct tape_device *device, struct tape_request *request)
+__tape_cancel_io(struct tape_device *device, struct tape_request *request)
{
int retries;
int rc;
@@ -270,20 +271,23 @@ __tape_halt_io(struct tape_device *device, struct tape_request *request)
for (retries = 0; retries < 5; retries++) {
rc = ccw_device_clear(device->cdev, (long) request);
- if (rc == 0) { /* Termination successful */
- request->rc = -EIO;
- request->status = TAPE_REQUEST_DONE;
- return 0;
+ switch (rc) {
+ case 0:
+ request->status = TAPE_REQUEST_DONE;
+ return 0;
+ case -EBUSY:
+ request->status = TAPE_REQUEST_CANCEL;
+ schedule_work(&device->tape_dnr);
+ return 0;
+ case -ENODEV:
+ DBF_EXCEPTION(2, "device gone, retry\n");
+ break;
+ case -EIO:
+ DBF_EXCEPTION(2, "I/O error, retry\n");
+ break;
+ default:
+ BUG();
}
-
- if (rc == -ENODEV)
- DBF_EXCEPTION(2, "device gone, retry\n");
- else if (rc == -EIO)
- DBF_EXCEPTION(2, "I/O error, retry\n");
- else if (rc == -EBUSY)
- DBF_EXCEPTION(2, "device busy, retry late\n");
- else
- BUG();
}
return rc;
@@ -473,6 +477,7 @@ tape_alloc_device(void)
*device->modeset_byte = 0;
device->first_minor = -1;
atomic_set(&device->ref_count, 1);
+ INIT_WORK(&device->tape_dnr, tape_delayed_next_request, device);
return device;
}
@@ -708,54 +713,119 @@ tape_free_request (struct tape_request * request)
kfree(request);
}
+static inline int
+__tape_start_io(struct tape_device *device, struct tape_request *request)
+{
+ int rc;
+
+#ifdef CONFIG_S390_TAPE_BLOCK
+ if (request->op == TO_BLOCK)
+ device->discipline->check_locate(device, request);
+#endif
+ rc = ccw_device_start(
+ device->cdev,
+ request->cpaddr,
+ (unsigned long) request,
+ 0x00,
+ request->options
+ );
+ if (rc == 0) {
+ request->status = TAPE_REQUEST_IN_IO;
+ } else if (rc == -EBUSY) {
+ /* The common I/O subsystem is currently busy. Retry later. */
+ request->status = TAPE_REQUEST_QUEUED;
+ schedule_work(&device->tape_dnr);
+ rc = 0;
+ } else {
+ /* Start failed. Remove request and indicate failure. */
+ DBF_EVENT(1, "tape: start request failed with RC = %i\n", rc);
+ }
+ return rc;
+}
+
static inline void
-__tape_do_io_list(struct tape_device *device)
+__tape_start_next_request(struct tape_device *device)
{
struct list_head *l, *n;
struct tape_request *request;
int rc;
- DBF_LH(6, "__tape_do_io_list(%p)\n", device);
+ DBF_LH(6, "__tape_start_next_request(%p)\n", device);
/*
* Try to start each request on request queue until one is
* started successful.
*/
list_for_each_safe(l, n, &device->req_queue) {
request = list_entry(l, struct tape_request, list);
-#ifdef CONFIG_S390_TAPE_BLOCK
- if (request->op == TO_BLOCK)
- device->discipline->check_locate(device, request);
-#endif
- rc = ccw_device_start(device->cdev, request->cpaddr,
- (unsigned long) request, 0x00,
- request->options);
- if (rc == 0) {
- request->status = TAPE_REQUEST_IN_IO;
- break;
+
+ /*
+ * Avoid race condition if bottom-half was triggered more than
+ * once.
+ */
+ if (request->status == TAPE_REQUEST_IN_IO)
+ return;
+
+ /*
+ * We wanted to cancel the request but the common I/O layer
+ * was busy at that time. This can only happen if this
+ * function is called by delayed_next_request.
+ * Otherwise we start the next request on the queue.
+ */
+ if (request->status == TAPE_REQUEST_CANCEL) {
+ rc = __tape_cancel_io(device, request);
+ } else {
+ rc = __tape_start_io(device, request);
}
- /* Start failed. Remove request and indicate failure. */
- DBF_EVENT(1, "tape: DOIO failed with er = %i\n", rc);
+ if (rc == 0)
+ return;
- /* Set ending status and do callback. */
+ /* Set ending status. */
request->rc = rc;
request->status = TAPE_REQUEST_DONE;
- __tape_remove_request(device, request);
+
+ /* Remove from request queue. */
+ list_del(&request->list);
+
+ /* Do callback. */
+ if (request->callback != NULL)
+ request->callback(request, request->callback_data);
}
}
static void
-__tape_remove_request(struct tape_device *device, struct tape_request *request)
+tape_delayed_next_request(void *data)
{
- /* Remove from request queue. */
- list_del(&request->list);
+ struct tape_device * device;
- /* Do callback. */
- if (request->callback != NULL)
- request->callback(request, request->callback_data);
+ device = (struct tape_device *) data;
+ DBF_LH(6, "tape_delayed_next_request(%p)\n", device);
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ __tape_start_next_request(device);
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+static inline void
+__tape_end_request(
+ struct tape_device * device,
+ struct tape_request * request,
+ int rc)
+{
+ DBF_LH(6, "__tape_end_request(%p, %p, %i)\n", device, request, rc);
+ if (request) {
+ request->rc = rc;
+ request->status = TAPE_REQUEST_DONE;
+
+ /* Remove from request queue. */
+ list_del(&request->list);
+
+ /* Do callback. */
+ if (request->callback != NULL)
+ request->callback(request, request->callback_data);
+ }
/* Start next request. */
if (!list_empty(&device->req_queue))
- __tape_do_io_list(device);
+ __tape_start_next_request(device);
}
/*
@@ -812,7 +882,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,
* the device lock held.
*/
static inline int
-__tape_do_io(struct tape_device *device, struct tape_request *request)
+__tape_start_request(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -837,24 +907,16 @@ __tape_do_io(struct tape_device *device, struct tape_request *request)
if (list_empty(&device->req_queue)) {
/* No other requests are on the queue. Start this one. */
-#ifdef CONFIG_S390_TAPE_BLOCK
- if (request->op == TO_BLOCK)
- device->discipline->check_locate(device, request);
-#endif
- rc = ccw_device_start(device->cdev, request->cpaddr,
- (unsigned long) request, 0x00,
- request->options);
- if (rc) {
- DBF_EVENT(1, "tape: DOIO failed with rc = %i\n", rc);
+ rc = __tape_start_io(device, request);
+ if (rc)
return rc;
- }
+
DBF_LH(5, "Request %p added for execution.\n", request);
list_add(&request->list, &device->req_queue);
- request->status = TAPE_REQUEST_IN_IO;
} else {
DBF_LH(5, "Request %p add to queue.\n", request);
- list_add_tail(&request->list, &device->req_queue);
request->status = TAPE_REQUEST_QUEUED;
+ list_add_tail(&request->list, &device->req_queue);
}
return 0;
}
@@ -872,7 +934,7 @@ tape_do_io_async(struct tape_device *device, struct tape_request *request)
spin_lock_irq(get_ccwdev_lock(device->cdev));
/* Add request to request queue and try to start it. */
- rc = __tape_do_io(device, request);
+ rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
}
@@ -901,7 +963,7 @@ tape_do_io(struct tape_device *device, struct tape_request *request)
request->callback = __tape_wake_up;
request->callback_data = &wq;
/* Add request to request queue and try to start it. */
- rc = __tape_do_io(device, request);
+ rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc)
return rc;
@@ -935,7 +997,7 @@ tape_do_io_interruptible(struct tape_device *device,
/* Setup callback */
request->callback = __tape_wake_up_interruptible;
request->callback_data = &wq;
- rc = __tape_do_io(device, request);
+ rc = __tape_start_request(device, request);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc)
return rc;
@@ -944,36 +1006,27 @@ tape_do_io_interruptible(struct tape_device *device,
if (rc != -ERESTARTSYS)
/* Request finished normally. */
return request->rc;
+
/* Interrupted by a signal. We have to stop the current request. */
spin_lock_irq(get_ccwdev_lock(device->cdev));
- rc = __tape_halt_io(device, request);
+ rc = __tape_cancel_io(device, request);
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (rc == 0) {
+ /* Wait for the interrupt that acknowledges the halt. */
+ do {
+ rc = wait_event_interruptible(
+ wq,
+ (request->callback == NULL)
+ );
+ } while (rc != -ERESTARTSYS);
+
DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id);
rc = -ERESTARTSYS;
}
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
}
/*
- * Handle requests that return an i/o error in the irb.
- */
-static inline void
-tape_handle_killed_request(
- struct tape_device *device,
- struct tape_request *request)
-{
- if(request != NULL) {
- /* Set ending status. FIXME: Should the request be retried? */
- request->rc = -EIO;
- request->status = TAPE_REQUEST_DONE;
- __tape_remove_request(device, request);
- } else {
- __tape_do_io_list(device);
- }
-}
-
-/*
* Tape interrupt routine, called from the ccw_device layer
*/
static void
@@ -981,7 +1034,6 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
{
struct tape_device *device;
struct tape_request *request;
- int final;
int rc;
device = (struct tape_device *) cdev->dev.driver_data;
@@ -996,12 +1048,13 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* On special conditions irb is an error pointer */
if (IS_ERR(irb)) {
+ /* FIXME: What to do with the request? */
switch (PTR_ERR(irb)) {
case -ETIMEDOUT:
PRINT_WARN("(%s): Request timed out\n",
cdev->dev.bus_id);
case -EIO:
- tape_handle_killed_request(device, request);
+ __tape_end_request(device, request, -EIO);
break;
default:
PRINT_ERR("(%s): Unexpected i/o error %li\n",
@@ -1011,6 +1064,21 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
return;
}
+ /*
+ * If the condition code is not zero and the start function bit is
+ * still set, this is an deferred error and the last start I/O did
+ * not succeed. Restart the request now.
+ */
+ if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
+ PRINT_WARN("(%s): deferred cc=%i. restaring\n",
+ cdev->dev.bus_id,
+ irb->scsw.cc);
+ rc = __tape_start_io(device, request);
+ if (rc)
+ __tape_end_request(device, request, rc);
+ return;
+ }
+
/* May be an unsolicited irq */
if(request != NULL)
request->rescnt = irb->scsw.count;
@@ -1042,7 +1110,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
* To detect these request the state will be set to TAPE_REQUEST_DONE.
*/
if(request != NULL && request->status == TAPE_REQUEST_DONE) {
- __tape_remove_request(device, request);
+ __tape_end_request(device, request, -EIO);
return;
}
@@ -1054,51 +1122,34 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
* rc == TAPE_IO_RETRY: request finished but needs another go.
* rc == TAPE_IO_STOP: request needs to get terminated.
*/
- final = 0;
switch (rc) {
- case TAPE_IO_SUCCESS:
- /* Upon normal completion the device _is_ online */
- device->tape_generic_status |= GMT_ONLINE(~0);
- final = 1;
- break;
- case TAPE_IO_PENDING:
- break;
- case TAPE_IO_RETRY:
-#ifdef CONFIG_S390_TAPE_BLOCK
- if (request->op == TO_BLOCK)
- device->discipline->check_locate(device, request);
-#endif
- rc = ccw_device_start(cdev, request->cpaddr,
- (unsigned long) request, 0x00,
- request->options);
- if (rc) {
- DBF_EVENT(1, "tape: DOIO failed with er = %i\n", rc);
- final = 1;
- }
- break;
- case TAPE_IO_STOP:
- __tape_halt_io(device, request);
- break;
- default:
- if (rc > 0) {
- DBF_EVENT(6, "xunknownrc\n");
- PRINT_ERR("Invalid return code from discipline "
- "interrupt function.\n");
- rc = -EIO;
- }
- final = 1;
- break;
- }
- if (final) {
- /* May be an unsolicited irq */
- if(request != NULL) {
- /* Set ending status. */
- request->rc = rc;
- request->status = TAPE_REQUEST_DONE;
- __tape_remove_request(device, request);
- } else {
- __tape_do_io_list(device);
- }
+ case TAPE_IO_SUCCESS:
+ /* Upon normal completion the device _is_ online */
+ device->tape_generic_status |= GMT_ONLINE(~0);
+ __tape_end_request(device, request, rc);
+ break;
+ case TAPE_IO_PENDING:
+ break;
+ case TAPE_IO_RETRY:
+ rc = __tape_start_io(device, request);
+ if (rc)
+ __tape_end_request(device, request, rc);
+ break;
+ case TAPE_IO_STOP:
+ rc = __tape_cancel_io(device, request);
+ if (rc)
+ __tape_end_request(device, request, rc);
+ break;
+ 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);
+ }
+ break;
}
}
@@ -1191,7 +1242,7 @@ tape_init (void)
#ifdef DBF_LIKE_HELL
debug_set_level(TAPE_DBF_AREA, 6);
#endif
- DBF_EVENT(3, "tape init: ($Revision: 1.51 $)\n");
+ DBF_EVENT(3, "tape init: ($Revision: 1.54 $)\n");
tape_proc_init();
tapechar_init ();
tapeblock_init ();
@@ -1216,7 +1267,7 @@ tape_exit(void)
MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and "
"Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
MODULE_DESCRIPTION("Linux on zSeries channel attached "
- "tape device driver ($Revision: 1.51 $)");
+ "tape device driver ($Revision: 1.54 $)");
MODULE_LICENSE("GPL");
module_init(tape_init);
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 7f11a608a633..8990d8076e7d 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -115,9 +115,9 @@ vmcp_write(struct file *file, const char __user * buff, size_t count,
return -ENOMEM;
}
debug_text_event(vmcp_debug, 1, cmd);
- session->resp_size = cpcmd(cmd, session->response,
- session->bufsize,
- &session->resp_code);
+ session->resp_size = __cpcmd(cmd, session->response,
+ session->bufsize,
+ &session->resp_code);
up(&session->mutex);
kfree(cmd);
*ppos = 0; /* reset the file pointer after a command */
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 22cf4fec8da9..5473c23fcb52 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -23,11 +23,7 @@
static char vmwdt_cmd[MAX_CMDLEN] = "IPL";
static int vmwdt_conceal;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-static int vmwdt_nowayout = 1;
-#else
-static int vmwdt_nowayout = 0;
-#endif
+static int vmwdt_nowayout = WATCHDOG_NOWAYOUT;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index b86f94ecd874..fa3c23b80e3a 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/chsc.c
* S/390 common I/O routines -- channel subsystem call
- * $Revision: 1.119 $
+ * $Revision: 1.120 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -412,11 +412,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
if (chp_mask == 0) {
spin_unlock_irq(&sch->lock);
-
- if (fla_mask != 0)
- break;
- else
- continue;
+ continue;
}
old_lpm = sch->lpm;
sch->lpm = ((sch->schib.pmcw.pim &
@@ -430,7 +426,7 @@ s390_process_res_acc (u8 chpid, __u16 fla, u32 fla_mask)
spin_unlock_irq(&sch->lock);
put_device(&sch->dev);
- if (fla_mask != 0)
+ if (fla_mask == 0xffff)
break;
}
return rc;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ea813bdce1d6..185bc73c3ecd 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls
- * $Revision: 1.134 $
+ * $Revision: 1.135 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -815,8 +815,9 @@ __clear_subchannel_easy(unsigned int schid)
struct tpi_info ti;
if (tpi(&ti)) {
- tsch(schid, (struct irb *)__LC_IRB);
- return 0;
+ tsch(ti.irq, (struct irb *)__LC_IRB);
+ if (ti.irq == schid)
+ return 0;
}
udelay(100);
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 9b7f6f548b1d..fbe4202a3f6f 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <asm/ccwdev.h>
-#include <asm/qdio.h>
+#include <asm/cio.h>
#include "cio.h"
#include "cio_debug.h"
@@ -21,7 +21,6 @@
#include "device.h"
#include "chsc.h"
#include "ioasm.h"
-#include "qdio.h"
int
device_is_online(struct subchannel *sch)
@@ -235,6 +234,9 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
sch->schib.pmcw.pam &
sch->schib.pmcw.pom &
sch->opm;
+ /* Check since device may again have become not operational. */
+ if (!sch->schib.pmcw.dnv)
+ state = DEV_STATE_NOT_OPER;
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
/* Force reprobe on all chpids. */
old_lpm = 0;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 02d01a0de16c..ad3fe5aeb663 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/device_ops.c
*
- * $Revision: 1.56 $
+ * $Revision: 1.57 $
*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -19,14 +19,12 @@
#include <asm/ccwdev.h>
#include <asm/idals.h>
-#include <asm/qdio.h>
#include "cio.h"
#include "cio_debug.h"
#include "css.h"
#include "chsc.h"
#include "device.h"
-#include "qdio.h"
int
ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 4ab2e0d95009..12a24d4331a2 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -39,15 +39,14 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
" ... device %04X on subchannel %04X, dev_stat "
": %02X sch_stat : %02X\n",
cdev->private->devno, cdev->private->irq,
- cdev->private->irb.scsw.dstat,
- cdev->private->irb.scsw.cstat);
+ irb->scsw.dstat, irb->scsw.cstat);
if (irb->scsw.cc != 3) {
char dbf_text[15];
sprintf(dbf_text, "chk%x", cdev->private->irq);
CIO_TRACE_EVENT(0, dbf_text);
- CIO_HEX_EVENT(0, &cdev->private->irb, sizeof (struct irb));
+ CIO_HEX_EVENT(0, irb, sizeof (struct irb));
}
}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index c874607d9a80..45480a2bc4c0 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -21,7 +21,7 @@ struct tpi_info {
* Some S390 specific IO instructions as inline
*/
-extern __inline__ int stsch(int irq, volatile struct schib *addr)
+static inline int stsch(int irq, volatile struct schib *addr)
{
int ccode;
@@ -36,7 +36,7 @@ extern __inline__ int stsch(int irq, volatile struct schib *addr)
return ccode;
}
-extern __inline__ int msch(int irq, volatile struct schib *addr)
+static inline int msch(int irq, volatile struct schib *addr)
{
int ccode;
@@ -51,7 +51,7 @@ extern __inline__ int msch(int irq, volatile struct schib *addr)
return ccode;
}
-extern __inline__ int msch_err(int irq, volatile struct schib *addr)
+static inline int msch_err(int irq, volatile struct schib *addr)
{
int ccode;
@@ -79,7 +79,7 @@ extern __inline__ int msch_err(int irq, volatile struct schib *addr)
return ccode;
}
-extern __inline__ int tsch(int irq, volatile struct irb *addr)
+static inline int tsch(int irq, volatile struct irb *addr)
{
int ccode;
@@ -94,7 +94,7 @@ extern __inline__ int tsch(int irq, volatile struct irb *addr)
return ccode;
}
-extern __inline__ int tpi( volatile struct tpi_info *addr)
+static inline int tpi( volatile struct tpi_info *addr)
{
int ccode;
@@ -108,7 +108,7 @@ extern __inline__ int tpi( volatile struct tpi_info *addr)
return ccode;
}
-extern __inline__ int ssch(int irq, volatile struct orb *addr)
+static inline int ssch(int irq, volatile struct orb *addr)
{
int ccode;
@@ -123,7 +123,7 @@ extern __inline__ int ssch(int irq, volatile struct orb *addr)
return ccode;
}
-extern __inline__ int rsch(int irq)
+static inline int rsch(int irq)
{
int ccode;
@@ -138,7 +138,7 @@ extern __inline__ int rsch(int irq)
return ccode;
}
-extern __inline__ int csch(int irq)
+static inline int csch(int irq)
{
int ccode;
@@ -153,7 +153,7 @@ extern __inline__ int csch(int irq)
return ccode;
}
-extern __inline__ int hsch(int irq)
+static inline int hsch(int irq)
{
int ccode;
@@ -168,7 +168,7 @@ extern __inline__ int hsch(int irq)
return ccode;
}
-extern __inline__ int xsch(int irq)
+static inline int xsch(int irq)
{
int ccode;
@@ -183,7 +183,7 @@ extern __inline__ int xsch(int irq)
return ccode;
}
-extern __inline__ int chsc(void *chsc_area)
+static inline int chsc(void *chsc_area)
{
int cc;
@@ -198,7 +198,7 @@ extern __inline__ int chsc(void *chsc_area)
return cc;
}
-extern __inline__ int iac( void)
+static inline int iac( void)
{
int ccode;
@@ -210,7 +210,7 @@ extern __inline__ int iac( void)
return ccode;
}
-extern __inline__ int rchp(int chpid)
+static inline int rchp(int chpid)
{
int ccode;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 82194c4eadfb..381f339e3200 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -112,7 +112,7 @@ qdio_min(int a,int b)
/***************** SCRUBBER HELPER ROUTINES **********************/
-static inline volatile __u64
+static inline __u64
qdio_get_micros(void)
{
return (get_clock() >> 10); /* time>>12 is microseconds */
@@ -230,7 +230,7 @@ qdio_siga_input(struct qdio_q *q)
}
/* locked by the locks in qdio_activate and qdio_cleanup */
-static __u32 * volatile
+static __u32 volatile *
qdio_get_indicator(void)
{
int i;
@@ -432,7 +432,7 @@ tiqdio_clear_global_summary(void)
/************************* OUTBOUND ROUTINES *******************************/
-inline static int
+static inline int
qdio_get_outbound_buffer_frontier(struct qdio_q *q)
{
int f,f_mod_no;
@@ -510,7 +510,7 @@ out:
}
/* all buffers are processed */
-inline static int
+static inline int
qdio_is_outbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -532,7 +532,7 @@ qdio_is_outbound_q_done(struct qdio_q *q)
return (no_used==0);
}
-inline static int
+static inline int
qdio_has_outbound_q_moved(struct qdio_q *q)
{
int i;
@@ -552,7 +552,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q)
}
}
-inline static void
+static inline void
qdio_kick_outbound_q(struct qdio_q *q)
{
int result;
@@ -641,7 +641,7 @@ qdio_kick_outbound_q(struct qdio_q *q)
}
}
-inline static void
+static inline void
qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, real_end, count;
@@ -740,7 +740,7 @@ qdio_outbound_processing(struct qdio_q *q)
/************************* INBOUND ROUTINES *******************************/
-inline static int
+static inline int
qdio_get_inbound_buffer_frontier(struct qdio_q *q)
{
int f,f_mod_no;
@@ -865,7 +865,7 @@ out:
return q->first_to_check;
}
-inline static int
+static inline int
qdio_has_inbound_q_moved(struct qdio_q *q)
{
int i;
@@ -898,7 +898,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
}
/* means, no more buffers to be filled */
-inline static int
+static inline int
tiqdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -951,7 +951,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
return 0;
}
-inline static int
+static inline int
qdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1010,7 +1010,7 @@ qdio_is_inbound_q_done(struct qdio_q *q)
}
}
-inline static void
+static inline void
qdio_kick_inbound_handler(struct qdio_q *q)
{
int count, start, end, real_end, i;
diff --git a/drivers/s390/crypto/z90common.h b/drivers/s390/crypto/z90common.h
index bcabac7a7c46..e319e78b5ea2 100644
--- a/drivers/s390/crypto/z90common.h
+++ b/drivers/s390/crypto/z90common.h
@@ -27,7 +27,7 @@
#ifndef _Z90COMMON_H_
#define _Z90COMMON_H_
-#define VERSION_Z90COMMON_H "$Revision: 1.16 $"
+#define VERSION_Z90COMMON_H "$Revision: 1.17 $"
#define RESPBUFFSIZE 256
@@ -164,5 +164,4 @@ struct CPRBX {
#define UMIN(a,b) ((a) < (b) ? (a) : (b))
#define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
-
#endif
diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h
index 82a1d97001d7..0a3bb5a10dd4 100644
--- a/drivers/s390/crypto/z90crypt.h
+++ b/drivers/s390/crypto/z90crypt.h
@@ -36,15 +36,6 @@
#define z90crypt_VARIANT 2 // 2 = added PCIXCC MCL3 and CEX2C support
/**
- * If we are not using the sparse checker, __user has no use.
- */
-#ifdef __CHECKER__
-# define __user __attribute__((noderef, address_space(1)))
-#else
-# define __user
-#endif
-
-/**
* struct ica_rsa_modexpo
*
* Requirements:
diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c
index beb6a5e0da22..c215e0889736 100644
--- a/drivers/s390/crypto/z90hardware.c
+++ b/drivers/s390/crypto/z90hardware.c
@@ -32,7 +32,7 @@
#include "z90crypt.h"
#include "z90common.h"
-#define VERSION_Z90HARDWARE_C "$Revision: 1.33 $"
+#define VERSION_Z90HARDWARE_C "$Revision: 1.34 $"
char z90hardware_version[] __initdata =
"z90hardware.o (" VERSION_Z90HARDWARE_C "/"
@@ -283,48 +283,6 @@ struct type6_msg {
struct CPRB CPRB;
};
-union request_msg {
- union type4_msg t4msg;
- struct type6_msg t6msg;
-};
-
-struct request_msg_ext {
- int q_nr;
- unsigned char *psmid;
- union request_msg reqMsg;
-};
-
-struct type82_hdr {
- unsigned char reserved1;
- unsigned char type;
- unsigned char reserved2[2];
- unsigned char reply_code;
- unsigned char reserved3[3];
-};
-
-#define TYPE82_RSP_CODE 0x82
-
-#define REPLY_ERROR_MACHINE_FAILURE 0x10
-#define REPLY_ERROR_PREEMPT_FAILURE 0x12
-#define REPLY_ERROR_CHECKPT_FAILURE 0x14
-#define REPLY_ERROR_MESSAGE_TYPE 0x20
-#define REPLY_ERROR_INVALID_COMM_CD 0x21
-#define REPLY_ERROR_INVALID_MSG_LEN 0x23
-#define REPLY_ERROR_RESERVD_FIELD 0x24
-#define REPLY_ERROR_FORMAT_FIELD 0x29
-#define REPLY_ERROR_INVALID_COMMAND 0x30
-#define REPLY_ERROR_MALFORMED_MSG 0x40
-#define REPLY_ERROR_RESERVED_FIELDO 0x50
-#define REPLY_ERROR_WORD_ALIGNMENT 0x60
-#define REPLY_ERROR_MESSAGE_LENGTH 0x80
-#define REPLY_ERROR_OPERAND_INVALID 0x82
-#define REPLY_ERROR_OPERAND_SIZE 0x84
-#define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85
-#define REPLY_ERROR_RESERVED_FIELD 0x88
-#define REPLY_ERROR_TRANSPORT_FAIL 0x90
-#define REPLY_ERROR_PACKET_TRUNCATED 0xA0
-#define REPLY_ERROR_ZERO_BUFFER_LEN 0xB0
-
struct type86_hdr {
unsigned char reserved1;
unsigned char type;
@@ -338,7 +296,7 @@ struct type86_hdr {
#define TYPE86_FMT2 0x02
struct type86_fmt2_msg {
- struct type86_hdr hdr;
+ struct type86_hdr header;
unsigned char reserved[4];
unsigned char apfs[4];
unsigned int count1;
@@ -538,6 +496,8 @@ static struct function_and_rules_block static_pke_function_and_rulesX = {
{'M','R','P',' ',' ',' ',' ',' '}
};
+static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+
struct T6_keyBlock_hdrX {
unsigned short blen;
unsigned short ulen;
@@ -688,9 +648,38 @@ static struct cca_public_sec static_cca_pub_sec = {
#define RESPONSE_CPRB_SIZE 0x000006B8
#define RESPONSE_CPRBX_SIZE 0x00000724
-#define CALLER_HEADER 12
+struct error_hdr {
+ unsigned char reserved1;
+ unsigned char type;
+ unsigned char reserved2[2];
+ unsigned char reply_code;
+ unsigned char reserved3[3];
+};
-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+#define TYPE82_RSP_CODE 0x82
+
+#define REP82_ERROR_MACHINE_FAILURE 0x10
+#define REP82_ERROR_PREEMPT_FAILURE 0x12
+#define REP82_ERROR_CHECKPT_FAILURE 0x14
+#define REP82_ERROR_MESSAGE_TYPE 0x20
+#define REP82_ERROR_INVALID_COMM_CD 0x21
+#define REP82_ERROR_INVALID_MSG_LEN 0x23
+#define REP82_ERROR_RESERVD_FIELD 0x24
+#define REP82_ERROR_FORMAT_FIELD 0x29
+#define REP82_ERROR_INVALID_COMMAND 0x30
+#define REP82_ERROR_MALFORMED_MSG 0x40
+#define REP82_ERROR_RESERVED_FIELDO 0x50
+#define REP82_ERROR_WORD_ALIGNMENT 0x60
+#define REP82_ERROR_MESSAGE_LENGTH 0x80
+#define REP82_ERROR_OPERAND_INVALID 0x82
+#define REP82_ERROR_OPERAND_SIZE 0x84
+#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REP82_ERROR_RESERVED_FIELD 0x88
+#define REP82_ERROR_TRANSPORT_FAIL 0x90
+#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
+
+#define CALLER_HEADER 12
static inline int
testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
@@ -1212,9 +1201,9 @@ send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
struct ap_status_word stat_word;
enum devstat stat;
int ccode;
+ u32 *q_nr_p = (u32 *)msg_ext;
- ((struct request_msg_ext *) msg_ext)->q_nr =
- (dev_nr << SKIP_BITL) + cdx;
+ *q_nr_p = (dev_nr << SKIP_BITL) + cdx;
PDEBUG("msg_len passed to sen: %d\n", msg_len);
PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
@@ -2104,7 +2093,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
int *respbufflen_p, unsigned char *resp_buff)
{
struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
- struct type82_hdr *t82h_p = (struct type82_hdr *) response;
+ struct error_hdr *errh_p = (struct error_hdr *) response;
struct type84_hdr *t84h_p = (struct type84_hdr *) response;
struct type86_fmt2_msg *t86m_p = (struct type86_fmt2_msg *) response;
int reply_code, service_rc, service_rs, src_l;
@@ -2117,12 +2106,13 @@ convert_response(unsigned char *response, unsigned char *buffer,
service_rc = 0;
service_rs = 0;
src_l = 0;
- switch (t82h_p->type) {
+ switch (errh_p->type) {
case TYPE82_RSP_CODE:
- reply_code = t82h_p->reply_code;
- src_p = (unsigned char *)t82h_p;
- PRINTK("Hardware error: Type 82 Message Header: "
+ reply_code = errh_p->reply_code;
+ src_p = (unsigned char *)errh_p;
+ PRINTK("Hardware error: Type %02X Message Header: "
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ errh_p->type,
src_p[0], src_p[1], src_p[2], src_p[3],
src_p[4], src_p[5], src_p[6], src_p[7]);
break;
@@ -2131,7 +2121,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
src_p = response + (int)t84h_p->len - src_l;
break;
case TYPE86_RSP_CODE:
- reply_code = t86m_p->hdr.reply_code;
+ reply_code = t86m_p->header.reply_code;
if (reply_code != 0)
break;
cprb_p = (struct CPRB *)
@@ -2143,6 +2133,9 @@ convert_response(unsigned char *response, unsigned char *buffer,
le2toI(cprb_p->ccp_rscode, &service_rs);
if ((service_rc == 8) && (service_rs == 66))
PDEBUG("Bad block format on PCICC\n");
+ else if ((service_rc == 8) && (service_rs == 65))
+ PDEBUG("Probably an even modulus on "
+ "PCICC\n");
else if ((service_rc == 8) && (service_rs == 770)) {
PDEBUG("Invalid key length on PCICC\n");
unset_ext_bitlens();
@@ -2155,7 +2148,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
return REC_USE_PCICA;
}
else
- PRINTK("service rc/rs: %d/%d\n",
+ PRINTK("service rc/rs (PCICC): %d/%d\n",
service_rc, service_rs);
return REC_OPERAND_INV;
}
@@ -2169,7 +2162,10 @@ convert_response(unsigned char *response, unsigned char *buffer,
if (service_rc != 0) {
service_rs = (int) cprbx_p->ccp_rscode;
if ((service_rc == 8) && (service_rs == 66))
- PDEBUG("Bad block format on PCXICC\n");
+ PDEBUG("Bad block format on PCIXCC\n");
+ else if ((service_rc == 8) && (service_rs == 65))
+ PDEBUG("Probably an even modulus on "
+ "PCIXCC\n");
else if ((service_rc == 8) && (service_rs == 770)) {
PDEBUG("Invalid key length on PCIXCC\n");
unset_ext_bitlens();
@@ -2182,7 +2178,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
return REC_USE_PCICA;
}
else
- PRINTK("service rc/rs: %d/%d\n",
+ PRINTK("service rc/rs (PCIXCC): %d/%d\n",
service_rc, service_rs);
return REC_OPERAND_INV;
}
@@ -2195,20 +2191,25 @@ convert_response(unsigned char *response, unsigned char *buffer,
}
break;
default:
+ src_p = (unsigned char *)errh_p;
+ PRINTK("Unrecognized Message Header: "
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ src_p[0], src_p[1], src_p[2], src_p[3],
+ src_p[4], src_p[5], src_p[6], src_p[7]);
return REC_BAD_MESSAGE;
}
if (reply_code)
switch (reply_code) {
- case REPLY_ERROR_OPERAND_INVALID:
+ case REP82_ERROR_OPERAND_INVALID:
return REC_OPERAND_INV;
- case REPLY_ERROR_OPERAND_SIZE:
+ case REP82_ERROR_OPERAND_SIZE:
return REC_OPERAND_SIZE;
- case REPLY_ERROR_EVEN_MOD_IN_OPND:
+ case REP82_ERROR_EVEN_MOD_IN_OPND:
return REC_EVEN_MOD;
- case REPLY_ERROR_MESSAGE_TYPE:
+ case REP82_ERROR_MESSAGE_TYPE:
return WRONG_DEVICE_TYPE;
- case REPLY_ERROR_TRANSPORT_FAIL:
+ case REP82_ERROR_TRANSPORT_FAIL:
PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
t86m_p->apfs[0], t86m_p->apfs[1],
t86m_p->apfs[2], t86m_p->apfs[3]);
@@ -2229,7 +2230,7 @@ convert_response(unsigned char *response, unsigned char *buffer,
PDEBUG("Length returned = %d\n", src_l);
tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
memcpy(tgt_p, src_p, src_l);
- if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
+ if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
return REC_INVALID_PAD;
diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
index 9ec29bb41b28..6aeef3bacc33 100644
--- a/drivers/s390/crypto/z90main.c
+++ b/drivers/s390/crypto/z90main.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/interrupt.h> // for tasklets
#include <linux/ioctl32.h>
+#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kobject_uevent.h>
@@ -39,19 +40,8 @@
#include <linux/version.h>
#include "z90crypt.h"
#include "z90common.h"
-#ifndef Z90CRYPT_USE_HOTPLUG
-#include <linux/miscdevice.h>
-#endif
-
-#define VERSION_CODE(vers, rel, seq) (((vers)<<16) | ((rel)<<8) | (seq))
-#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) /* version < 2.4 */
-# error "This kernel is too old: not supported"
-#endif
-#if LINUX_VERSION_CODE > VERSION_CODE(2,7,0) /* version > 2.6 */
-# error "This kernel is too recent: not supported by this file"
-#endif
-#define VERSION_Z90MAIN_C "$Revision: 1.57 $"
+#define VERSION_Z90MAIN_C "$Revision: 1.62 $"
static char z90main_version[] __initdata =
"z90main.o (" VERSION_Z90MAIN_C "/"
@@ -63,21 +53,12 @@ extern char z90hardware_version[];
* Defaults that may be modified.
*/
-#ifndef Z90CRYPT_USE_HOTPLUG
/**
* You can specify a different minor at compile time.
*/
#ifndef Z90CRYPT_MINOR
#define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR
#endif
-#else
-/**
- * You can specify a different major at compile time.
- */
-#ifndef Z90CRYPT_MAJOR
-#define Z90CRYPT_MAJOR 0
-#endif
-#endif
/**
* You can specify a different domain at compile time or on the insmod
@@ -97,7 +78,7 @@ extern char z90hardware_version[];
* older than CLEANUPTIME seconds in the past.
*/
#ifndef CLEANUPTIME
-#define CLEANUPTIME 20
+#define CLEANUPTIME 15
#endif
/**
@@ -298,6 +279,10 @@ struct z90crypt {
* it contains the request; at READ, the response. The function
* send_to_crypto_device converts the request to device-dependent
* form and use the caller's OPEN-allocated buffer for the response.
+ *
+ * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
+ * because that points to it, see the discussion in z90hardware.c.
+ * Search for "extended request message block".
*/
struct caller {
int caller_buf_l; // length of original request
@@ -398,24 +383,9 @@ static int z90crypt_status_write(struct file *, const char __user *,
unsigned long, void *);
/**
- * Hotplug support
- */
-
-#ifdef Z90CRYPT_USE_HOTPLUG
-#define Z90CRYPT_HOTPLUG_ADD 1
-#define Z90CRYPT_HOTPLUG_REMOVE 2
-
-static void z90crypt_hotplug_event(int, int, int);
-#endif
-
-/**
* Storage allocated at initialization and used throughout the life of
* this insmod
*/
-#ifdef Z90CRYPT_USE_HOTPLUG
-static int z90crypt_major = Z90CRYPT_MAJOR;
-#endif
-
static int domain = DOMAIN_INDEX;
static struct z90crypt z90crypt;
static int quiesce_z90crypt;
@@ -444,14 +414,12 @@ static struct file_operations z90crypt_fops = {
.release = z90crypt_release
};
-#ifndef Z90CRYPT_USE_HOTPLUG
static struct miscdevice z90crypt_misc_device = {
.minor = Z90CRYPT_MINOR,
.name = DEV_NAME,
.fops = &z90crypt_fops,
.devfs_name = DEV_NAME
};
-#endif
/**
* Documentation values.
@@ -603,7 +571,6 @@ z90crypt_init_module(void)
return -EINVAL;
}
-#ifndef Z90CRYPT_USE_HOTPLUG
/* Register as misc device with given minor (or get a dynamic one). */
result = misc_register(&z90crypt_misc_device);
if (result < 0) {
@@ -611,18 +578,6 @@ z90crypt_init_module(void)
z90crypt_misc_device.minor, result);
return result;
}
-#else
- /* Register the major (or get a dynamic one). */
- result = register_chrdev(z90crypt_major, REG_NAME, &z90crypt_fops);
- if (result < 0) {
- PRINTKW("register_chrdev (major %d) failed with %d.\n",
- z90crypt_major, result);
- return result;
- }
-
- if (z90crypt_major == 0)
- z90crypt_major = result;
-#endif
PDEBUG("Registered " DEV_NAME " with result %d\n", result);
@@ -645,11 +600,6 @@ z90crypt_init_module(void)
} else
PRINTK("No devices at startup\n");
-#ifdef Z90CRYPT_USE_HOTPLUG
- /* generate hotplug event for device node generation */
- z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_ADD);
-#endif
-
/* Initialize globals. */
spin_lock_init(&queuespinlock);
@@ -701,17 +651,10 @@ z90crypt_init_module(void)
return 0; // success
init_module_cleanup:
-#ifndef Z90CRYPT_USE_HOTPLUG
if ((nresult = misc_deregister(&z90crypt_misc_device)))
PRINTK("misc_deregister failed with %d.\n", nresult);
else
PDEBUG("misc_deregister successful.\n");
-#else
- if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
- PRINTK("unregister_chrdev failed with %d.\n", nresult);
- else
- PDEBUG("unregister_chrdev successful.\n");
-#endif
return result; // failure
}
@@ -728,19 +671,10 @@ z90crypt_cleanup_module(void)
remove_proc_entry("driver/z90crypt", 0);
-#ifndef Z90CRYPT_USE_HOTPLUG
if ((nresult = misc_deregister(&z90crypt_misc_device)))
PRINTK("misc_deregister failed with %d.\n", nresult);
else
PDEBUG("misc_deregister successful.\n");
-#else
- z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_REMOVE);
-
- if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
- PRINTK("unregister_chrdev failed with %d.\n", nresult);
- else
- PDEBUG("unregister_chrdev successful.\n");
-#endif
/* Remove the tasks */
tasklet_kill(&reader_tasklet);
@@ -748,6 +682,9 @@ z90crypt_cleanup_module(void)
del_timer(&config_timer);
del_timer(&cleanup_timer);
+ if (z90_device_work)
+ destroy_workqueue(z90_device_work);
+
destroy_z90crypt();
PRINTKN("Unloaded.\n");
@@ -766,8 +703,6 @@ z90crypt_cleanup_module(void)
* z90crypt_status_write
* disable_card
* enable_card
- * scan_char
- * scan_string
*
* Helper functions:
* z90crypt_rsa
@@ -1057,9 +992,10 @@ remove_device(struct device *device_p)
* The MCL must be applied and the newer bitlengths enabled for these to work.
*
* Card Type Old limit New limit
+ * PCICA ??-2048 same (the lower limit is less than 128 bit...)
* PCICC 512-1024 512-2048
- * PCIXCC_MCL2 512-2048 no change (applying this MCL == card is MCL3+)
- * PCIXCC_MCL3 512-2048 128-2048
+ * PCIXCC_MCL2 512-2048 ----- (applying any GA LIC will make an MCL3 card)
+ * PCIXCC_MCL3 ----- 128-2048
* CEX2C 512-2048 128-2048
*
* ext_bitlens (extended bitlengths) is a global, since you should not apply an
@@ -1104,7 +1040,7 @@ select_device_type(int *dev_type_p, int bytelength)
if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail) {
/**
* bitlength is a factor, PCICA is the most capable, even with
- * the new MCL.
+ * the new MCL for PCIXCC.
*/
if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
(!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
@@ -2144,73 +2080,15 @@ enable_card(int card_index)
z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
}
-static inline int
-scan_char(unsigned char *bf, unsigned int len,
- unsigned int *offs, unsigned int *p_eof, unsigned char c)
-{
- unsigned int i, found;
-
- found = 0;
- for (i = 0; i < len; i++) {
- if (bf[i] == c) {
- found = 1;
- break;
- }
- if (bf[i] == '\0') {
- *p_eof = 1;
- break;
- }
- if (bf[i] == '\n') {
- break;
- }
- }
- *offs = i+1;
- return found;
-}
-
-static inline int
-scan_string(unsigned char *bf, unsigned int len,
- unsigned int *offs, unsigned int *p_eof, unsigned char *s)
-{
- unsigned int temp_len, temp_offs, found, eof;
-
- temp_len = temp_offs = found = eof = 0;
- while (!eof && !found) {
- found = scan_char(bf+temp_len, len-temp_len,
- &temp_offs, &eof, *s);
-
- temp_len += temp_offs;
- if (eof) {
- found = 0;
- break;
- }
-
- if (found) {
- if (len >= temp_offs+strlen(s)) {
- found = !strncmp(bf+temp_len-1, s, strlen(s));
- if (found) {
- *offs = temp_len+strlen(s)-1;
- break;
- }
- } else {
- found = 0;
- *p_eof = 1;
- break;
- }
- }
- }
- return found;
-}
-
static int
z90crypt_status_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
- int i, j, len, offs, found, eof;
- unsigned char *lbuf;
+ int j, eol;
+ unsigned char *lbuf, *ptr;
unsigned int local_count;
-#define LBUFSIZE 600
+#define LBUFSIZE 1200
lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
if (!lbuf) {
PRINTK("kmalloc failed!\n");
@@ -2227,49 +2105,46 @@ z90crypt_status_write(struct file *file, const char __user *buffer,
return -EFAULT;
}
- lbuf[local_count-1] = '\0';
+ lbuf[local_count] = '\0';
- len = 0;
- eof = 0;
- found = 0;
- while (!eof) {
- found = scan_string(lbuf+len, local_count-len, &offs, &eof,
- "Online devices");
- len += offs;
- if (found == 1)
- break;
+ ptr = strstr(lbuf, "Online devices");
+ if (ptr == 0) {
+ PRINTK("Unable to parse data (missing \"Online devices\")\n");
+ kfree(lbuf);
+ return count;
}
- if (eof) {
+ ptr = strstr(ptr, "\n");
+ if (ptr == 0) {
+ PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
kfree(lbuf);
return count;
}
+ ptr++;
- if (found)
- found = scan_char(lbuf+len, local_count-len, &offs, &eof, '\n');
-
- if (!found || eof) {
+ if (strstr(ptr, "Waiting work element counts") == NULL) {
+ PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
kfree(lbuf);
return count;
}
- len += offs;
j = 0;
- for (i = 0; i < 80; i++) {
- switch (*(lbuf+len+i)) {
+ eol = 0;
+ while ((j < 64) && (*ptr != '\0')) {
+ switch (*ptr) {
case '\t':
case ' ':
break;
case '\n':
default:
- eof = 1;
+ eol = 1;
break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
+ case '0': // no device
+ case '1': // PCICA
+ case '2': // PCICC
+ case '3': // PCIXCC_MCL2
+ case '4': // PCIXCC_MCL3
+ case '5': // CEX2C
j++;
break;
case 'd':
@@ -2283,8 +2158,9 @@ z90crypt_status_write(struct file *file, const char __user *buffer,
j++;
break;
}
- if (eof)
+ if (eol)
break;
+ ptr++;
}
kfree(lbuf);
@@ -3479,45 +3355,5 @@ probe_PCIXCC_type(struct device *devPtr)
return rv;
}
-#ifdef Z90CRYPT_USE_HOTPLUG
-static void
-z90crypt_hotplug_event(int dev_major, int dev_minor, int action)
-{
-#ifdef CONFIG_HOTPLUG
- char *argv[3];
- char *envp[6];
- char major[20];
- char minor[20];
-
- sprintf(major, "MAJOR=%d", dev_major);
- sprintf(minor, "MINOR=%d", dev_minor);
-
- argv[0] = hotplug_path;
- argv[1] = "z90crypt";
- argv[2] = 0;
-
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- switch (action) {
- case Z90CRYPT_HOTPLUG_ADD:
- envp[2] = "ACTION=add";
- break;
- case Z90CRYPT_HOTPLUG_REMOVE:
- envp[2] = "ACTION=remove";
- break;
- default:
- BUG();
- break;
- }
- envp[3] = major;
- envp[4] = minor;
- envp[5] = 0;
-
- call_usermodehelper(argv[0], argv, envp, 0);
-#endif
-}
-#endif
-
module_init(z90crypt_init_module);
module_exit(z90crypt_cleanup_module);
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 008e0a5d2eb3..3a0285669adf 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -824,7 +824,7 @@ extern struct list_head qeth_notify_list;
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
-inline static __u8
+static inline __u8
qeth_get_ipa_adp_type(enum qeth_link_types link_type)
{
switch (link_type) {
@@ -835,7 +835,7 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type)
}
}
-inline static int
+static inline int
qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
{
struct sk_buff *new_skb = NULL;
@@ -852,6 +852,7 @@ qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
}
return 0;
}
+
static inline struct sk_buff *
qeth_pskb_unshare(struct sk_buff *skb, int pri)
{
@@ -863,8 +864,7 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri)
return nskb;
}
-
-inline static void *
+static inline void *
qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
{
void *hdr;
@@ -887,7 +887,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
}
-inline static int
+static inline int
qeth_get_hlen(__u8 link_type)
{
#ifdef CONFIG_QETH_IPV6
@@ -911,7 +911,7 @@ qeth_get_hlen(__u8 link_type)
#endif /* CONFIG_QETH_IPV6 */
}
-inline static unsigned short
+static inline unsigned short
qeth_get_netdev_flags(struct qeth_card *card)
{
if (card->options.layer2)
@@ -929,7 +929,7 @@ qeth_get_netdev_flags(struct qeth_card *card)
}
}
-inline static int
+static inline int
qeth_get_initial_mtu_for_card(struct qeth_card * card)
{
switch (card->info.type) {
@@ -950,7 +950,7 @@ qeth_get_initial_mtu_for_card(struct qeth_card * card)
}
}
-inline static int
+static inline int
qeth_get_max_mtu_for_card(int cardtype)
{
switch (cardtype) {
@@ -965,7 +965,7 @@ qeth_get_max_mtu_for_card(int cardtype)
}
}
-inline static int
+static inline int
qeth_get_mtu_out_of_mpc(int cardtype)
{
switch (cardtype) {
@@ -976,7 +976,7 @@ qeth_get_mtu_out_of_mpc(int cardtype)
}
}
-inline static int
+static inline int
qeth_get_mtu_outof_framesize(int framesize)
{
switch (framesize) {
@@ -993,7 +993,7 @@ qeth_get_mtu_outof_framesize(int framesize)
}
}
-inline static int
+static inline int
qeth_mtu_is_valid(struct qeth_card * card, int mtu)
{
switch (card->info.type) {
@@ -1008,7 +1008,7 @@ qeth_mtu_is_valid(struct qeth_card * card, int mtu)
}
}
-inline static int
+static inline int
qeth_get_arphdr_type(int cardtype, int linktype)
{
switch (cardtype) {
@@ -1027,7 +1027,7 @@ qeth_get_arphdr_type(int cardtype, int linktype)
}
#ifdef CONFIG_QETH_PERF_STATS
-inline static int
+static inline int
qeth_get_micros(void)
{
return (int) (get_clock() >> 12);
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 3cb88c770037..79c74f3a11f5 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -2210,7 +2210,7 @@ no_mem:
return NULL;
}
-static inline unsigned short
+static inline __be16
qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct qeth_card *card;
@@ -8120,20 +8120,22 @@ static struct notifier_block qeth_ip6_notifier = {
#endif
static int
-qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
+__qeth_reboot_event_card(struct device *dev, void *data)
{
-
- struct device *entry;
struct qeth_card *card;
- down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
- list_for_each_entry(entry, &qeth_ccwgroup_driver.driver.devices,
- driver_list) {
- card = (struct qeth_card *) entry->driver_data;
- qeth_clear_ip_list(card, 0, 0);
- qeth_qdio_clear_card(card, 0);
- }
- up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+ card = (struct qeth_card *) dev->driver_data;
+ qeth_clear_ip_list(card, 0, 0);
+ qeth_qdio_clear_card(card, 0);
+ return 0;
+}
+
+static int
+qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+
+ driver_for_each_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
+ __qeth_reboot_event_card);
return NOTIFY_DONE;
}
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 04719196fd20..f2ccfea8fdb8 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -27,23 +27,33 @@ const char *VERSION_QETH_PROC_C = "$Revision: 1.13 $";
#define QETH_PROCFILE_NAME "qeth"
static struct proc_dir_entry *qeth_procfile;
+static int
+qeth_procfile_seq_match(struct device *dev, void *data)
+{
+ return 1;
+}
+
static void *
qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
- struct list_head *next_card = NULL;
- int i = 0;
+ struct device *dev;
+ loff_t nr;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
- if (*offset == 0)
+ nr = *offset;
+ if (nr == 0)
return SEQ_START_TOKEN;
- /* get card at pos *offset */
- list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices)
- if (++i == *offset)
- return next_card;
+ dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL,
+ NULL, qeth_procfile_seq_match);
- return NULL;
+ /* get card at pos *offset */
+ nr = *offset;
+ while (nr-- > 1 && dev)
+ dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
+ NULL, qeth_procfile_seq_match);
+ return (void *) dev;
}
static void
@@ -55,23 +65,21 @@ qeth_procfile_seq_stop(struct seq_file *s, void* it)
static void *
qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
- struct list_head *next_card = NULL;
- struct list_head *current_card;
+ struct device *prev, *next;
if (it == SEQ_START_TOKEN) {
- next_card = qeth_ccwgroup_driver.driver.devices.next;
- if (next_card->next == next_card) /* list empty */
- return NULL;
- (*offset)++;
- } else {
- current_card = (struct list_head *)it;
- if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
- return NULL; /* end of list reached */
- next_card = current_card->next;
- (*offset)++;
+ next = driver_find_device(&qeth_ccwgroup_driver.driver,
+ NULL, NULL, qeth_procfile_seq_match);
+ if (next)
+ (*offset)++;
+ return (void *) next;
}
-
- return next_card;
+ prev = (struct device *) it;
+ next = driver_find_device(&qeth_ccwgroup_driver.driver,
+ prev, NULL, qeth_procfile_seq_match);
+ if (next)
+ (*offset)++;
+ return (void *) next;
}
static inline const char *
@@ -126,7 +134,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it)
"-------------- ---- ------ ---------- ---- "
"---- ----- -----\n");
} else {
- device = list_entry(it, struct device, driver_list);
+ device = (struct device *) it;
card = device->driver_data;
seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ",
CARD_RDEV_ID(card),
@@ -180,17 +188,20 @@ static struct proc_dir_entry *qeth_perf_procfile;
static void *
qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
- struct list_head *next_card = NULL;
- int i = 0;
+ struct device *dev = NULL;
+ int nr;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
/* get card at pos *offset */
- list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
- if (i == *offset)
- return next_card;
- i++;
- }
- return NULL;
+ dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
+ qeth_procfile_seq_match);
+
+ /* get card at pos *offset */
+ nr = *offset;
+ while (nr-- > 1 && dev)
+ dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
+ NULL, qeth_procfile_seq_match);
+ return (void *) dev;
}
static void
@@ -202,12 +213,14 @@ qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
static void *
qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
- struct list_head *current_card = (struct list_head *)it;
+ struct device *prev, *next;
- if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
- return NULL; /* end of list reached */
- (*offset)++;
- return current_card->next;
+ prev = (struct device *) it;
+ next = driver_find_device(&qeth_ccwgroup_driver.driver, prev,
+ NULL, qeth_procfile_seq_match);
+ if (next)
+ (*offset)++;
+ return (void *) next;
}
static int
@@ -216,7 +229,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
struct device *device;
struct qeth_card *card;
- device = list_entry(it, struct device, driver_list);
+ device = (struct device *) it;
card = device->driver_data;
seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
CARD_RDEV_ID(card),
@@ -318,8 +331,8 @@ static struct proc_dir_entry *qeth_ipato_procfile;
static void *
qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
- struct list_head *next_card = NULL;
- int i = 0;
+ struct device *dev;
+ loff_t nr;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
/* TODO: finish this */
@@ -328,13 +341,16 @@ qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
* output driver settings then;
* else output setting for respective card
*/
+
+ dev = driver_find_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
+ qeth_procfile_seq_match);
+
/* get card at pos *offset */
- list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
- if (i == *offset)
- return next_card;
- i++;
- }
- return NULL;
+ nr = *offset;
+ while (nr-- > 1 && dev)
+ dev = driver_find_device(&qeth_ccwgroup_driver.driver, dev,
+ NULL, qeth_procfile_seq_match);
+ return (void *) dev;
}
static void
@@ -346,18 +362,14 @@ qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
static void *
qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
- struct list_head *current_card = (struct list_head *)it;
+ struct device *prev, *next;
- /* TODO: finish this */
- /*
- * maybe SEQ_SATRT_TOKEN can be returned for offset 0
- * output driver settings then;
- * else output setting for respective card
- */
- if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
- return NULL; /* end of list reached */
- (*offset)++;
- return current_card->next;
+ prev = (struct device *) it;
+ next = driver_find_device(&qeth_ccwgroup_driver.driver, prev,
+ NULL, qeth_procfile_seq_match);
+ if (next)
+ (*offset)++;
+ return (void *) next;
}
static int
@@ -372,7 +384,7 @@ qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
* output driver settings then;
* else output setting for respective card
*/
- device = list_entry(it, struct device, driver_list);
+ device = (struct device *) it;
card = device->driver_data;
return 0;
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 5bb255e02acc..4191fd9d4d11 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -240,7 +240,7 @@ s390_revalidate_registers(struct mci *mci)
* Floating point control register can't be restored.
* Task will be terminated.
*/
- asm volatile ("lfpc 0(%0)" : : "a" (&zero));
+ asm volatile ("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
kill_task = 1;
}
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index e17b4d58a9f6..bfe3ba73bc0f 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -1299,13 +1299,10 @@ struct zfcp_port *
zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status,
u32 d_id)
{
- struct zfcp_port *port, *tmp_port;
+ struct zfcp_port *port;
int check_wwpn;
- scsi_id_t scsi_id;
- int found;
check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN);
-
/*
* check that there is no port with this WWPN already in list
*/
@@ -1368,7 +1365,7 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status,
} else {
snprintf(port->sysfs_device.bus_id,
BUS_ID_SIZE, "0x%016llx", wwpn);
- port->sysfs_device.parent = &adapter->ccw_device->dev;
+ port->sysfs_device.parent = &adapter->ccw_device->dev;
}
port->sysfs_device.release = zfcp_sysfs_port_release;
dev_set_drvdata(&port->sysfs_device, port);
@@ -1388,24 +1385,8 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status,
zfcp_port_get(port);
- scsi_id = 1;
- found = 0;
write_lock_irq(&zfcp_data.config_lock);
- list_for_each_entry(tmp_port, &adapter->port_list_head, list) {
- if (atomic_test_mask(ZFCP_STATUS_PORT_NO_SCSI_ID,
- &tmp_port->status))
- continue;
- if (tmp_port->scsi_id != scsi_id) {
- found = 1;
- break;
- }
- scsi_id++;
- }
- port->scsi_id = scsi_id;
- if (found)
- list_add_tail(&port->list, &tmp_port->list);
- else
- list_add_tail(&port->list, &adapter->port_list_head);
+ list_add_tail(&port->list, &adapter->port_list_head);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status);
if (d_id == ZFCP_DID_DIRECTORY_SERVICE)
@@ -1427,6 +1408,9 @@ zfcp_port_dequeue(struct zfcp_port *port)
list_del(&port->list);
port->adapter->ports--;
write_unlock_irq(&zfcp_data.config_lock);
+ if (port->rport)
+ fc_remote_port_delete(port->rport);
+ port->rport = NULL;
zfcp_adapter_put(port->adapter);
zfcp_sysfs_port_remove_files(&port->sysfs_device,
atomic_read(&port->status));
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 0fc46381fc22..b30abab77da3 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -202,9 +202,19 @@ static int
zfcp_ccw_set_offline(struct ccw_device *ccw_device)
{
struct zfcp_adapter *adapter;
+ struct zfcp_port *port;
+ struct fc_rport *rport;
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
+ /* might be racy, but we cannot take config_lock due to the fact that
+ fc_remote_port_delete might sleep */
+ list_for_each_entry(port, &adapter->port_list_head, list)
+ if (port->rport) {
+ rport = port->rport;
+ port->rport = NULL;
+ fc_remote_port_delete(rport);
+ }
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
zfcp_adapter_scsi_unregister(adapter);
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 4103b5be7683..455e902533a9 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -906,6 +906,7 @@ struct zfcp_adapter {
*/
struct zfcp_port {
struct device sysfs_device; /* sysfs device */
+ struct fc_rport *rport; /* rport of fc transport class */
struct list_head list; /* list of remote ports */
atomic_t refcount; /* reference count */
wait_queue_head_t remove_wq; /* can be used to wait for
@@ -916,7 +917,6 @@ struct zfcp_port {
list */
u32 units; /* # of logical units in list */
atomic_t status; /* status of this remote port */
- scsi_id_t scsi_id; /* own SCSI ID */
wwn_t wwnn; /* WWNN if known */
wwn_t wwpn; /* WWPN */
fc_id_t d_id; /* D_ID */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 0cf31f7d1c0f..cb4f612550ba 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -3360,13 +3360,32 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
if ((result == ZFCP_ERP_SUCCEEDED)
&& (!atomic_test_mask(ZFCP_STATUS_UNIT_TEMPORARY,
&unit->status))
- && (!unit->device))
- scsi_add_device(unit->port->adapter->scsi_host, 0,
- unit->port->scsi_id, unit->scsi_lun);
+ && !unit->device
+ && port->rport)
+ scsi_add_device(port->adapter->scsi_host, 0,
+ port->rport->scsi_target_id,
+ unit->scsi_lun);
zfcp_unit_put(unit);
break;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
case ZFCP_ERP_ACTION_REOPEN_PORT:
+ if ((result == ZFCP_ERP_SUCCEEDED)
+ && !atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN,
+ &port->status)
+ && !port->rport) {
+ struct fc_rport_identifiers ids;
+ ids.node_name = port->wwnn;
+ ids.port_name = port->wwpn;
+ ids.port_id = port->d_id;
+ ids.roles = FC_RPORT_ROLE_FCP_TARGET;
+ port->rport =
+ fc_remote_port_add(adapter->scsi_host, 0, &ids);
+ if (!port->rport)
+ ZFCP_LOG_NORMAL("failed registration of rport"
+ "(adapter %s, wwpn=0x%016Lx)\n",
+ zfcp_get_busid_by_port(port),
+ port->wwpn);
+ }
zfcp_port_put(port);
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 42df7e57eeae..cd98a2de9f8f 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -143,6 +143,8 @@ extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *,
struct scsi_cmnd *, struct timer_list *);
extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *,
struct timer_list *);
+extern void zfcp_set_fc_host_attrs(struct zfcp_adapter *);
+extern void zfcp_set_fc_rport_attrs(struct zfcp_port *);
extern struct scsi_transport_template *zfcp_transport_template;
extern struct fc_function_template zfcp_transport_functions;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 0d9f20edc490..c007b6424e74 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -2062,6 +2062,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
zfcp_erp_adapter_shutdown(adapter, 0);
return -EIO;
}
+ zfcp_set_fc_host_attrs(adapter);
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index b61d309352c3..31a76065cf28 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -389,7 +389,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id,
struct zfcp_unit *unit, *retval = NULL;
list_for_each_entry(port, &adapter->port_list_head, list) {
- if (id != port->scsi_id)
+ if (!port->rport || (id != port->rport->scsi_target_id))
continue;
list_for_each_entry(unit, &port->unit_list_head, list) {
if (lun == unit->scsi_lun) {
@@ -408,7 +408,7 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list) {
- if (id == port->scsi_id)
+ if (port->rport && (id == port->rport->scsi_target_id))
return port;
}
return (struct zfcp_port *) NULL;
@@ -634,7 +634,6 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
int retval;
struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata;
- struct Scsi_Host *scsi_host = scpnt->device->host;
if (!unit) {
ZFCP_LOG_NORMAL("bug: Tried reset for nonexistent unit\n");
@@ -729,7 +728,6 @@ zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
{
int retval = 0;
struct zfcp_unit *unit;
- struct Scsi_Host *scsi_host = scpnt->device->host;
unit = (struct zfcp_unit *) scpnt->device->hostdata;
ZFCP_LOG_NORMAL("bus reset because of problems with "
@@ -753,7 +751,6 @@ zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
int retval = 0;
struct zfcp_unit *unit;
- struct Scsi_Host *scsi_host = scpnt->device->host;
unit = (struct zfcp_unit *) scpnt->device->hostdata;
ZFCP_LOG_NORMAL("host reset because of problems with "
@@ -833,6 +830,7 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
shost = adapter->scsi_host;
if (!shost)
return;
+ fc_remove_host(shost);
scsi_remove_host(shost);
scsi_host_put(shost);
adapter->scsi_host = NULL;
@@ -906,6 +904,18 @@ zfcp_get_node_name(struct scsi_target *starget)
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
}
+void
+zfcp_set_fc_host_attrs(struct zfcp_adapter *adapter)
+{
+ struct Scsi_Host *shost = adapter->scsi_host;
+
+ fc_host_node_name(shost) = adapter->wwnn;
+ fc_host_port_name(shost) = adapter->wwpn;
+ strncpy(fc_host_serial_number(shost), adapter->serial_number,
+ min(FC_SERIAL_NUMBER_SIZE, 32));
+ fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
+}
+
struct fc_function_template zfcp_transport_functions = {
.get_starget_port_id = zfcp_get_port_id,
.get_starget_port_name = zfcp_get_port_name,
@@ -913,6 +923,11 @@ struct fc_function_template zfcp_transport_functions = {
.show_starget_port_id = 1,
.show_starget_port_name = 1,
.show_starget_node_name = 1,
+ .show_rport_supported_classes = 1,
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_serial_number = 1,
};
/**
diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c
index 7a84c7d474d9..c55e82d91deb 100644
--- a/drivers/s390/scsi/zfcp_sysfs_port.c
+++ b/drivers/s390/scsi/zfcp_sysfs_port.c
@@ -67,7 +67,6 @@ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL);
ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status));
ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn);
ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id);
-ZFCP_DEFINE_PORT_ATTR(scsi_id, "0x%x\n", port->scsi_id);
ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask
(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status));
ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask
@@ -263,7 +262,6 @@ static struct attribute_group zfcp_port_common_attr_group = {
static struct attribute *zfcp_port_no_ns_attrs[] = {
&dev_attr_unit_add.attr,
&dev_attr_unit_remove.attr,
- &dev_attr_scsi_id.attr,
NULL
};