All of lore.kernel.org
 help / color / mirror / Atom feed
* An MCA ESP driver
@ 2007-08-06 23:24 Matthew Wilcox
  2007-08-07  7:26 ` David Miller
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew Wilcox @ 2007-08-06 23:24 UTC (permalink / raw)
  To: linux-scsi

This is about 90% complete.  I need to implement:

drivers/scsi/mca_53c9x.c:191: error: 'mca_esp_reset_dma' undeclared here (not in a function)
drivers/scsi/mca_53c9x.c:192: error: 'mca_esp_dma_drain' undeclared here (not in a function)
drivers/scsi/mca_53c9x.c:193: error: 'mca_esp_dma_invalidate' undeclared here (not in a function)
drivers/scsi/mca_53c9x.c:195: error: 'mca_esp_dma_error' undeclared here (not in a function)

I thought I'd post what I have so far.  If you compare it to the
mca_53c9x driver currently in-tree, you'll see that davem's new core is
much nicer.  I had to make one tiny change to the esp driver core:

diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index 856e38b..fc8437d 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -514,11 +514,14 @@ struct esp {
 
 	struct completion	*eh_reset;
 
-	struct sbus_dma		*dma;
+	union {
+		struct sbus_dma	*sbus_dma;
+		unsigned int	x86_dma;
+	};
 };
 
 /* A front-end driver for the ESP chip should do the following in
- * it's device probe routine:
+ * its device probe routine:
  * 1) Allocate the host and private area using scsi_host_alloc()
  *    with size 'sizeof(struct esp)'.  The first argument to
  *    scsi_host_alloc() should be &scsi_esp_template.

(er, I suppose I need to touch up the sun_esp driver to match the name
change).

Anyway, the new driver:

/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx
 *  (and maybe some other) Microchannel machines
 *
 * Code taken mostly from Cyberstorm SCSI drivers
 *   Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
 *
 * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org)
 *
 * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's
 *   ESP driver  * for the Sparc computers.
 *
 * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on
 *  the 86C01.  I was on the brink of going ga-ga...
 *
 * Also thanks to Jesper Skov for helping me with info on how the Amiga
 *  does things...
 */

/*
 * Info on the 86C01 MCA interface chip at the bottom, if you care enough to
 *  look.
 */

#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mca.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
#include <linux/proc_fs.h>

#include <asm/dma.h>
#include <asm/mca_dma.h>

#include <scsi/scsi_host.h>
#include "scsi.h"
#include "esp_scsi.h"

/* Tell the 86C01 to stop sending interrupts */
static void mca_esp_disable_irq(struct esp *esp)
{
	u8 mode_enable = ioread8(esp->dma_regs + 2);
	iowrite8(mode_enable & ~0x40, esp->dma_regs + 2);
}

/* Tell the 86C01 to give us interrupts */
static void mca_esp_enable_irq(struct esp *esp)
{
	u8 mode_enable = ioread8(esp->dma_regs + 2);
	iowrite8(mode_enable | 0x40, esp->dma_regs + 2);
}

/*
 * We keep the structure that is used to access the registers on the 53c9x
 *  here.
 */

static struct ESP_regs eregs;

/************************************************************* DMA Functions */
static int dma_bytes_sent(struct esp *esp, int fifo_count)
{
	/* Ask the 53c9x.  It knows. */

	return fifo_count;
}

static int dma_can_transfer(struct esp *esp, Scsi_Cmnd *sp)
{
	/*
	 * The MCA dma channels can only do up to 128K bytes at a time.
         *  (16 bit mode)
	 */

	unsigned long sz = sp->SCp.this_residual;
	if(sz > 0x20000)
		sz = 0x20000;
	return sz;
}

#if 0
static void dma_dump_state(struct esp *esp)
{
	/*
	 * Doesn't quite match up to the other drivers, but we do what we
	 *  can.
	 */

	ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->x86_dma));
	ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->x86_dma)));
}

/*
 * These will not play nicely with other disk controllers that try to use the
 *  disk active LED... but what can you do?  Don't answer that.
 *
 * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver
 */

#define PS2_SYS_CTR	0x92

static void dma_led_on(struct esp *esp)
{
	outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR);
}

static void dma_led_off(struct esp *esp)
{
	outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR);
}

/*
 * Check to see if interrupts are enabled on the 'C01 (in case abort
 *  is entered multiple times, so we only do the abort once)
 */
static int dma_ports_p(struct esp *esp)
{
	return (ioread8(esp->dma_regs + 2) & 0x40) ? 1 : 0;
}

#endif

static void mca_esp_write8(struct esp *esp, u8 val, unsigned long reg)
{
	iowrite8(val, esp->regs + reg);
}

static u8 mca_esp_read8(struct esp *esp, unsigned long reg)
{
	return ioread8(esp->regs + reg);
}

static dma_addr_t mca_esp_map_single(struct esp *esp, void *buf, size_t sz,
					int dir)
{
	return dma_map_single(esp->dev, buf, sz, dir);
}

static int mca_esp_map_sg(struct esp *esp, struct scatterlist *sg, int num_sg,
					int dir)
{
	return dma_map_sg(esp->dev, sg, num_sg, dir);
}

static void mca_esp_unmap_single(struct esp *esp, dma_addr_t addr, size_t sz,
					int dir)
{
	dma_unmap_single(esp->dev, addr, sz, dir);
}

static void mca_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
					int num_sg, int dir)
{
	dma_unmap_sg(esp->dev, sg, num_sg, dir);
}

static int mca_esp_irq_pending(struct esp *esp)
{
	u8 status = ioread8(esp->dma_regs + 0xc);
	return status & 1;
}

#define mca_esp_dma_flags MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 | MCA_DMA_MODE_IO

static void mca_esp_send_dma_cmd(struct esp *esp, u32 dma_addr, u32 esp_count,
				 u32 dma_count, int write, u8 cmd)
{
	mca_disable_dma(esp->x86_dma);
	mca_set_dma_mode(esp->x86_dma, mca_esp_dma_flags | (write ?
						MCA_DMA_MODE_WRITE : 0));
	mca_set_dma_addr(esp->x86_dma, dma_addr);
	mca_set_dma_count(esp->x86_dma, dma_count);
	mca_enable_dma(esp->x86_dma);

	mca_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
	mca_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);

	scsi_esp_cmd(esp, cmd);
}

static const struct esp_driver_ops mca_esp_ops = {
	.esp_write8	= mca_esp_write8,
	.esp_read8	= mca_esp_read8,
	.map_single	= mca_esp_map_single,
	.map_sg		= mca_esp_map_sg,
	.unmap_single	= mca_esp_unmap_single,
	.unmap_sg	= mca_esp_unmap_sg,
	.irq_pending	= mca_esp_irq_pending,
	.reset_dma	= mca_esp_reset_dma,
	.dma_drain	= mca_esp_dma_drain,
	.dma_invalidate	= mca_esp_dma_invalidate,
	.send_dma_cmd	= mca_esp_send_dma_cmd,
	.dma_error	= mca_esp_dma_error,
};

/*
 * IO port base is given in the pos 2 register, like so:
 *
 *  Bits 3  2  1       IO base
 * ----------------------------
 *       0  0  0       <disabled>
 *       0  0  1       0x0240
 *       0  1  0       0x0340
 *       0  1  1       0x0400
 *       1  0  0       0x0420
 *       1  0  1       0x3240
 *       1  1  0       0x8240
 *       1  1  1       0xA240
 */
static const short __devinitdata mca_esp_ports[] = {
	0x0000, 0x0240, 0x0340, 0x0400, 0x0420, 0x3240, 0x8240, 0xA240
};

static int __devinit mca_esp_probe(struct device *dev)
{
	struct mca_device *mdev = to_mca_device(dev);
	struct Scsi_Host *shost;
	struct esp *esp;
	unsigned short io_port;
	int err;

	shost = scsi_host_alloc(&scsi_esp_template, sizeof(struct esp));

	err = -ENOMEM;
	if (!shost)
		goto fail;

	shost->max_id = 8;
	esp = shost_priv(shost);

	esp->host = shost;
	esp->dev = dev;
	esp->ops = &mca_esp_ops;

	if (mdev->pos[2] & 0x80)
		esp->flags |= ESP_FLAG_WIDE_CAPABLE;

	err = -ENODEV;
	io_port = mca_esp_ports[(mdev->pos[2] & 0x0E) >> 1];
	if (io_port == 0) {
        	printk("Adapter is disabled.\n");
		goto free_shost;
	}

	err = -EBUSY;
	if (request_region(io_port, 32, "NCR 53c9x SCSI")) {
		printk("Resources in use\n");
		goto free_shost;
	}

	esp->dma_regs = ioport_map(io_port, 32);
	esp->regs = esp->dma_regs + 0x10;

	err = -ENOMEM;
	esp->command_block = dma_alloc_coherent(dev, 16,
				&esp->command_block_dma, GFP_KERNEL);
	if (!esp->command_block) {
		printk("Could not alloc DMA memory\n");
		goto release_region;
	}

	shost->irq = ((mdev->pos[2] & 0x30) >> 3) + 3;

	err = request_irq(shost->irq, scsi_esp_intr, IRQF_SHARED,
			  "NCR 53c9x SCSI", esp);
	if (err) {
		printk("Unable to request IRQ %d.\n", shost->irq);
		goto free_dma_mem;
	}

	esp->x86_dma = mdev->pos[3] & 7;

	err = request_dma(esp->x86_dma, "NCR 53c9x SCSI");
	if (err) {
		printk("Unable to request DMA channel %d.\n", esp->x86_dma);
		goto free_irq;
	}

	shost->this_id = esp->scsi_id = ((mdev->pos[4] & 0xC0) >> 6) + 4;
	esp->scsi_id_mask = 1 << esp->scsi_id;

	/* SCSI chip speed */

	esp->cfreq = 25000000;

	/*
	 * 86C01 handles DMA, IO mode, from address (base + 0x0a)
	 */

	mca_disable_dma(esp->x86_dma);
	mca_set_dma_io(esp->x86_dma, io_port + 0x0a);
	mca_enable_dma(esp->x86_dma);

	mca_esp_enable_irq(esp);

	dev_set_drvdata(dev, shost);

	err = scsi_esp_register(esp, dev);
	if (err) {
		printk("ESP register failed\n");
		goto free_dma;
	}

      	printk("Adapter found in slot %2d: io port 0x%x irq %d "
		"dma channel %d\n", mdev->slot, io_port, shost->irq,
		esp->x86_dma);

	return 0;

 free_dma:
	free_dma(esp->x86_dma);
 free_irq:
	free_irq(shost->irq, scsi_esp_intr);
 free_dma_mem:
	dma_free_coherent(dev, 16, esp->command_block, esp->command_block_dma);
 release_region:
	release_region(io_port, 32);
 free_shost:
	scsi_host_put(shost);
 fail:
	return err;
}

static int mca_esp_remove(struct device *dev)
{
	struct Scsi_Host *shost = dev_get_drvdata(dev);
	struct esp *esp = shost_priv(shost);

	scsi_remove_host(shost);
	scsi_esp_unregister(esp);
	mca_esp_disable_irq(esp);
	free_irq(shost->irq, scsi_esp_intr);
	free_dma(esp->x86_dma);

	scsi_host_put(shost);
	return 0;
}

/*
 * Supposedly there were some cards put together with the 'c9x and 86c01.
 * If they have different ID's from the ones on the 3500 series machines,
 * you can add them here and hopefully things will work out.
 */
static const short mca_esp_id_table[] = { 0x7F4C, 0 };

static struct mca_driver mca_esp_driver = {
	.id_table	= mca_esp_id_table,
	.driver = {
		.name	= "mca_esp",
		.probe	= mca_esp_probe,
		.remove	= __devexit_p(mca_esp_remove),
	},
};

static int __init mca_esp_init(void)
{
	return mca_register_driver(&mca_esp_driver);
}

static void __exit mca_esp_exit(void)
{
	mca_unregister_driver(&mca_esp_driver);
}

module_init(mca_esp_init);
module_exit(mca_esp_exit);

/*
 * OK, here's the goods I promised.  The NCR 86C01 is an MCA interface chip
 *  that handles enabling/diabling IRQ, dma interfacing, IO port selection
 *  and other fun stuff.  It takes up 16 addresses, and the chip it is
 *  connnected to gets the following 16.  Registers are as follows:
 *
 * Offsets 0-1 : Card ID
 *
 * Offset    2 : Mode enable register --
 *                Bit    7 : Data Word width (1 = 16, 0 = 8)
 *		  Bit    6 : IRQ enable (1 = enabled)
 *                Bits 5,4 : IRQ select
 *                              0  0 : IRQ 3
 *			        0  1 : IRQ 5
 * 				1  0 : IRQ 7
 *  				1  1 : IRQ 9
 *                Bits 3-1 : Base Address
 *                           0  0  0 : <disabled>
 * 			     0  0  1 : 0x0240
 *    			     0  1  0 : 0x0340
 *     			     0  1  1 : 0x0400
 * 			     1  0  0 : 0x0420
 * 			     1  0  1 : 0x3240
 * 			     1  1  0 : 0x8240
 * 			     1  1  1 : 0xA240
 *		  Bit    0 : Card enable (1 = enabled)
 *
 * Offset    3 : DMA control register --
 *                Bit    7 : DMA enable (1 = enabled)
 *                Bits 6,5 : Preemt Count Select (transfers to complete after
 *                            'C01 has been preempted on MCA bus)
 *                              0  0 : 0
 *                              0  1 : 1
 *                              1  0 : 3
 *                              1  1 : 7
 *  (all these wacky numbers; I'm sure there's a reason somewhere)
 *                Bit    4 : Fairness enable (1 = fair bus priority)
 *                Bits 3-0 : Arbitration level (0-15 consecutive)
 *
 * Offset    4 : General purpose register
 *                Bits 7-3 : User definable (here, 7,6 are SCSI ID)
 *                Bits 2-0 : reserved
 *
 * Offset   10 : DMA decode register (used for IO based DMA; also can do
 *                PIO through this port)
 *
 * Offset   12 : Status
 *                Bits 7-2 : reserved
 *                Bit    1 : DMA pending (1 = pending)
 *                Bit    0 : IRQ pending (0 = pending)
 *
 * Exciting, huh?
 *
 */

----- End forwarded message -----

-- 
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: An MCA ESP driver
  2007-08-06 23:24 An MCA ESP driver Matthew Wilcox
@ 2007-08-07  7:26 ` David Miller
  2007-08-15 17:26   ` Matthew Wilcox
  0 siblings, 1 reply; 6+ messages in thread
From: David Miller @ 2007-08-07  7:26 UTC (permalink / raw)
  To: matthew; +Cc: linux-scsi

From: Matthew Wilcox <matthew@wil.cx>
Date: Mon, 6 Aug 2007 17:24:58 -0600

> @@ -514,11 +514,14 @@ struct esp {
>  
>  	struct completion	*eh_reset;
>  
> -	struct sbus_dma		*dma;
> +	union {
> +		struct sbus_dma	*sbus_dma;
> +		unsigned int	x86_dma;
> +	};
>  };

Feel free to make this a "void *dma_cookie" or similar.
It's private to the bus front-end.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: An MCA ESP driver
  2007-08-07  7:26 ` David Miller
@ 2007-08-15 17:26   ` Matthew Wilcox
  2007-08-15 21:55     ` David Miller
  0 siblings, 1 reply; 6+ messages in thread
From: Matthew Wilcox @ 2007-08-15 17:26 UTC (permalink / raw)
  To: David Miller; +Cc: linux-scsi

On Tue, Aug 07, 2007 at 12:26:04AM -0700, David Miller wrote:
> > -	struct sbus_dma		*dma;
> > +	union {
> > +		struct sbus_dma	*sbus_dma;
> > +		unsigned int	x86_dma;
> > +	};
> >  };
> 
> Feel free to make this a "void *dma_cookie" or similar.
> It's private to the bus front-end.

Hi Dave,

Could I just clarify; would you prefer it to be a void *?  I prefer the
anonymous union that I have there right now, but I'm not particularly
attached to it.  In particular, I don't really care to be casting ints
(x86) to pointers, but that's a matter of personal taste.

-- 
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: An MCA ESP driver
  2007-08-15 17:26   ` Matthew Wilcox
@ 2007-08-15 21:55     ` David Miller
  2008-01-05 21:18       ` James Bottomley
  0 siblings, 1 reply; 6+ messages in thread
From: David Miller @ 2007-08-15 21:55 UTC (permalink / raw)
  To: matthew; +Cc: linux-scsi

From: Matthew Wilcox <matthew@wil.cx>
Date: Wed, 15 Aug 2007 11:26:00 -0600

> On Tue, Aug 07, 2007 at 12:26:04AM -0700, David Miller wrote:
> > > -	struct sbus_dma		*dma;
> > > +	union {
> > > +		struct sbus_dma	*sbus_dma;
> > > +		unsigned int	x86_dma;
> > > +	};
> > >  };
> > 
> > Feel free to make this a "void *dma_cookie" or similar.
> > It's private to the bus front-end.
> 
> Hi Dave,
> 
> Could I just clarify; would you prefer it to be a void *?  I prefer the
> anonymous union that I have there right now, but I'm not particularly
> attached to it.  In particular, I don't really care to be casting ints
> (x86) to pointers, but that's a matter of personal taste.

Alternatively, you could remove this member entirely, and
make the front-end driver allocate a private area at the
end of "struct esp" to use for whatever purpose it likes.

I'm mostly ambivalent, but if the member stays it should be
some generic type rather than anything front-end specific
like it is now.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: An MCA ESP driver
  2007-08-15 21:55     ` David Miller
@ 2008-01-05 21:18       ` James Bottomley
  2008-01-05 21:53         ` Matthew Wilcox
  0 siblings, 1 reply; 6+ messages in thread
From: James Bottomley @ 2008-01-05 21:18 UTC (permalink / raw)
  To: David Miller; +Cc: matthew, linux-scsi


On Wed, 2007-08-15 at 14:55 -0700, David Miller wrote:
> From: Matthew Wilcox <matthew@wil.cx>
> Date: Wed, 15 Aug 2007 11:26:00 -0600
> 
> > On Tue, Aug 07, 2007 at 12:26:04AM -0700, David Miller wrote:
> > > > -	struct sbus_dma		*dma;
> > > > +	union {
> > > > +		struct sbus_dma	*sbus_dma;
> > > > +		unsigned int	x86_dma;
> > > > +	};
> > > >  };
> > > 
> > > Feel free to make this a "void *dma_cookie" or similar.
> > > It's private to the bus front-end.
> > 
> > Hi Dave,
> > 
> > Could I just clarify; would you prefer it to be a void *?  I prefer the
> > anonymous union that I have there right now, but I'm not particularly
> > attached to it.  In particular, I don't really care to be casting ints
> > (x86) to pointers, but that's a matter of personal taste.
> 
> Alternatively, you could remove this member entirely, and
> make the front-end driver allocate a private area at the
> end of "struct esp" to use for whatever purpose it likes.
> 
> I'm mostly ambivalent, but if the member stays it should be
> some generic type rather than anything front-end specific
> like it is now.

Just a check up on this:  Matthew were you ever going to complete the
mca_94x conversion?  It's quite topical because it would be another
example driver for the m68k people to look at.

If not, I can probably complete the bits you haven't yet done, but it
would be nice to know.

Thanks,

James



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: An MCA ESP driver
  2008-01-05 21:18       ` James Bottomley
@ 2008-01-05 21:53         ` Matthew Wilcox
  0 siblings, 0 replies; 6+ messages in thread
From: Matthew Wilcox @ 2008-01-05 21:53 UTC (permalink / raw)
  To: James Bottomley; +Cc: David Miller, linux-scsi

On Sat, Jan 05, 2008 at 03:18:12PM -0600, James Bottomley wrote:
> Just a check up on this:  Matthew were you ever going to complete the
> mca_94x conversion?  It's quite topical because it would be another
> example driver for the m68k people to look at.
> 
> If not, I can probably complete the bits you haven't yet done, but it
> would be nice to know.

I wasn't planning on completing the conversion, no.  I don't have the
hardware myself, so can't test it.  I started working on it when I was
between jobs, and once I found gainful employment, the amount of free
time I have to hack on obscure hardware that I don't have declined to
nil ;-)

Thanks for volunteering to complete the conversion.

-- 
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-01-05 21:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-06 23:24 An MCA ESP driver Matthew Wilcox
2007-08-07  7:26 ` David Miller
2007-08-15 17:26   ` Matthew Wilcox
2007-08-15 21:55     ` David Miller
2008-01-05 21:18       ` James Bottomley
2008-01-05 21:53         ` Matthew Wilcox

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.