lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4513B21A.30507@garzik.org>
Date:	Fri, 22 Sep 2006 05:51:22 -0400
From:	Jeff Garzik <jeff@...zik.org>
To:	Lennert Buytenhek <buytenh@...tstofly.org>
CC:	"linux-ide@...r.kernel.org" <linux-ide@...r.kernel.org>,
	Linux Kernel <linux-kernel@...r.kernel.org>,
	Alan Cox <alan@...rguk.ukuu.org.uk>,
	Andrew Morton <akpm@...l.org>
Subject: Re: PATA drivers queued for 2.6.19

Lennert Buytenhek wrote:
> On Mon, Sep 04, 2006 at 07:01:13AM -0400, Jeff Garzik wrote:
> 
>> * ARM, PPC and other non-x86 platform drivers are severely 
>> under-represented.
> 
> Allessandro Zummo sent the patch below to me a while ago, for support
> for the PATA controller (PIO only, although the hardware can also do
> UDMA) in the cirrus logic ep93xx ARM cpu.
> 
> The driver has bitrotted somewhat, and apart from that it never honored
> PIO timings properly and has some other issues, but Allessandro seems to
> have disappeared off the face of the planet.  I'd still like to see
> support for this go in at some point, so I'll have a try at cleaning it
> up and updating it (and converting it to a platform driver, etc.)

Please do, I'm definitely interested in it.

If you can diff against jgarzik/libata-dev.git#upstream, that would be 
most helpful.  That's where the other PATA drivers and API updates are, 
as well as a move of everything libata into drivers/ata.

I've included a few comments below, if they are of any help.


> Index: linux-2.6.16-rc5/drivers/scsi/Kconfig
> ===================================================================
> --- linux-2.6.16-rc5.orig/drivers/scsi/Kconfig
> +++ linux-2.6.16-rc5/drivers/scsi/Kconfig
> @@ -912,6 +912,10 @@ config SCSI_PATA_TS7200
>  	tristate "TS7200 Compact Flash support"
>  	depends on MACH_TS72XX
>  
> +config SCSI_PATA_EP93XX
> +	tristate "Cirrus Logic EP93XX PATA support"
> +	depends on ARCH_EP93XX
> +
>  config SCSI_BUSLOGIC
>  	tristate "BusLogic SCSI support"
>  	depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
> Index: linux-2.6.16-rc5/drivers/scsi/Makefile
> ===================================================================
> --- linux-2.6.16-rc5.orig/drivers/scsi/Makefile
> +++ linux-2.6.16-rc5/drivers/scsi/Makefile
> @@ -175,6 +175,7 @@ obj-$(CONFIG_SCSI_PATA_WINBOND)	+= libat
>  obj-$(CONFIG_SCSI_ATA_GENERIC)	+= libata.o ata_generic.o
>  obj-$(CONFIG_SCSI_PATA_LEGACY)	+= libata.o pata_legacy.o
>  obj-$(CONFIG_SCSI_PATA_TS7200)	+= libata.o pata_ts7200.o
> +obj-$(CONFIG_SCSI_PATA_EP93XX)		+= libata.o pata_ep93xx.o

this stuff moves to drivers/ata, and changes to CONFIG_PATA_xxx


> Index: linux-2.6.16-rc5/drivers/scsi/pata_ep93xx.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.16-rc5/drivers/scsi/pata_ep93xx.c
> @@ -0,0 +1,375 @@
> +/*
> + * EP93XX PATA controller driver.
> + * Copyright (c) 2006 Tower Technologies
> + * Author: Alessandro Zummo <a.zummo@...ertech.it>
> + *
> + * An ATA driver to handle the embedded IDE controller
> + * of the Cirrus Logic EP93XX.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/libata.h>
> +#include <scsi/scsi_host.h>
> +#include <linux/platform_device.h>
> +
> +#define DRV_NAME	"pata_ep93xx"
> +#define DRV_VERSION	"0.1"
> +
> +struct ata_host_set *ep93xx_host;

this should be stored in the platform_driver's driver_data area.

The code should be pretty darn close to the current libata PCI code, 
which uses pci_set_drvdata().


> +static inline void ep93xx_toggle_wr(register u32 ctrl)

no 'register', please

> +{
> +	ctrl &= ~(EP93XX_IDE_CTRL_DIOWn);
> +	__raw_writel(ctrl, EP93XX_IDE_CTRL);
> +
> +	ctrl |= EP93XX_IDE_CTRL_DIOWn;
> +	__raw_writel(ctrl, EP93XX_IDE_CTRL);
> +}
> +
> +static inline void ep93xx_toggle_rd(register u32 ctrl)

ditto


> +{
> +	ctrl &= ~(EP93XX_IDE_CTRL_DIORn);
> +	__raw_writel(ctrl, EP93XX_IDE_CTRL);
> +
> +	ctrl |= EP93XX_IDE_CTRL_DIORn;
> +	__raw_writel(ctrl, EP93XX_IDE_CTRL);
> +}
> +
> +#define ep93xx_write_addr(ctrl,addr) { \
> +	ctrl = (ctrl & ~(EP93XX_IDE_CTRL_DA_CS_MASK)) | EP93XX_IDE_CTRL_DA_CS(addr); \
> +	__raw_writel(ctrl, EP93XX_IDE_CTRL); }

this could be static inline too, AFAICS?


> +static inline void ep93xx_writew(register u16 value, volatile void __iomem *p)

no 'volatile' or 'register', please


> +{
> +	register u32 ctrl = __raw_readl(EP93XX_IDE_CTRL);
> +
> +	ep93xx_write_addr(ctrl, (unsigned long) p);
> +	__raw_writel(value, EP93XX_IDE_DATAOUT);
> +	ep93xx_toggle_wr(ctrl);
> +}
> +
> +#define ep93xx_writeb(value,addr) ep93xx_writew(value,addr)
> +
> +static inline unsigned short ep93xx_readw(volatile void __iomem *p)
> +{
> +	register u32 ctrl = __raw_readl(EP93XX_IDE_CTRL);

ditto


> +	ep93xx_write_addr(ctrl, (unsigned long) p);
> +	ep93xx_toggle_rd(ctrl);
> +	return __raw_readl(EP93XX_IDE_DATAIN);
> +}
> +
> +#define ep93xx_readb(addr) ep93xx_readw(addr)
> +
> +static unsigned int ep93xx_mode_filter(const struct ata_port *ap,
> +	struct ata_device *adev, unsigned int mask, int shift)
> +{
> +	if (shift != ATA_SHIFT_PIO)
> +		return 0;
> +	return mask;
> +}
> +
> +static void ep93xx_set_mode(struct ata_port *ap)
> +{
> +	int i;
> +
> +	for (i = 0; i < ATA_MAX_DEVICES; i++) {
> +		struct ata_device *dev = &ap->device[i];
> +		if (ata_dev_present(dev)) {
> +			dev->pio_mode = XFER_PIO_0;
> +			dev->xfer_mode = XFER_PIO_0;
> +			dev->xfer_shift = ATA_SHIFT_PIO;
> +			dev->flags |= ATA_DFLAG_PIO;
> +		}
> +	}
> +}
> +
> +static void ep93xx_phy_reset(struct ata_port *ap)
> +{
> +	ap->cbl = ATA_CBL_PATA40;
> +	ata_port_probe(ap);
> +	ata_bus_reset(ap);
> +}
> +
> +static void ep93xx_irq_clear(struct ata_port *ap)
> +{
> +}
> +
> +static void ep93xx_irq_on(struct ata_port *ap)
> +{
> +}
> +
> +static void ep93xx_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
> +{
> +	struct ata_ioports *ioaddr = &ap->ioaddr;
> +	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
> +
> +	if (tf->ctl != ap->last_ctl) {
> +		ep93xx_writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
> +		ap->last_ctl = tf->ctl;
> +		ata_wait_idle(ap);
> +	}
> +
> +	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
> +		ep93xx_writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
> +		ep93xx_writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
> +		ep93xx_writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
> +		ep93xx_writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
> +		ep93xx_writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
> +		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
> +			tf->hob_feature,
> +			tf->hob_nsect,
> +			tf->hob_lbal,
> +			tf->hob_lbam,
> +			tf->hob_lbah);
> +	}
> +
> +	if (is_addr) {
> +		ep93xx_writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
> +		ep93xx_writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
> +		ep93xx_writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
> +		ep93xx_writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
> +		ep93xx_writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
> +		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
> +			tf->feature,
> +			tf->nsect,
> +			tf->lbal,
> +			tf->lbam,
> +			tf->lbah);
> +	}
> +
> +	if (tf->flags & ATA_TFLAG_DEVICE) {
> +		ep93xx_writeb(tf->device, (void __iomem *) ioaddr->device_addr);
> +		VPRINTK("device 0x%X\n", tf->device);
> +	}
> +
> +	ata_wait_idle(ap);
> +}
> +
> +static void ep93xx_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
> +{
> +	struct ata_ioports *ioaddr = &ap->ioaddr;
> +
> +	tf->command = ap->ops->check_status(ap);

remove indirection in the hot path, by directly calling 
ep93xx_check_status() here


> +	tf->feature = ep93xx_readb((void __iomem *)ioaddr->error_addr);
> +	tf->nsect = ep93xx_readb((void __iomem *)ioaddr->nsect_addr);
> +	tf->lbal = ep93xx_readb((void __iomem *)ioaddr->lbal_addr);
> +	tf->lbam = ep93xx_readb((void __iomem *)ioaddr->lbam_addr);
> +	tf->lbah = ep93xx_readb((void __iomem *)ioaddr->lbah_addr);
> +	tf->device = ep93xx_readb((void __iomem *)ioaddr->device_addr);
> +
> +	if (tf->flags & ATA_TFLAG_LBA48) {
> +		ep93xx_writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
> +		tf->hob_feature = ep93xx_readb((void __iomem *)ioaddr->error_addr);
> +		tf->hob_nsect = ep93xx_readb((void __iomem *)ioaddr->nsect_addr);
> +		tf->hob_lbal = ep93xx_readb((void __iomem *)ioaddr->lbal_addr);
> +		tf->hob_lbam = ep93xx_readb((void __iomem *)ioaddr->lbam_addr);
> +		tf->hob_lbah = ep93xx_readb((void __iomem *)ioaddr->lbah_addr);
> +	}
> +}
> +
> +static u8 ep93xx_check_status(struct ata_port *ap)
> +{
> +	return ep93xx_readb((void __iomem *) ap->ioaddr.status_addr);
> +}
> +
> +static u8 ep93xx_check_altstatus(struct ata_port *ap)
> +{
> +	return ep93xx_readb((void __iomem *)ap->ioaddr.altstatus_addr);
> +}
> +
> +static void ep93xx_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
> +{
> +	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
> +
> +	ep93xx_writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
> +	ata_pause(ap);
> +}
> +
> +static unsigned int ep93xx_dev_check(struct ata_port *ap, unsigned int device)
> +{
> +	struct ata_ioports *ioaddr = &ap->ioaddr;
> +	u8 nsect, lbal;
> +
> +	ap->ops->dev_select(ap, device);
> +
> +	ep93xx_writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
> +	ep93xx_writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
> +
> +	ep93xx_writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
> +	ep93xx_writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
> +
> +	ep93xx_writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
> +	ep93xx_writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
> +
> +	nsect = ep93xx_readb((void __iomem *) ioaddr->nsect_addr);
> +	lbal = ep93xx_readb((void __iomem *) ioaddr->lbal_addr);
> +
> +	if ((nsect == 0x55) && (lbal == 0xaa))
> +		return 1;	/* we found a device */
> +
> +	return 0;		/* nothing found */
> +}
> +
> +static void ep93xx_dev_select (struct ata_port *ap, unsigned int device)
> +{
> +	u8 tmp;
> +
> +	if (device == 0)
> +		tmp = ATA_DEVICE_OBS;
> +	else
> +		tmp = ATA_DEVICE_OBS | ATA_DEV1;
> +
> +	ep93xx_writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
> +
> +	ata_pause(ap);	/* needed; also flushes, for mmio */
> +}
> +
> +static void ep93xx_data_xfer(struct ata_port *ap, struct ata_device *adev,
> +			unsigned char *buf, unsigned int buflen, int write_data)
> +{
> +	unsigned int i;
> +	unsigned int words = buflen >> 1;
> +	u16 *buf16 = (u16 *) buf;
> +	void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
> +
> +	/* Transfer multiple of 2 bytes */
> +	if (write_data) {
> +		for (i = 0; i < words; i++)
> +			ep93xx_writew(le16_to_cpu(buf16[i]), mmio);
> +	} else {
> +		for (i = 0; i < words; i++)
> +			buf16[i] = cpu_to_le16(ep93xx_readw(mmio));
> +	}
> +
> +	/* Transfer trailing 1 byte, if any. */
> +	if (unlikely(buflen & 0x01)) {
> +		u16 align_buf[1] = { 0 };
> +		unsigned char *trailing_buf = buf + buflen - 1;
> +
> +		if (write_data) {
> +			memcpy(align_buf, trailing_buf, 1);
> +			ep93xx_writew(le16_to_cpu(align_buf[0]), mmio);
> +		} else {
> +			align_buf[0] = cpu_to_le16(ep93xx_readw(mmio));
> +			memcpy(trailing_buf, align_buf, 1);

any chance your platform as string functions, a la insl() ?


> +static struct scsi_host_template ep93xx_sht = {
> +	.module			= THIS_MODULE,
> +	.name			= DRV_NAME,
> +	.ioctl			= ata_scsi_ioctl,
> +	.queuecommand		= ata_scsi_queuecmd,
> +	.eh_strategy_handler	= ata_scsi_error,
> +	.can_queue		= ATA_DEF_QUEUE,
> +	.this_id		= ATA_SHT_THIS_ID,
> +	.sg_tablesize		= LIBATA_MAX_PRD,
> +	.max_sectors		= ATA_MAX_SECTORS,
> +	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
> +	.emulated		= ATA_SHT_EMULATED,
> +	.use_clustering		= ATA_SHT_USE_CLUSTERING,
> +	.proc_name		= DRV_NAME,
> +	.dma_boundary		= ATA_DMA_BOUNDARY,
> +	.slave_configure	= ata_scsi_slave_config,
> +	.bios_param		= ata_std_bios_param,
> +};
> +
> +static struct ata_port_operations ep93xx_port_ops = {
> +	.set_mode		= ep93xx_set_mode,
> +	.mode_filter		= ep93xx_mode_filter,
> +
> +	.port_disable		= ata_port_disable,
> +	.tf_load		= ep93xx_tf_load,
> +	.tf_read		= ep93xx_tf_read,
> +	.check_status 		= ep93xx_check_status,
> +	.check_altstatus	= ep93xx_check_altstatus,
> +	.exec_command		= ep93xx_exec_command,
> +	.data_xfer		= ep93xx_data_xfer,
> +
> +	.dev_select 		= ep93xx_dev_select,
> +	.dev_check		= ep93xx_dev_check,
> +
> +	.qc_prep 		= ata_qc_prep,
> +	.qc_issue		= ata_qc_issue_prot,
> +	.eng_timeout		= ata_eng_timeout,
> +
> +	.irq_handler		= ata_interrupt,
> +	.irq_clear		= ep93xx_irq_clear,
> +	.irq_on			= ep93xx_irq_on,
> +
> +	.port_start		= ata_port_start,
> +	.port_stop		= ata_port_stop,
> +	.host_stop		= ata_host_stop,
> +
> +	.phy_reset		= ep93xx_phy_reset,

this driver will need updating for the new EH.  Existing PATA drivers in 
drivers/ata/pata_* provide plenty of examples.  It's mostly just 
deleting ->eng_timeout() hook and a couple others, and using the new 
reset driver.


> +/* Setup the addresses and encode CSx within them */
> +static void ep93xx_ports(struct ata_ioports *ioaddr)
> +{
> +	ioaddr->cmd_addr	= 0 + 2; /* CS1 */
> +	ioaddr->altstatus_addr	= (0x06 << 2) + 1; /* CS0 */
> +	ioaddr->ctl_addr	= (0x06 << 2) + 1; /* CS0 */
> +
> +	ioaddr->data_addr	= (ATA_REG_DATA << 2) + 2;
> +	ioaddr->error_addr	= (ATA_REG_ERR << 2) + 2;
> +	ioaddr->feature_addr	= (ATA_REG_FEATURE << 2) + 2;
> +	ioaddr->nsect_addr	= (ATA_REG_NSECT << 2) + 2;
> +	ioaddr->lbal_addr	= (ATA_REG_LBAL << 2) + 2;
> +	ioaddr->lbam_addr	= (ATA_REG_LBAM << 2) + 2;
> +	ioaddr->lbah_addr	= (ATA_REG_LBAH << 2) + 2;
> +	ioaddr->device_addr	= (ATA_REG_DEVICE << 2) + 2;
> +	ioaddr->status_addr	= (ATA_REG_STATUS << 2) + 2;
> +	ioaddr->command_addr	= (ATA_REG_CMD << 2) + 2;
> +}
> +
> +static int __init ep93xx_pata_init(void)
> +{
> +	int ret;
> +	struct ata_probe_ent ae;
> +
> +	memset(&ae, 0, sizeof(struct ata_probe_ent));
> +	INIT_LIST_HEAD(&ae.node);
> +
> +	ae.dev		= NULL;
> +	ae.private_data = NULL;
> +	ae.port_ops	= &ep93xx_port_ops;
> +	ae.sht		= &ep93xx_sht;
> +	ae.n_ports	= 1;
> +	ae.pio_mask	= 0x1f; /* PIO4 */
> +	ae.irq		= 0;
> +	ae.irq_flags	= 0;
> +	ae.host_flags	= ATA_FLAG_IRQ_MASK | ATA_FLAG_MMIO;
> +
> +	ep93xx_ports(&ae.port[0]);
> +
> +	/* enable ide and set pio mode 4 */
> +	__raw_writel(EP93XX_IDE_CFG_IDEEN | EP93XX_IDE_CFG_PIO |
> +			EP93XX_IDE_CFG_WST(0) | EP93XX_IDE_CFG_MODE(4),
> +			EP93XX_IDE_CFG);
> +
> +	ret = ata_device_add(&ae);
> +	if (ret == 0)
> +		return -ENODEV;
> +
> +	ep93xx_host = ae.host_set;
> +
> +	return 0;
> +}
> +
> +static void __exit ep93xx_pata_exit(void)
> +{
> +	if (ep93xx_host)
> +		ata_host_set_remove(ep93xx_host);
> +}
> +
> +MODULE_AUTHOR("Alessandro Zummo <a.zummo@...ertech.it>");
> +MODULE_DESCRIPTION("low-level driver for ep93xx ATA");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(DRV_VERSION);
> +
> +module_init(ep93xx_pata_init);
> +module_exit(ep93xx_pata_exit);
> Index: linux-2.6.16-rc5/include/asm-arm/arch-ep93xx/ep93xx-regs.h
> ===================================================================
> --- linux-2.6.16-rc5.orig/include/asm-arm/arch-ep93xx/ep93xx-regs.h
> +++ linux-2.6.16-rc5/include/asm-arm/arch-ep93xx/ep93xx-regs.h
> @@ -42,6 +42,32 @@
>  #define EP93XX_BOOT_ROM_BASE		(EP93XX_AHB_VIRT_BASE + 0x00090000)
>  
>  #define EP93XX_IDE_BASE			(EP93XX_AHB_VIRT_BASE + 0x000a0000)
> +#define EP93XX_IDE_REG(x)		(EP93XX_IDE_BASE + (x))
> +#define EP93XX_IDE_CTRL			EP93XX_IDE_REG(0x0000)
> +#define EP93XX_IDE_CFG			EP93XX_IDE_REG(0x0004)
> +#define EP93XX_IDE_DATAOUT		EP93XX_IDE_REG(0x0010)
> +#define EP93XX_IDE_DATAIN		EP93XX_IDE_REG(0x0014)
> +
> +#define EP93XX_IDE_CTRL_CS0n		(1L << 0)
> +#define EP93XX_IDE_CTRL_CS1n		(1L << 1)
> +#define EP93XX_IDE_CTRL_DA_MASK		0x1C
> +#define EP93XX_IDE_CTRL_DA(x)		((x << 2) & EP93XX_IDE_CTRL_DA_MASK)
> +#define EP93XX_IDE_CTRL_DA_CS_MASK	(EP93XX_IDE_CTRL_DA_MASK | EP93XX_IDE_CTRL_CS0n | EP93XX_IDE_CTRL_CS1n)
> +#define EP93XX_IDE_CTRL_DA_CS(x)	(((x)) & EP93XX_IDE_CTRL_DA_CS_MASK)
> +#define EP93XX_IDE_CTRL_DIORn		(1L << 5)
> +#define EP93XX_IDE_CTRL_DIOWn		(1L << 6)
> +#define EP93XX_IDE_CTRL_DASPn		(1L << 7)
> +#define EP93XX_IDE_CTRL_DMARQ		(1L << 8)
> +#define EP93XX_IDE_CTRL_INTRQ		(1L << 9)
> +#define EP93XX_IDE_CTRL_IORDY		(1L << 10)
> +
> +#define EP93XX_IDE_CFG_IDEEN		(1L << 0)
> +#define EP93XX_IDE_CFG_PIO		(1L << 1)
> +#define EP93XX_IDE_CFG_MDMA		(1L << 2)
> +#define EP93XX_IDE_CFG_UDMA		(1L << 3)
> +#define EP93XX_IDE_CFG_MODE(x)		((x & 0x0F) << 4)
> +#define EP93XX_IDE_CFG_WST(x)		((x & 0x03) << 8)

would prefer that this stuff go into the pata_ep93xx.c file, if it's not 
used anywhere else

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ