aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/pktcdvd.c82
-rw-r--r--drivers/char/agp/Kconfig55
-rw-r--r--drivers/char/agp/amd64-agp.c6
-rw-r--r--drivers/char/agp/sworks-agp.c4
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/fc4/fc.c2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c14
-rw-r--r--drivers/net/irda/irda-usb.c90
-rw-r--r--drivers/net/irda/irda-usb.h7
-rw-r--r--drivers/net/wireless/ipw2200.c6
-rw-r--r--drivers/s390/block/Kconfig14
-rw-r--r--drivers/s390/block/Makefile2
-rw-r--r--drivers/s390/block/dasd.c97
-rw-r--r--drivers/s390/block/dasd_3990_erp.c3
-rw-r--r--drivers/s390/block/dasd_eckd.h1
-rw-r--r--drivers/s390/block/dasd_eer.c1090
-rw-r--r--drivers/s390/block/dasd_int.h38
-rw-r--r--drivers/s390/cio/qdio.c13
-rw-r--r--drivers/spi/spi.c5
-rw-r--r--drivers/video/aty/radeon_pm.c19
20 files changed, 202 insertions, 1348 deletions
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 93e44d0292ab7a..bc9b2bcd7dba71 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -58,6 +58,7 @@
#include <linux/suspend.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi.h>
#include <asm/uaccess.h>
@@ -380,6 +381,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
+ rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
rq->ref_count++;
rq->flags |= REQ_NOMERGE;
@@ -1495,40 +1497,42 @@ static int pkt_set_write_settings(struct pktcdvd_device *pd)
}
/*
- * 0 -- we can write to this track, 1 -- we can't
+ * 1 -- we can write to this track, 0 -- we can't
*/
-static int pkt_good_track(track_information *ti)
+static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
{
- /*
- * only good for CD-RW at the moment, not DVD-RW
- */
+ switch (pd->mmc3_profile) {
+ case 0x1a: /* DVD+RW */
+ case 0x12: /* DVD-RAM */
+ /* The track is always writable on DVD+RW/DVD-RAM */
+ return 1;
+ default:
+ break;
+ }
- /*
- * FIXME: only for FP
- */
- if (ti->fp == 0)
+ if (!ti->packet || !ti->fp)
return 0;
/*
* "good" settings as per Mt Fuji.
*/
- if (ti->rt == 0 && ti->blank == 0 && ti->packet == 1)
- return 0;
+ if (ti->rt == 0 && ti->blank == 0)
+ return 1;
- if (ti->rt == 0 && ti->blank == 1 && ti->packet == 1)
- return 0;
+ if (ti->rt == 0 && ti->blank == 1)
+ return 1;
- if (ti->rt == 1 && ti->blank == 0 && ti->packet == 1)
- return 0;
+ if (ti->rt == 1 && ti->blank == 0)
+ return 1;
printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
- return 1;
+ return 0;
}
/*
- * 0 -- we can write to this disc, 1 -- we can't
+ * 1 -- we can write to this disc, 0 -- we can't
*/
-static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
+static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
{
switch (pd->mmc3_profile) {
case 0x0a: /* CD-RW */
@@ -1537,10 +1541,10 @@ static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
case 0x1a: /* DVD+RW */
case 0x13: /* DVD-RW */
case 0x12: /* DVD-RAM */
- return 0;
+ return 1;
default:
VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
- return 1;
+ return 0;
}
/*
@@ -1549,25 +1553,25 @@ static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
*/
if (di->disc_type == 0xff) {
printk("pktcdvd: Unknown disc. No track?\n");
- return 1;
+ return 0;
}
if (di->disc_type != 0x20 && di->disc_type != 0) {
printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
- return 1;
+ return 0;
}
if (di->erasable == 0) {
printk("pktcdvd: Disc not erasable\n");
- return 1;
+ return 0;
}
if (di->border_status == PACKET_SESSION_RESERVED) {
printk("pktcdvd: Can't write to last track (reserved)\n");
- return 1;
+ return 0;
}
- return 0;
+ return 1;
}
static int pkt_probe_settings(struct pktcdvd_device *pd)
@@ -1592,23 +1596,9 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
return ret;
}
- if (pkt_good_disc(pd, &di))
- return -ENXIO;
+ if (!pkt_writable_disc(pd, &di))
+ return -EROFS;
- switch (pd->mmc3_profile) {
- case 0x1a: /* DVD+RW */
- printk("pktcdvd: inserted media is DVD+RW\n");
- break;
- case 0x13: /* DVD-RW */
- printk("pktcdvd: inserted media is DVD-RW\n");
- break;
- case 0x12: /* DVD-RAM */
- printk("pktcdvd: inserted media is DVD-RAM\n");
- break;
- default:
- printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");
- break;
- }
pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;
track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
@@ -1617,9 +1607,9 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
return ret;
}
- if (pkt_good_track(&ti)) {
+ if (!pkt_writable_track(pd, &ti)) {
printk("pktcdvd: can't write to this track\n");
- return -ENXIO;
+ return -EROFS;
}
/*
@@ -1633,7 +1623,7 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
}
if (pd->settings.size > PACKET_MAX_SECTORS) {
printk("pktcdvd: packet size is too big\n");
- return -ENXIO;
+ return -EROFS;
}
pd->settings.fp = ti.fp;
pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);
@@ -1675,7 +1665,7 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
break;
default:
printk("pktcdvd: unknown data mode\n");
- return 1;
+ return -EROFS;
}
return 0;
}
@@ -1886,7 +1876,7 @@ static int pkt_open_write(struct pktcdvd_device *pd)
if ((ret = pkt_probe_settings(pd))) {
VPRINTK("pktcdvd: %s failed probe\n", pd->name);
- return -EROFS;
+ return ret;
}
if ((ret = pkt_set_write_settings(pd))) {
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 486ed8a11b5921..a4d425d2dce2de 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -15,22 +15,23 @@ config AGP
due to kernel allocation issues), you could use PCI accesses
and have up to a couple gigs of texture space.
- Note that this is the only means to have XFree4/GLX use
+ Note that this is the only means to have X/GLX use
write-combining with MTRR support on the AGP bus. Without it, OpenGL
direct rendering will be a lot slower but still faster than PIO.
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N.
-
To compile this driver as a module, choose M here: the
module will be called agpgart.
+ You should say Y here if you want to use GLX or DRI.
+
+ If unsure, say N.
+
config AGP_ALI
tristate "ALI chipset support"
depends on AGP && X86_32
---help---
This option gives you AGP support for the GLX component of
- XFree86 4.x on the following ALi chipsets. The supported chipsets
+ X on the following ALi chipsets. The supported chipsets
include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
For the ALi-chipset question, ALi suggests you refer to
<http://www.ali.com.tw/eng/support/index.shtml>.
@@ -40,28 +41,19 @@ config AGP_ALI
timing issues, this chipset cannot do AGP 2x with the G200.
This is a hardware limitation. AGP 1x seems to be fine, though.
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N.
-
config AGP_ATI
tristate "ATI chipset support"
depends on AGP && X86_32
---help---
- This option gives you AGP support for the GLX component of
- XFree86 4.x on the ATI RadeonIGP family of chipsets.
-
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N.
+ This option gives you AGP support for the GLX component of
+ X on the ATI RadeonIGP family of chipsets.
config AGP_AMD
tristate "AMD Irongate, 761, and 762 chipset support"
depends on AGP && X86_32
help
This option gives you AGP support for the GLX component of
- XFree86 4.x on AMD Irongate, 761, and 762 chipsets.
-
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N.
+ X on AMD Irongate, 761, and 762 chipsets.
config AGP_AMD64
tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU
@@ -69,45 +61,38 @@ config AGP_AMD64
default y if GART_IOMMU
help
This option gives you AGP support for the GLX component of
- XFree86 4.x using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
+ X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
You still need an external AGP bridge like the AMD 8151, VIA
K8T400M, SiS755. It may also support other AGP bridges when loaded
with agp_try_unsupported=1.
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say Y
config AGP_INTEL
tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
depends on AGP && X86
help
- This option gives you AGP support for the GLX component of XFree86 4.x
+ This option gives you AGP support for the GLX component of X
on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
- E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G,
- 852GM, 855GM, 865G and I915 integrated graphics chipsets.
+ E7205 and E7505 chipsets and full support for the 810, 815, 830M,
+ 845G, 852GM, 855GM, 865G and I915 integrated graphics chipsets.
+
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI, or if you have any Intel integrated graphics
- chipsets. If unsure, say Y.
config AGP_NVIDIA
tristate "NVIDIA nForce/nForce2 chipset support"
depends on AGP && X86_32
help
This option gives you AGP support for the GLX component of
- XFree86 4.x on the following NVIDIA chipsets. The supported chipsets
- include nForce and nForce2
+ X on NVIDIA chipsets including nForce and nForce2
config AGP_SIS
tristate "SiS chipset support"
depends on AGP && X86_32
help
This option gives you AGP support for the GLX component of
- XFree86 4.x on Silicon Integrated Systems [SiS] chipsets.
+ X on Silicon Integrated Systems [SiS] chipsets.
Note that 5591/5592 AGP chipsets are NOT supported.
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N.
config AGP_SWORKS
tristate "Serverworks LE/HE chipset support"
@@ -121,10 +106,7 @@ config AGP_VIA
depends on AGP && X86_32
help
This option gives you AGP support for the GLX component of
- XFree86 4.x on VIA MVP3/Apollo Pro chipsets.
-
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say N.
+ X on VIA MVP3/Apollo Pro chipsets.
config AGP_I460
tristate "Intel 460GX chipset support"
@@ -159,9 +141,6 @@ config AGP_EFFICEON
This option gives you AGP support for the Transmeta Efficeon
series processors with integrated northbridges.
- You should say Y here if you use XFree86 3.3.6 or 4.x and want to
- use GLX or DRI. If unsure, say Y.
-
config AGP_SGI_TIOCA
tristate "SGI TIO chipset AGP support"
depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC)
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 9964c508c1113e..1251b2515bbea9 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -516,8 +516,10 @@ static int __devinit nforce3_agp_init(struct pci_dev *pdev)
pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase);
/* if x86-64 aperture base is beyond 4G, exit here */
- if ( (apbase & 0x7fff) >> (32 - 25) )
- return -ENODEV;
+ if ( (apbase & 0x7fff) >> (32 - 25) ) {
+ printk(KERN_INFO PFX "aperture base > 4G\n");
+ return -ENODEV;
+ }
apbase = (apbase & 0x7fff) << 25;
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 268f78d926d337..efef9999f1cfaf 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -468,9 +468,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
switch (pdev->device) {
case 0x0006:
- /* ServerWorks CNB20HE
- Fail silently.*/
- printk (KERN_ERR PFX "Detected ServerWorks CNB20HE chipset: No AGP present.\n");
+ printk (KERN_ERR PFX "ServerWorks CNB20HE is unsupported due to lack of documentation.\n");
return -ENODEV;
case PCI_DEVICE_ID_SERVERWORKS_HE:
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 5765f672e853b5..d58f8231885396 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -243,7 +243,7 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(void *ignored)
{
- out_of_memory(GFP_KERNEL, 0);
+ out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0);
}
static DECLARE_WORK(moom_work, moom_callback, NULL);
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index 5c8943509cc1b7..66d03f242d3ce7 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -1053,7 +1053,7 @@ static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len)
int i;
fcmd = &_fcmd;
- memset(fcmd, 0, sizeof(fcmd));
+ memset(fcmd, 0, sizeof(fcp_cmnd));
FCD(("PLOGI SID %d DID %d\n", fc->sid, alpa))
fch = &fcmd->fch;
FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, alpa);
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 69c04945591f93..ded2c33f5b853a 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -1019,8 +1019,8 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
#define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
-#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
- UDELAY(map, chip, adr, usec)
+#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \
+ UDELAY(map, chip, cmd_adr, usec)
/*
* Extra notes:
@@ -1052,7 +1052,7 @@ do { \
spin_lock(chip->mutex); \
} while (0)
-#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \
do { \
spin_unlock(chip->mutex); \
INVALIDATE_CACHED_RANGE(map, adr, len); \
@@ -1284,7 +1284,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
map_write(map, datum, adr);
chip->state = mode;
- INVALIDATE_CACHE_UDELAY(map, chip,
+ INVALIDATE_CACHE_UDELAY(map, chip, adr,
adr, map_bankwidth(map),
chip->word_write_time);
@@ -1572,8 +1572,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- INVALIDATE_CACHE_UDELAY(map, chip,
- cmd_adr, len,
+ INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr,
+ adr, len,
chip->buffer_write_time);
timeo = jiffies + (HZ/2);
@@ -1744,7 +1744,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- INVALIDATE_CACHE_UDELAY(map, chip,
+ INVALIDATE_CACHE_UDELAY(map, chip, adr,
adr, len,
chip->erase_time*1000/2);
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index fa176ffb4ad525..8936058a3ccee9 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -108,6 +108,7 @@ static void irda_usb_close(struct irda_usb_cb *self);
static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs);
static void write_bulk_callback(struct urb *urb, struct pt_regs *regs);
static void irda_usb_receive(struct urb *urb, struct pt_regs *regs);
+static void irda_usb_rx_defer_expired(unsigned long data);
static int irda_usb_net_open(struct net_device *dev);
static int irda_usb_net_close(struct net_device *dev);
static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -677,6 +678,12 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* on the interrupt pipe and hang the Rx URB only when an interrupt is
* received.
* Jean II
+ *
+ * Note : don't read the above as what we are currently doing, but as
+ * something we could do with KC dongle. Also don't forget that the
+ * interrupt pipe is not part of the original standard, so this would
+ * need to be optional...
+ * Jean II
*/
/*------------------------------------------------------------------*/
@@ -704,10 +711,8 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struc
/* Reinitialize URB */
usb_fill_bulk_urb(urb, self->usbdev,
usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep),
- skb->data, skb->truesize,
+ skb->data, IRDA_SKB_MAX_MTU,
irda_usb_receive, skb);
- /* Note : unlink *must* be synchronous because of the code in
- * irda_usb_net_close() -> free the skb - Jean II */
urb->status = 0;
/* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */
@@ -734,6 +739,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
struct irda_skb_cb *cb;
struct sk_buff *newskb;
struct sk_buff *dataskb;
+ struct urb *next_urb;
int docopy;
IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
@@ -755,20 +761,37 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
if (urb->status != 0) {
switch (urb->status) {
case -EILSEQ:
- self->stats.rx_errors++;
self->stats.rx_crc_errors++;
- break;
+ /* Also precursor to a hot-unplug on UHCI. */
+ /* Fallthrough... */
case -ECONNRESET: /* -104 */
- IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, urb->transfer_flags);
+ /* Random error, if I remember correctly */
/* uhci_cleanup_unlink() is going to kill the Rx
* URB just after we return. No problem, at this
* point the URB will be idle ;-) - Jean II */
- break;
+ case -ESHUTDOWN: /* -108 */
+ /* That's usually a hot-unplug. Submit will fail... */
+ case -ETIMEDOUT: /* -110 */
+ /* Usually precursor to a hot-unplug on OHCI. */
default:
- IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags);
+ self->stats.rx_errors++;
+ IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags);
break;
}
- goto done;
+ /* If we received an error, we don't want to resubmit the
+ * Rx URB straight away but to give the USB layer a little
+ * bit of breathing room.
+ * We are in the USB thread context, therefore there is a
+ * danger of recursion (new URB we submit fails, we come
+ * back here).
+ * With recent USB stack (2.6.15+), I'm seeing that on
+ * hot unplug of the dongle...
+ * Lowest effective timer is 10ms...
+ * Jean II */
+ self->rx_defer_timer.function = &irda_usb_rx_defer_expired;
+ self->rx_defer_timer.data = (unsigned long) urb;
+ mod_timer(&self->rx_defer_timer, jiffies + (10 * HZ / 1000));
+ return;
}
/* Check for empty frames */
@@ -845,13 +868,45 @@ done:
* idle slot....
* Jean II */
/* Note : with this scheme, we could submit the idle URB before
- * processing the Rx URB. Another time... Jean II */
+ * processing the Rx URB. I don't think it would buy us anything as
+ * we are running in the USB thread context. Jean II */
+ next_urb = self->idle_rx_urb;
- /* Submit the idle URB to replace the URB we've just received */
- irda_usb_submit(self, skb, self->idle_rx_urb);
/* Recycle Rx URB : Now, the idle URB is the present one */
urb->context = NULL;
self->idle_rx_urb = urb;
+
+ /* Submit the idle URB to replace the URB we've just received.
+ * Do it last to avoid race conditions... Jean II */
+ irda_usb_submit(self, skb, next_urb);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * In case of errors, we want the USB layer to have time to recover.
+ * Now, it is time to resubmit ouur Rx URB...
+ */
+static void irda_usb_rx_defer_expired(unsigned long data)
+{
+ struct urb *urb = (struct urb *) data;
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct irda_usb_cb *self;
+ struct irda_skb_cb *cb;
+ struct urb *next_urb;
+
+ IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+ /* Find ourselves */
+ cb = (struct irda_skb_cb *) skb->cb;
+ IRDA_ASSERT(cb != NULL, return;);
+ self = (struct irda_usb_cb *) cb->context;
+ IRDA_ASSERT(self != NULL, return;);
+
+ /* Same stuff as when Rx is done, see above... */
+ next_urb = self->idle_rx_urb;
+ urb->context = NULL;
+ self->idle_rx_urb = urb;
+ irda_usb_submit(self, skb, next_urb);
}
/*------------------------------------------------------------------*/
@@ -990,6 +1045,9 @@ static int irda_usb_net_close(struct net_device *netdev)
/* Stop network Tx queue */
netif_stop_queue(netdev);
+ /* Kill defered Rx URB */
+ del_timer(&self->rx_defer_timer);
+
/* Deallocate all the Rx path buffers (URBs and skb) */
for (i = 0; i < IU_MAX_RX_URBS; i++) {
struct urb *urb = self->rx_urb[i];
@@ -1365,6 +1423,7 @@ static int irda_usb_probe(struct usb_interface *intf,
self = net->priv;
self->netdev = net;
spin_lock_init(&self->lock);
+ init_timer(&self->rx_defer_timer);
/* Create all of the needed urbs */
for (i = 0; i < IU_MAX_RX_URBS; i++) {
@@ -1498,6 +1557,9 @@ static void irda_usb_disconnect(struct usb_interface *intf)
* This will stop/desactivate the Tx path. - Jean II */
self->present = 0;
+ /* Kill defered Rx URB */
+ del_timer(&self->rx_defer_timer);
+
/* We need to have irq enabled to unlink the URBs. That's OK,
* at this point the Tx path is gone - Jean II */
spin_unlock_irqrestore(&self->lock, flags);
@@ -1507,11 +1569,11 @@ static void irda_usb_disconnect(struct usb_interface *intf)
/* Accept no more transmissions */
/*netif_device_detach(self->netdev);*/
netif_stop_queue(self->netdev);
- /* Stop all the receive URBs */
+ /* Stop all the receive URBs. Must be synchronous. */
for (i = 0; i < IU_MAX_RX_URBS; i++)
usb_kill_urb(self->rx_urb[i]);
/* Cancel Tx and speed URB.
- * Toggle flags to make sure it's synchronous. */
+ * Make sure it's synchronous to avoid races. */
usb_kill_urb(self->tx_urb);
usb_kill_urb(self->speed_urb);
}
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index bd8f66542322fa..4026af42dd47da 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -136,8 +136,6 @@ struct irda_usb_cb {
__u16 bulk_out_mtu; /* Max Tx packet size in bytes */
__u8 bulk_int_ep; /* Interrupt Endpoint assignments */
- wait_queue_head_t wait_q; /* for timeouts */
-
struct urb *rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */
struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */
struct urb *tx_urb; /* URB used to send data frames */
@@ -147,17 +145,18 @@ struct irda_usb_cb {
struct net_device_stats stats;
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos;
- hashbin_t *tx_list; /* Queued transmit skb's */
char *speed_buff; /* Buffer for speed changes */
struct timeval stamp;
struct timeval now;
- spinlock_t lock; /* For serializing operations */
+ spinlock_t lock; /* For serializing Tx operations */
__u16 xbofs; /* Current xbofs setting */
__s16 new_xbofs; /* xbofs we need to set */
__u32 speed; /* Current speed */
__s32 new_speed; /* speed we need to set */
+
+ struct timer_list rx_defer_timer; /* Wait for Rx error to clear */
};
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 14beab4bc91cba..287676ad80df82 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -4616,9 +4616,9 @@ static void ipw_rx_notification(struct ipw_priv *priv,
}
default:
- IPW_ERROR("Unknown notification: "
- "subtype=%d,flags=0x%2x,size=%d\n",
- notif->subtype, notif->flags, notif->size);
+ IPW_DEBUG_NOTIF("Unknown notification: "
+ "subtype=%d,flags=0x%2x,size=%d\n",
+ notif->subtype, notif->flags, notif->size);
}
}
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 6912399d093709..6f50cc9323d959 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -55,21 +55,13 @@ config DASD_DIAG
Disks under VM. If you are not running under VM or unsure what it is,
say "N".
-config DASD_EER
- tristate "Extended error reporting (EER)"
- depends on DASD
- help
- This driver provides a character device interface to the
- DASD extended error reporting. This is only needed if you want to
- use applications written for the EER facility.
-
config DASD_CMB
tristate "Compatibility interface for DASD channel measurement blocks"
depends on DASD
help
- This driver provides an additional interface to the channel
- measurement facility, which is normally accessed though sysfs, with
- a set of ioctl functions specific to the dasd driver.
+ This driver provides an additional interface to the channel measurement
+ facility, which is normally accessed though sysfs, with a set of
+ ioctl functions specific to the dasd driver.
This is only needed if you want to use applications written for
linux-2.4 dasd channel measurement facility interface.
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
index 0c0d871e8f512f..58c6780134f748 100644
--- a/drivers/s390/block/Makefile
+++ b/drivers/s390/block/Makefile
@@ -5,7 +5,6 @@
dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
dasd_diag_mod-objs := dasd_diag.o
-dasd_eer_mod-objs := dasd_eer.o
dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
dasd_genhd.o dasd_erp.o
@@ -14,6 +13,5 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o
obj-$(CONFIG_DASD_CMB) += dasd_cmb.o
-obj-$(CONFIG_DASD_EER) += dasd_eer.o
obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
obj-$(CONFIG_DCSSBLK) += dcssblk.o
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 08c88fcd896339..af1d5b404cee3f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
-#include <linux/notifier.h>
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
@@ -58,7 +57,6 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data);
-static void dasd_disable_eer(struct dasd_device *device);
/*
* SECTION: Operations on the device structure.
@@ -153,10 +151,13 @@ dasd_state_new_to_known(struct dasd_device *device)
static inline void
dasd_state_known_to_new(struct dasd_device * device)
{
- /* disable extended error reporting for this device */
- dasd_disable_eer(device);
/* Forget the discipline information. */
+ if (device->discipline)
+ module_put(device->discipline->owner);
device->discipline = NULL;
+ if (device->base_discipline)
+ module_put(device->base_discipline->owner);
+ device->base_discipline = NULL;
device->state = DASD_STATE_NEW;
dasd_free_queue(device);
@@ -871,9 +872,6 @@ dasd_handle_state_change_pending(struct dasd_device *device)
struct dasd_ccw_req *cqr;
struct list_head *l, *n;
- /* first of all call extended error reporting */
- dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
-
device->stopped &= ~DASD_STOPPED_PENDING;
/* restart all 'running' IO on queue */
@@ -1093,19 +1091,6 @@ restart:
}
goto restart;
}
-
- /* first of all call extended error reporting */
- if (device->eer && cqr->status == DASD_CQR_FAILED) {
- dasd_write_eer_trigger(DASD_EER_FATALERROR,
- device, cqr);
-
- /* restart request */
- cqr->status = DASD_CQR_QUEUED;
- cqr->retries = 255;
- device->stopped |= DASD_STOPPED_QUIESCE;
- goto restart;
- }
-
/* Process finished ERP request. */
if (cqr->refers) {
__dasd_process_erp(device, cqr);
@@ -1243,8 +1228,7 @@ __dasd_start_head(struct dasd_device * device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
/* check FAILFAST */
if (device->stopped & ~DASD_STOPPED_PENDING &&
- test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
- (!device->eer)) {
+ test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) {
cqr->status = DASD_CQR_FAILED;
dasd_schedule_bh(device);
}
@@ -1880,9 +1864,10 @@ dasd_generic_remove (struct ccw_device *cdev)
*/
int
dasd_generic_set_online (struct ccw_device *cdev,
- struct dasd_discipline *discipline)
+ struct dasd_discipline *base_discipline)
{
+ struct dasd_discipline *discipline;
struct dasd_device *device;
int rc;
@@ -1890,6 +1875,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
if (IS_ERR(device))
return PTR_ERR(device);
+ discipline = base_discipline;
if (device->features & DASD_FEATURE_USEDIAG) {
if (!dasd_diag_discipline_pointer) {
printk (KERN_WARNING
@@ -1901,6 +1887,16 @@ dasd_generic_set_online (struct ccw_device *cdev,
}
discipline = dasd_diag_discipline_pointer;
}
+ if (!try_module_get(base_discipline->owner)) {
+ dasd_delete_device(device);
+ return -EINVAL;
+ }
+ if (!try_module_get(discipline->owner)) {
+ module_put(base_discipline->owner);
+ dasd_delete_device(device);
+ return -EINVAL;
+ }
+ device->base_discipline = base_discipline;
device->discipline = discipline;
rc = discipline->check_device(device);
@@ -1909,6 +1905,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
"dasd_generic couldn't online device %s "
"with discipline %s rc=%i\n",
cdev->dev.bus_id, discipline->name, rc);
+ module_put(discipline->owner);
+ module_put(base_discipline->owner);
dasd_delete_device(device);
return rc;
}
@@ -1986,9 +1984,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
switch (event) {
case CIO_GONE:
case CIO_NO_PATH:
- /* first of all call extended error reporting */
- dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
-
if (device->state < DASD_STATE_BASIC)
break;
/* Device is active. We want to keep it. */
@@ -2046,51 +2041,6 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
put_driver(drv);
}
-/*
- * notifications for extended error reports
- */
-static struct notifier_block *dasd_eer_chain;
-
-int
-dasd_register_eer_notifier(struct notifier_block *nb)
-{
- return notifier_chain_register(&dasd_eer_chain, nb);
-}
-
-int
-dasd_unregister_eer_notifier(struct notifier_block *nb)
-{
- return notifier_chain_unregister(&dasd_eer_chain, nb);
-}
-
-/*
- * Notify the registered error reporting module of a problem
- */
-void
-dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
- struct dasd_ccw_req *cqr)
-{
- if (device->eer) {
- struct dasd_eer_trigger temp;
- temp.id = id;
- temp.device = device;
- temp.cqr = cqr;
- notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
- (void *)&temp);
- }
-}
-
-/*
- * Tell the registered error reporting module to disable error reporting for
- * a given device and to cleanup any private data structures on that device.
- */
-static void
-dasd_disable_eer(struct dasd_device *device)
-{
- notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
-}
-
-
static int __init
dasd_init(void)
{
@@ -2172,11 +2122,6 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
-EXPORT_SYMBOL(dasd_register_eer_notifier);
-EXPORT_SYMBOL(dasd_unregister_eer_notifier);
-EXPORT_SYMBOL(dasd_write_eer_trigger);
-
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index c811380b907967..4ee0f934e32538 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1108,9 +1108,6 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
case 0x0B:
DEV_MESSAGE(KERN_WARNING, device, "%s",
"FORMAT F - Volume is suspended duplex");
- /* call extended error reporting (EER) */
- dasd_write_eer_trigger(DASD_EER_PPRCSUSPEND, device,
- erp->refers);
break;
case 0x0C:
DEV_MESSAGE(KERN_WARNING, device, "%s",
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index e15dd79780509d..bc3823d3522336 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -29,7 +29,6 @@
#define DASD_ECKD_CCW_PSF 0x27
#define DASD_ECKD_CCW_RSSD 0x3e
#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
-#define DASD_ECKD_CCW_SNSS 0x54
#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
#define DASD_ECKD_CCW_WRITE_MT 0x85
#define DASD_ECKD_CCW_READ_MT 0x86
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
deleted file mode 100644
index f70cd7716b2446..00000000000000
--- a/drivers/s390/block/dasd_eer.c
+++ /dev/null
@@ -1,1090 +0,0 @@
-/*
- * character device driver for extended error reporting
- *
- *
- * Copyright (C) 2005 IBM Corporation
- * extended error reporting for DASD ECKD devices
- * Author(s): Stefan Weinhuber <wein@de.ibm.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <linux/notifier.h>
-
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
-#include <asm/atomic.h>
-#include <asm/ebcdic.h>
-
-#include "dasd_int.h"
-#include "dasd_eckd.h"
-
-
-MODULE_LICENSE("GPL");
-
-MODULE_AUTHOR("Stefan Weinhuber <wein@de.ibm.com>");
-MODULE_DESCRIPTION("DASD extended error reporting module");
-
-
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(eer):"
-
-
-
-
-
-/*****************************************************************************/
-/* the internal buffer */
-/*****************************************************************************/
-
-/*
- * The internal buffer is meant to store obaque blobs of data, so it doesn't
- * know of higher level concepts like triggers.
- * It consists of a number of pages that are used as a ringbuffer. Each data
- * blob is stored in a simple record that consists of an integer, which
- * contains the size of the following data, and the data bytes themselfes.
- *
- * To allow for multiple independent readers we create one internal buffer
- * each time the device is opened and destroy the buffer when the file is
- * closed again.
- *
- * One record can be written to a buffer by using the functions
- * - dasd_eer_start_record (one time per record to write the size to the buffer
- * and reserve the space for the data)
- * - dasd_eer_write_buffer (one or more times per record to write the data)
- * The data can be written in several steps but you will have to compute
- * the total size up front for the invocation of dasd_eer_start_record.
- * If the ringbuffer is full, dasd_eer_start_record will remove the required
- * number of old records.
- *
- * A record is typically read in two steps, first read the integer that
- * specifies the size of the following data, then read the data.
- * Both can be done by
- * - dasd_eer_read_buffer
- *
- * For all mentioned functions you need to get the bufferlock first and keep it
- * until a complete record is written or read.
- */
-
-
-/*
- * Alle information necessary to keep track of an internal buffer is kept in
- * a struct eerbuffer. The buffer specific to a file pointer is strored in
- * the private_data field of that file. To be able to write data to all
- * existing buffers, each buffer is also added to the bufferlist.
- * If the user doesn't want to read a complete record in one go, we have to
- * keep track of the rest of the record. residual stores the number of bytes
- * that are still to deliver. If the rest of the record is invalidated between
- * two reads then residual will be set to -1 so that the next read will fail.
- * All entries in the eerbuffer structure are protected with the bufferlock.
- * To avoid races between writing to a buffer on the one side and creating
- * and destroying buffers on the other side, the bufferlock must also be used
- * to protect the bufferlist.
- */
-
-struct eerbuffer {
- struct list_head list;
- char **buffer;
- int buffersize;
- int buffer_page_count;
- int head;
- int tail;
- int residual;
-};
-
-LIST_HEAD(bufferlist);
-
-static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
-
-DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
-
-/*
- * How many free bytes are available on the buffer.
- * needs to be called with bufferlock held
- */
-static int
-dasd_eer_get_free_bytes(struct eerbuffer *eerb)
-{
- if (eerb->head < eerb->tail) {
- return eerb->tail - eerb->head - 1;
- } else
- return eerb->buffersize - eerb->head + eerb->tail -1;
-}
-
-/*
- * How many bytes of buffer space are used.
- * needs to be called with bufferlock held
- */
-static int
-dasd_eer_get_filled_bytes(struct eerbuffer *eerb)
-{
-
- if (eerb->head >= eerb->tail) {
- return eerb->head - eerb->tail;
- } else
- return eerb->buffersize - eerb->tail + eerb->head;
-}
-
-/*
- * The dasd_eer_write_buffer function just copies count bytes of data
- * to the buffer. Make sure to call dasd_eer_start_record first, to
- * make sure that enough free space is available.
- * needs to be called with bufferlock held
- */
-static void
-dasd_eer_write_buffer(struct eerbuffer *eerb, int count, char *data)
-{
-
- unsigned long headindex,localhead;
- unsigned long rest, len;
- char *nextdata;
-
- nextdata = data;
- rest = count;
- while (rest > 0) {
- headindex = eerb->head / PAGE_SIZE;
- localhead = eerb->head % PAGE_SIZE;
- len = min(rest, (PAGE_SIZE - localhead));
- memcpy(eerb->buffer[headindex]+localhead, nextdata, len);
- nextdata += len;
- rest -= len;
- eerb->head += len;
- if ( eerb->head == eerb->buffersize )
- eerb->head = 0; /* wrap around */
- if (eerb->head > eerb->buffersize) {
- MESSAGE(KERN_ERR, "%s", "runaway buffer head.");
- BUG();
- }
- }
-}
-
-/*
- * needs to be called with bufferlock held
- */
-static int
-dasd_eer_read_buffer(struct eerbuffer *eerb, int count, char *data)
-{
-
- unsigned long tailindex,localtail;
- unsigned long rest, len, finalcount;
- char *nextdata;
-
- finalcount = min(count, dasd_eer_get_filled_bytes(eerb));
- nextdata = data;
- rest = finalcount;
- while (rest > 0) {
- tailindex = eerb->tail / PAGE_SIZE;
- localtail = eerb->tail % PAGE_SIZE;
- len = min(rest, (PAGE_SIZE - localtail));
- memcpy(nextdata, eerb->buffer[tailindex]+localtail, len);
- nextdata += len;
- rest -= len;
- eerb->tail += len;
- if ( eerb->tail == eerb->buffersize )
- eerb->tail = 0; /* wrap around */
- if (eerb->tail > eerb->buffersize) {
- MESSAGE(KERN_ERR, "%s", "runaway buffer tail.");
- BUG();
- }
- }
- return finalcount;
-}
-
-/*
- * Whenever you want to write a blob of data to the internal buffer you
- * have to start by using this function first. It will write the number
- * of bytes that will be written to the buffer. If necessary it will remove
- * old records to make room for the new one.
- * needs to be called with bufferlock held
- */
-static int
-dasd_eer_start_record(struct eerbuffer *eerb, int count)
-{
- int tailcount;
- if (count + sizeof(count) > eerb->buffersize)
- return -ENOMEM;
- while (dasd_eer_get_free_bytes(eerb) < count + sizeof(count)) {
- if (eerb->residual > 0) {
- eerb->tail += eerb->residual;
- if (eerb->tail >= eerb->buffersize)
- eerb->tail -= eerb->buffersize;
- eerb->residual = -1;
- }
- dasd_eer_read_buffer(eerb, sizeof(tailcount),
- (char*)(&tailcount));
- eerb->tail += tailcount;
- if (eerb->tail >= eerb->buffersize)
- eerb->tail -= eerb->buffersize;
- }
- dasd_eer_write_buffer(eerb, sizeof(count), (char*)(&count));
-
- return 0;
-};
-
-/*
- * release pages that are not used anymore
- */
-static void
-dasd_eer_free_buffer_pages(char **buf, int no_pages)
-{
- int i;
-
- for (i = 0; i < no_pages; ++i) {
- free_page((unsigned long)buf[i]);
- }
-}
-
-/*
- * allocate a new set of memory pages
- */
-static int
-dasd_eer_allocate_buffer_pages(char **buf, int no_pages)
-{
- int i;
-
- for (i = 0; i < no_pages; ++i) {
- buf[i] = (char *) get_zeroed_page(GFP_KERNEL);
- if (!buf[i]) {
- dasd_eer_free_buffer_pages(buf, i);
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-/*
- * empty the buffer by resetting head and tail
- * In case there is a half read data blob in the buffer, we set residual
- * to -1 to indicate that the remainder of the blob is lost.
- */
-static void
-dasd_eer_purge_buffer(struct eerbuffer *eerb)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&bufferlock, flags);
- if (eerb->residual > 0)
- eerb->residual = -1;
- eerb->tail=0;
- eerb->head=0;
- spin_unlock_irqrestore(&bufferlock, flags);
-}
-
-/*
- * set the size of the buffer, newsize is the new number of pages to be used
- * we don't try to copy any data back an forth, so any resize will also purge
- * the buffer
- */
-static int
-dasd_eer_resize_buffer(struct eerbuffer *eerb, int newsize)
-{
- int i, oldcount, reuse;
- char **new;
- char **old;
- unsigned long flags;
-
- if (newsize < 1)
- return -EINVAL;
- if (eerb->buffer_page_count == newsize) {
- /* documented behaviour is that any successfull invocation
- * will purge all records */
- dasd_eer_purge_buffer(eerb);
- return 0;
- }
- new = kmalloc(newsize*sizeof(char*), GFP_KERNEL);
- if (!new)
- return -ENOMEM;
-
- reuse=min(eerb->buffer_page_count, newsize);
- for (i = 0; i < reuse; ++i) {
- new[i] = eerb->buffer[i];
- }
- if (eerb->buffer_page_count < newsize) {
- if (dasd_eer_allocate_buffer_pages(
- &new[eerb->buffer_page_count],
- newsize - eerb->buffer_page_count)) {
- kfree(new);
- return -ENOMEM;
- }
- }
-
- spin_lock_irqsave(&bufferlock, flags);
- old = eerb->buffer;
- eerb->buffer = new;
- if (eerb->residual > 0)
- eerb->residual = -1;
- eerb->tail = 0;
- eerb->head = 0;
- oldcount = eerb->buffer_page_count;
- eerb->buffer_page_count = newsize;
- spin_unlock_irqrestore(&bufferlock, flags);
-
- if (oldcount > newsize) {
- for (i = newsize; i < oldcount; ++i) {
- free_page((unsigned long)old[i]);
- }
- }
- kfree(old);
-
- return 0;
-}
-
-
-/*****************************************************************************/
-/* The extended error reporting functionality */
-/*****************************************************************************/
-
-/*
- * When a DASD device driver wants to report an error, it calls the
- * function dasd_eer_write_trigger (via a notifier mechanism) and gives the
- * respective trigger ID as parameter.
- * Currently there are four kinds of triggers:
- *
- * DASD_EER_FATALERROR: all kinds of unrecoverable I/O problems
- * DASD_EER_PPRCSUSPEND: PPRC was suspended
- * DASD_EER_NOPATH: There is no path to the device left.
- * DASD_EER_STATECHANGE: The state of the device has changed.
- *
- * For the first three triggers all required information can be supplied by
- * the caller. For these triggers a record is written by the function
- * dasd_eer_write_standard_trigger.
- *
- * When dasd_eer_write_trigger is called to write a DASD_EER_STATECHANGE
- * trigger, we have to gather the necessary sense data first. We cannot queue
- * the necessary SNSS (sense subsystem status) request immediatly, since we
- * are likely to run in a deadlock situation. Instead, we schedule a
- * work_struct that calls the function dasd_eer_sense_subsystem_status to
- * create and start an SNSS request asynchronously.
- *
- * To avoid memory allocations at runtime, the necessary memory is allocated
- * when the extended error reporting is enabled for a device (by
- * dasd_eer_probe). There is one private eer data structure for each eer
- * enabled DASD device. It contains memory for the work_struct, one SNSS cqr
- * and a flags field that is used to coordinate the use of the cqr. The call
- * to write a state change trigger can come in at any time, so we have one flag
- * CQR_IN_USE that protects the cqr itself. When this flag indicates that the
- * cqr is currently in use, dasd_eer_sense_subsystem_status cannot start a
- * second request but sets the SNSS_REQUESTED flag instead.
- *
- * When the request is finished, the callback function dasd_eer_SNSS_cb
- * is called. This function will invoke the function
- * dasd_eer_write_SNSS_trigger to finally write the trigger. It will also
- * check the SNSS_REQUESTED flag and if it is set it will call
- * dasd_eer_sense_subsystem_status again.
- *
- * To avoid race conditions during the handling of the lock, the flags must
- * be protected by the snsslock.
- */
-
-struct dasd_eer_private {
- struct dasd_ccw_req *cqr;
- unsigned long flags;
- struct work_struct worker;
-};
-
-static void dasd_eer_destroy(struct dasd_device *device,
- struct dasd_eer_private *eer);
-static int
-dasd_eer_write_trigger(struct dasd_eer_trigger *trigger);
-static void dasd_eer_sense_subsystem_status(void *data);
-static int dasd_eer_notify(struct notifier_block *self,
- unsigned long action, void *data);
-
-struct workqueue_struct *dasd_eer_workqueue;
-
-#define SNSS_DATA_SIZE 44
-static spinlock_t snsslock = SPIN_LOCK_UNLOCKED;
-
-#define DASD_EER_BUSID_SIZE 10
-struct dasd_eer_header {
- __u32 total_size;
- __u32 trigger;
- __u64 tv_sec;
- __u64 tv_usec;
- char busid[DASD_EER_BUSID_SIZE];
-} __attribute__ ((packed));
-
-static struct notifier_block dasd_eer_nb = {
- .notifier_call = dasd_eer_notify,
-};
-
-/*
- * flags for use with dasd_eer_private
- */
-#define CQR_IN_USE 0
-#define SNSS_REQUESTED 1
-
-/*
- * This function checks if extended error reporting is available for a given
- * dasd_device. If yes, then it creates and returns a struct dasd_eer,
- * otherwise it returns an -EPERM error pointer.
- */
-struct dasd_eer_private *
-dasd_eer_probe(struct dasd_device *device)
-{
- struct dasd_eer_private *private;
-
- if (!(device && device->discipline
- && !strcmp(device->discipline->name, "ECKD"))) {
- return ERR_PTR(-EPERM);
- }
- /* allocate the private data structure */
- private = (struct dasd_eer_private *)kmalloc(
- sizeof(struct dasd_eer_private), GFP_KERNEL);
- if (!private) {
- return ERR_PTR(-ENOMEM);
- }
- INIT_WORK(&private->worker, dasd_eer_sense_subsystem_status,
- (void *)device);
- private->cqr = dasd_kmalloc_request("ECKD",
- 1 /* SNSS */ ,
- SNSS_DATA_SIZE ,
- device);
- if (!private->cqr) {
- kfree(private);
- return ERR_PTR(-ENOMEM);
- }
- private->flags = 0;
- return private;
-};
-
-/*
- * If our private SNSS request is queued, remove it from the
- * dasd ccw queue so we can free the requests memory.
- */
-static void
-dasd_eer_dequeue_SNSS_request(struct dasd_device *device,
- struct dasd_eer_private *eer)
-{
- struct list_head *lst, *nxt;
- struct dasd_ccw_req *cqr, *erpcqr;
- dasd_erp_fn_t erp_fn;
-
- spin_lock_irq(get_ccwdev_lock(device->cdev));
- list_for_each_safe(lst, nxt, &device->ccw_queue) {
- cqr = list_entry(lst, struct dasd_ccw_req, list);
- /* we are looking for two kinds or requests */
- /* first kind: our SNSS request: */
- if (cqr == eer->cqr) {
- if (cqr->status == DASD_CQR_IN_IO)
- device->discipline->term_IO(cqr);
- list_del(&cqr->list);
- break;
- }
- /* second kind: ERP requests for our SNSS request */
- if (cqr->refers) {
- /* If this erp request chain ends in our cqr, then */
- /* cal the erp_postaction to clean it up */
- erpcqr = cqr;
- while (erpcqr->refers) {
- erpcqr = erpcqr->refers;
- }
- if (erpcqr == eer->cqr) {
- erp_fn = device->discipline->erp_postaction(
- cqr);
- erp_fn(cqr);
- }
- continue;
- }
- }
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
-}
-
-/*
- * This function dismantles a struct dasd_eer that was created by
- * dasd_eer_probe. Since we want to free our private data structure,
- * we must make sure that the memory is not in use anymore.
- * We have to flush the work queue and remove a possible SNSS request
- * from the dasd queue.
- */
-static void
-dasd_eer_destroy(struct dasd_device *device, struct dasd_eer_private *eer)
-{
- flush_workqueue(dasd_eer_workqueue);
- dasd_eer_dequeue_SNSS_request(device, eer);
- dasd_kfree_request(eer->cqr, device);
- kfree(eer);
-};
-
-/*
- * enable the extended error reporting for a particular device
- */
-static int
-dasd_eer_enable_on_device(struct dasd_device *device)
-{
- void *eer;
- if (!device)
- return -ENODEV;
- if (device->eer)
- return 0;
- if (!try_module_get(THIS_MODULE)) {
- return -EINVAL;
- }
- eer = (void *)dasd_eer_probe(device);
- if (IS_ERR(eer)) {
- module_put(THIS_MODULE);
- return PTR_ERR(eer);
- }
- device->eer = eer;
- return 0;
-}
-
-/*
- * enable the extended error reporting for a particular device
- */
-static int
-dasd_eer_disable_on_device(struct dasd_device *device)
-{
- struct dasd_eer_private *eer = device->eer;
-
- if (!device)
- return -ENODEV;
- if (!device->eer)
- return 0;
- device->eer = NULL;
- dasd_eer_destroy(device,eer);
- module_put(THIS_MODULE);
-
- return 0;
-}
-
-/*
- * Set extended error reporting (eer)
- * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
- */
-static int
-dasd_ioctl_set_eer(struct block_device *bdev, int no, long args)
-{
- struct dasd_device *device;
- int intval;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (bdev != bdev->bd_contains)
- /* Error-reporting is not allowed for partitions */
- return -EINVAL;
- if (get_user(intval, (int __user *) args))
- return -EFAULT;
- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
-
- intval = (intval != 0);
- DEV_MESSAGE (KERN_DEBUG, device,
- "set eer on device to %d", intval);
- if (intval)
- return dasd_eer_enable_on_device(device);
- else
- return dasd_eer_disable_on_device(device);
-}
-
-/*
- * Get value of extended error reporting.
- * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
- */
-static int
-dasd_ioctl_get_eer(struct block_device *bdev, int no, long args)
-{
- struct dasd_device *device;
-
- device = bdev->bd_disk->private_data;
- if (device == NULL)
- return -ENODEV;
- return put_user((device->eer != NULL), (int __user *) args);
-}
-
-/*
- * The following function can be used for those triggers that have
- * all necessary data available when the function is called.
- * If the parameter cqr is not NULL, the chain of requests will be searched
- * for valid sense data, and all valid sense data sets will be added to
- * the triggers data.
- */
-static int
-dasd_eer_write_standard_trigger(int trigger, struct dasd_device *device,
- struct dasd_ccw_req *cqr)
-{
- struct dasd_ccw_req *temp_cqr;
- int data_size;
- struct timeval tv;
- struct dasd_eer_header header;
- unsigned long flags;
- struct eerbuffer *eerb;
-
- /* go through cqr chain and count the valid sense data sets */
- temp_cqr = cqr;
- data_size = 0;
- while (temp_cqr) {
- if (temp_cqr->irb.esw.esw0.erw.cons)
- data_size += 32;
- temp_cqr = temp_cqr->refers;
- }
-
- header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
- header.trigger = trigger;
- do_gettimeofday(&tv);
- header.tv_sec = tv.tv_sec;
- header.tv_usec = tv.tv_usec;
- strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
-
- spin_lock_irqsave(&bufferlock, flags);
- list_for_each_entry(eerb, &bufferlist, list) {
- dasd_eer_start_record(eerb, header.total_size);
- dasd_eer_write_buffer(eerb, sizeof(header), (char*)(&header));
- temp_cqr = cqr;
- while (temp_cqr) {
- if (temp_cqr->irb.esw.esw0.erw.cons)
- dasd_eer_write_buffer(eerb, 32, cqr->irb.ecw);
- temp_cqr = temp_cqr->refers;
- }
- dasd_eer_write_buffer(eerb, 4,"EOR");
- }
- spin_unlock_irqrestore(&bufferlock, flags);
-
- wake_up_interruptible(&dasd_eer_read_wait_queue);
-
- return 0;
-}
-
-/*
- * This function writes a DASD_EER_STATECHANGE trigger.
- */
-static void
-dasd_eer_write_SNSS_trigger(struct dasd_device *device,
- struct dasd_ccw_req *cqr)
-{
- int data_size;
- int snss_rc;
- struct timeval tv;
- struct dasd_eer_header header;
- unsigned long flags;
- struct eerbuffer *eerb;
-
- snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
- if (snss_rc)
- data_size = 0;
- else
- data_size = SNSS_DATA_SIZE;
-
- header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
- header.trigger = DASD_EER_STATECHANGE;
- do_gettimeofday(&tv);
- header.tv_sec = tv.tv_sec;
- header.tv_usec = tv.tv_usec;
- strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
-
- spin_lock_irqsave(&bufferlock, flags);
- list_for_each_entry(eerb, &bufferlist, list) {
- dasd_eer_start_record(eerb, header.total_size);
- dasd_eer_write_buffer(eerb, sizeof(header),(char*)(&header));
- if (!snss_rc)
- dasd_eer_write_buffer(eerb, SNSS_DATA_SIZE, cqr->data);
- dasd_eer_write_buffer(eerb, 4,"EOR");
- }
- spin_unlock_irqrestore(&bufferlock, flags);
-
- wake_up_interruptible(&dasd_eer_read_wait_queue);
-}
-
-/*
- * callback function for use with SNSS request
- */
-static void
-dasd_eer_SNSS_cb(struct dasd_ccw_req *cqr, void *data)
-{
- struct dasd_device *device;
- struct dasd_eer_private *private;
- unsigned long irqflags;
-
- device = (struct dasd_device *)data;
- private = (struct dasd_eer_private *)device->eer;
- dasd_eer_write_SNSS_trigger(device, cqr);
- spin_lock_irqsave(&snsslock, irqflags);
- if(!test_and_clear_bit(SNSS_REQUESTED, &private->flags)) {
- clear_bit(CQR_IN_USE, &private->flags);
- spin_unlock_irqrestore(&snsslock, irqflags);
- return;
- };
- clear_bit(CQR_IN_USE, &private->flags);
- spin_unlock_irqrestore(&snsslock, irqflags);
- dasd_eer_sense_subsystem_status(device);
- return;
-}
-
-/*
- * clean a used cqr before using it again
- */
-static void
-dasd_eer_clean_SNSS_request(struct dasd_ccw_req *cqr)
-{
- struct ccw1 *cpaddr = cqr->cpaddr;
- void *data = cqr->data;
-
- memset(cqr, 0, sizeof(struct dasd_ccw_req));
- memset(cpaddr, 0, sizeof(struct ccw1));
- memset(data, 0, SNSS_DATA_SIZE);
- cqr->cpaddr = cpaddr;
- cqr->data = data;
- strncpy((char *) &cqr->magic, "ECKD", 4);
- ASCEBC((char *) &cqr->magic, 4);
- set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
-}
-
-/*
- * build and start an SNSS request
- * This function is called from a work queue so we have to
- * pass the dasd_device pointer as a void pointer.
- */
-static void
-dasd_eer_sense_subsystem_status(void *data)
-{
- struct dasd_device *device;
- struct dasd_eer_private *private;
- struct dasd_ccw_req *cqr;
- struct ccw1 *ccw;
- unsigned long irqflags;
-
- device = (struct dasd_device *)data;
- private = (struct dasd_eer_private *)device->eer;
- if (!private) /* device not eer enabled any more */
- return;
- cqr = private->cqr;
- spin_lock_irqsave(&snsslock, irqflags);
- if(test_and_set_bit(CQR_IN_USE, &private->flags)) {
- set_bit(SNSS_REQUESTED, &private->flags);
- spin_unlock_irqrestore(&snsslock, irqflags);
- return;
- };
- spin_unlock_irqrestore(&snsslock, irqflags);
- dasd_eer_clean_SNSS_request(cqr);
- cqr->device = device;
- cqr->retries = 255;
- cqr->expires = 10 * HZ;
-
- ccw = cqr->cpaddr;
- ccw->cmd_code = DASD_ECKD_CCW_SNSS;
- ccw->count = SNSS_DATA_SIZE;
- ccw->flags = 0;
- ccw->cda = (__u32)(addr_t)cqr->data;
-
- cqr->buildclk = get_clock();
- cqr->status = DASD_CQR_FILLED;
- cqr->callback = dasd_eer_SNSS_cb;
- cqr->callback_data = (void *)device;
- dasd_add_request_head(cqr);
-
- return;
-}
-
-/*
- * This function is called for all triggers. It calls the appropriate
- * function that writes the actual trigger records.
- */
-static int
-dasd_eer_write_trigger(struct dasd_eer_trigger *trigger)
-{
- int rc;
- struct dasd_eer_private *private = trigger->device->eer;
-
- switch (trigger->id) {
- case DASD_EER_FATALERROR:
- case DASD_EER_PPRCSUSPEND:
- rc = dasd_eer_write_standard_trigger(
- trigger->id, trigger->device, trigger->cqr);
- break;
- case DASD_EER_NOPATH:
- rc = dasd_eer_write_standard_trigger(
- trigger->id, trigger->device, NULL);
- break;
- case DASD_EER_STATECHANGE:
- if (queue_work(dasd_eer_workqueue, &private->worker)) {
- rc=0;
- } else {
- /* If the work_struct was already queued, it can't
- * be queued again. But this is OK since we don't
- * need to have it queued twice.
- */
- rc = -EBUSY;
- }
- break;
- default: /* unknown trigger, so we write it without any sense data */
- rc = dasd_eer_write_standard_trigger(
- trigger->id, trigger->device, NULL);
- break;
- }
- return rc;
-}
-
-/*
- * This function is registered with the dasd device driver and gets called
- * for all dasd eer notifications.
- */
-static int dasd_eer_notify(struct notifier_block *self,
- unsigned long action, void *data)
-{
- switch (action) {
- case DASD_EER_DISABLE:
- dasd_eer_disable_on_device((struct dasd_device *)data);
- break;
- case DASD_EER_TRIGGER:
- dasd_eer_write_trigger((struct dasd_eer_trigger *)data);
- break;
- }
- return NOTIFY_OK;
-}
-
-
-/*****************************************************************************/
-/* the device operations */
-/*****************************************************************************/
-
-/*
- * On the one side we need a lock to access our internal buffer, on the
- * other side a copy_to_user can sleep. So we need to copy the data we have
- * to transfer in a readbuffer, which is protected by the readbuffer_mutex.
- */
-static char readbuffer[PAGE_SIZE];
-DECLARE_MUTEX(readbuffer_mutex);
-
-
-static int
-dasd_eer_open(struct inode *inp, struct file *filp)
-{
- struct eerbuffer *eerb;
- unsigned long flags;
-
- eerb = kmalloc(sizeof(struct eerbuffer), GFP_KERNEL);
- eerb->head = 0;
- eerb->tail = 0;
- eerb->residual = 0;
- eerb->buffer_page_count = 1;
- eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE;
- eerb->buffer = kmalloc(eerb->buffer_page_count*sizeof(char*),
- GFP_KERNEL);
- if (!eerb->buffer)
- return -ENOMEM;
- if (dasd_eer_allocate_buffer_pages(eerb->buffer,
- eerb->buffer_page_count)) {
- kfree(eerb->buffer);
- return -ENOMEM;
- }
- filp->private_data = eerb;
- spin_lock_irqsave(&bufferlock, flags);
- list_add(&eerb->list, &bufferlist);
- spin_unlock_irqrestore(&bufferlock, flags);
-
- return nonseekable_open(inp,filp);
-}
-
-static int
-dasd_eer_close(struct inode *inp, struct file *filp)
-{
- struct eerbuffer *eerb;
- unsigned long flags;
-
- eerb = (struct eerbuffer *)filp->private_data;
- spin_lock_irqsave(&bufferlock, flags);
- list_del(&eerb->list);
- spin_unlock_irqrestore(&bufferlock, flags);
- dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count);
- kfree(eerb->buffer);
- kfree(eerb);
-
- return 0;
-}
-
-static long
-dasd_eer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- int intval;
- struct eerbuffer *eerb;
-
- eerb = (struct eerbuffer *)filp->private_data;
- switch (cmd) {
- case DASD_EER_PURGE:
- dasd_eer_purge_buffer(eerb);
- return 0;
- case DASD_EER_SETBUFSIZE:
- if (get_user(intval, (int __user *)arg))
- return -EFAULT;
- return dasd_eer_resize_buffer(eerb, intval);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-static ssize_t
-dasd_eer_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
-{
- int tc,rc;
- int tailcount,effective_count;
- unsigned long flags;
- struct eerbuffer *eerb;
-
- eerb = (struct eerbuffer *)filp->private_data;
- if(down_interruptible(&readbuffer_mutex))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&bufferlock, flags);
-
- if (eerb->residual < 0) { /* the remainder of this record */
- /* has been deleted */
- eerb->residual = 0;
- spin_unlock_irqrestore(&bufferlock, flags);
- up(&readbuffer_mutex);
- return -EIO;
- } else if (eerb->residual > 0) {
- /* OK we still have a second half of a record to deliver */
- effective_count = min(eerb->residual, (int)count);
- eerb->residual -= effective_count;
- } else {
- tc = 0;
- while (!tc) {
- tc = dasd_eer_read_buffer(eerb,
- sizeof(tailcount), (char*)(&tailcount));
- if (!tc) {
- /* no data available */
- spin_unlock_irqrestore(&bufferlock, flags);
- up(&readbuffer_mutex);
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- rc = wait_event_interruptible(
- dasd_eer_read_wait_queue,
- eerb->head != eerb->tail);
- if (rc) {
- return rc;
- }
- if(down_interruptible(&readbuffer_mutex))
- return -ERESTARTSYS;
- spin_lock_irqsave(&bufferlock, flags);
- }
- }
- WARN_ON(tc != sizeof(tailcount));
- effective_count = min(tailcount,(int)count);
- eerb->residual = tailcount - effective_count;
- }
-
- tc = dasd_eer_read_buffer(eerb, effective_count, readbuffer);
- WARN_ON(tc != effective_count);
-
- spin_unlock_irqrestore(&bufferlock, flags);
-
- if (copy_to_user(buf, readbuffer, effective_count)) {
- up(&readbuffer_mutex);
- return -EFAULT;
- }
-
- up(&readbuffer_mutex);
- return effective_count;
-}
-
-static unsigned int
-dasd_eer_poll (struct file *filp, poll_table *ptable)
-{
- unsigned int mask;
- unsigned long flags;
- struct eerbuffer *eerb;
-
- eerb = (struct eerbuffer *)filp->private_data;
- poll_wait(filp, &dasd_eer_read_wait_queue, ptable);
- spin_lock_irqsave(&bufferlock, flags);
- if (eerb->head != eerb->tail)
- mask = POLLIN | POLLRDNORM ;
- else
- mask = 0;
- spin_unlock_irqrestore(&bufferlock, flags);
- return mask;
-}
-
-static struct file_operations dasd_eer_fops = {
- .open = &dasd_eer_open,
- .release = &dasd_eer_close,
- .unlocked_ioctl = &dasd_eer_ioctl,
- .compat_ioctl = &dasd_eer_ioctl,
- .read = &dasd_eer_read,
- .poll = &dasd_eer_poll,
- .owner = THIS_MODULE,
-};
-
-static struct miscdevice dasd_eer_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "dasd_eer",
- .fops = &dasd_eer_fops,
-};
-
-
-/*****************************************************************************/
-/* Init and exit */
-/*****************************************************************************/
-
-static int
-__init dasd_eer_init(void)
-{
- int rc;
-
- dasd_eer_workqueue = create_singlethread_workqueue("dasd_eer");
- if (!dasd_eer_workqueue) {
- MESSAGE(KERN_ERR , "%s", "dasd_eer_init could not "
- "create workqueue \n");
- rc = -ENOMEM;
- goto out;
- }
-
- rc = dasd_register_eer_notifier(&dasd_eer_nb);
- if (rc) {
- MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
- "register error reporting");
- goto queue;
- }
-
- dasd_ioctl_no_register(THIS_MODULE, BIODASDEERSET, dasd_ioctl_set_eer);
- dasd_ioctl_no_register(THIS_MODULE, BIODASDEERGET, dasd_ioctl_get_eer);
-
- /* we don't need our own character device,
- * so we just register as misc device */
- rc = misc_register(&dasd_eer_dev);
- if (rc) {
- MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
- "register misc device");
- goto unregister;
- }
-
- return 0;
-
-unregister:
- dasd_unregister_eer_notifier(&dasd_eer_nb);
- dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
- dasd_ioctl_set_eer);
- dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
- dasd_ioctl_get_eer);
-queue:
- destroy_workqueue(dasd_eer_workqueue);
-out:
- return rc;
-
-}
-module_init(dasd_eer_init);
-
-static void
-__exit dasd_eer_exit(void)
-{
- dasd_unregister_eer_notifier(&dasd_eer_nb);
- dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
- dasd_ioctl_set_eer);
- dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
- dasd_ioctl_get_eer);
- destroy_workqueue(dasd_eer_workqueue);
-
- WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
-}
-module_exit(dasd_eer_exit);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index d1b08fa13fd224..0592354cc60431 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -275,34 +275,6 @@ struct dasd_discipline {
extern struct dasd_discipline *dasd_diag_discipline_pointer;
-
-/*
- * Notification numbers for extended error reporting notifications:
- * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's
- * eer pointer) is freed. The error reporting module needs to do all necessary
- * cleanup steps.
- * The DASD_EER_TRIGGER notification sends the actual error reports (triggers).
- */
-#define DASD_EER_DISABLE 0
-#define DASD_EER_TRIGGER 1
-
-/* Trigger IDs for extended error reporting DASD_EER_TRIGGER notification */
-#define DASD_EER_FATALERROR 1
-#define DASD_EER_NOPATH 2
-#define DASD_EER_STATECHANGE 3
-#define DASD_EER_PPRCSUSPEND 4
-
-/*
- * The dasd_eer_trigger structure contains all data that we need to send
- * along with an DASD_EER_TRIGGER notification.
- */
-struct dasd_eer_trigger {
- unsigned int id;
- struct dasd_device *device;
- struct dasd_ccw_req *cqr;
-};
-
-
struct dasd_device {
/* Block device stuff. */
struct gendisk *gdp;
@@ -316,11 +288,9 @@ struct dasd_device {
unsigned long flags; /* per device flags */
unsigned short features; /* copy of devmap-features (read-only!) */
- /* extended error reporting stuff (eer) */
- void *eer;
-
/* Device discipline stuff. */
struct dasd_discipline *discipline;
+ struct dasd_discipline *base_discipline;
char *private;
/* Device state and target state. */
@@ -519,12 +489,6 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_auto_online (struct ccw_driver *);
-int dasd_register_eer_notifier(struct notifier_block *);
-int dasd_unregister_eer_notifier(struct notifier_block *);
-void dasd_write_eer_trigger(unsigned int , struct dasd_device *,
- struct dasd_ccw_req *);
-
-
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 45ce032772f4e6..9ed37dc9a1b048 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -165,8 +165,13 @@ qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
q_no = q->q_no;
if(!q->is_input_q)
q_no += irq->no_input_qs;
+again:
ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt);
rc = qdio_check_ccq(q, ccq);
+ if (rc == 1) {
+ QDIO_DBF_TEXT5(1,trace,"eqAGAIN");
+ goto again;
+ }
if (rc < 0) {
QDIO_DBF_TEXT2(1,trace,"eqberr");
sprintf(dbf_text,"%2x,%2x,%d,%d",tmp_cnt, *cnt, ccq, q_no);
@@ -195,8 +200,13 @@ qdio_do_sqbs(struct qdio_q *q, unsigned char state,
q_no = q->q_no;
if(!q->is_input_q)
q_no += irq->no_input_qs;
+again:
ccq = do_sqbs(irq->sch_token, state, q_no, start, cnt);
rc = qdio_check_ccq(q, ccq);
+ if (rc == 1) {
+ QDIO_DBF_TEXT5(1,trace,"sqAGAIN");
+ goto again;
+ }
if (rc < 0) {
QDIO_DBF_TEXT3(1,trace,"sqberr");
sprintf(dbf_text,"%2x,%2x,%d,%d",tmp_cnt,*cnt,ccq,q_no);
@@ -1187,8 +1197,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
if (!no_used)
return 1;
-
- if (!q->siga_sync)
+ if (!q->siga_sync && !irq->is_qebsm)
/* we'll check for more primed buffers in qeth_stop_polling */
return 0;
if (irq->is_qebsm) {
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 791c4dc550aee0..94f5e8ed83a7a8 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -90,7 +90,7 @@ static int spi_suspend(struct device *dev, pm_message_t message)
int value;
struct spi_driver *drv = to_spi_driver(dev->driver);
- if (!drv->suspend)
+ if (!drv || !drv->suspend)
return 0;
/* suspend will stop irqs and dma; no more i/o */
@@ -105,7 +105,7 @@ static int spi_resume(struct device *dev)
int value;
struct spi_driver *drv = to_spi_driver(dev->driver);
- if (!drv->resume)
+ if (!drv || !drv->resume)
return 0;
/* resume may restart the i/o queue */
@@ -449,7 +449,6 @@ void spi_unregister_master(struct spi_master *master)
{
(void) device_for_each_child(master->cdev.dev, NULL, __unregister);
class_device_unregister(&master->cdev);
- master->cdev.dev = NULL;
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 556895e9964509..1f8d805c61e588 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -1321,8 +1321,6 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
mdelay( 15);
}
-#ifdef CONFIG_PPC_OF
-
static void radeon_pm_reset_pad_ctlr_strength(struct radeonfb_info *rinfo)
{
u32 tmp, tmp2;
@@ -1836,6 +1834,8 @@ static void radeon_reinitialize_M10(struct radeonfb_info *rinfo)
radeon_pm_m10_enable_lvds_spread_spectrum(rinfo);
}
+#ifdef CONFIG_PPC_OF
+
static void radeon_pm_m9p_reconfigure_mc(struct radeonfb_info *rinfo)
{
OUTREG(MC_CNTL, rinfo->save_regs[46]);
@@ -2728,13 +2728,23 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
printk("radeonfb: Dynamic Clock Power Management disabled\n");
}
+#if defined(CONFIG_PM)
/* Check if we can power manage on suspend/resume. We can do
* D2 on M6, M7 and M9, and we can resume from D3 cold a few other
* "Mac" cards, but that's all. We need more infos about what the
* BIOS does tho. Right now, all this PM stuff is pmac-only for that
* reason. --BenH
*/
-#if defined(CONFIG_PM) && defined(CONFIG_PPC_PMAC)
+ /* Special case for Samsung P35 laptops
+ */
+ if ((rinfo->pdev->vendor == PCI_VENDOR_ID_ATI) &&
+ (rinfo->pdev->device == PCI_CHIP_RV350_NP) &&
+ (rinfo->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG) &&
+ (rinfo->pdev->subsystem_device == 0xc00c)) {
+ rinfo->reinit_func = radeon_reinitialize_M10;
+ rinfo->pm_mode |= radeon_pm_off;
+ }
+#if defined(CONFIG_PPC_PMAC)
if (_machine == _MACH_Pmac && rinfo->of_node) {
if (rinfo->is_mobility && rinfo->pm_reg &&
rinfo->family <= CHIP_FAMILY_RV250)
@@ -2778,7 +2788,8 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
OUTREG(TV_DAC_CNTL, INREG(TV_DAC_CNTL) | 0x07000000);
#endif
}
-#endif /* defined(CONFIG_PM) && defined(CONFIG_PPC_PMAC) */
+#endif /* defined(CONFIG_PPC_PMAC) */
+#endif /* defined(CONFIG_PM) */
}
void radeonfb_pm_exit(struct radeonfb_info *rinfo)