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 ([EMAIL PROTECTED])
*
* Hacked to work with the NCR MCA stuff by Tymm Twillman ([EMAIL PROTECTED])
*
* 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."
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html