mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-29 05:55:02 +08:00
96068e6b4d
The *_RELEASE macros don't tell me anything. In some cases the version in the macro contradicts the version in the comments. Anyway, the Linux kernel version is sufficient information. Remove these macros to improve readability. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Reviewed-by: Hannes Reinecke <hare@suse.de> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
326 lines
7.2 KiB
C
326 lines
7.2 KiB
C
/*
|
|
* Generic Generic NCR5380 driver
|
|
*
|
|
* Copyright 1995-2002, Russell King
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/signal.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/init.h>
|
|
|
|
#include <asm/ecard.h>
|
|
#include <asm/io.h>
|
|
|
|
#include "../scsi.h"
|
|
#include <scsi/scsi_host.h>
|
|
|
|
#include <scsi/scsicam.h>
|
|
|
|
#define PSEUDO_DMA
|
|
|
|
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
|
|
#define NCR5380_local_declare() struct Scsi_Host *_instance
|
|
#define NCR5380_setup(instance) _instance = instance
|
|
#define NCR5380_read(reg) cumanascsi_read(_instance, reg)
|
|
#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
|
|
#define NCR5380_intr cumanascsi_intr
|
|
#define NCR5380_queue_command cumanascsi_queue_command
|
|
#define NCR5380_info cumanascsi_info
|
|
|
|
#define NCR5380_implementation_fields \
|
|
unsigned ctrl; \
|
|
void __iomem *base; \
|
|
void __iomem *dma
|
|
|
|
#include "../NCR5380.h"
|
|
|
|
void cumanascsi_setup(char *str, int *ints)
|
|
{
|
|
}
|
|
|
|
#define CTRL 0x16fc
|
|
#define STAT 0x2004
|
|
#define L(v) (((v)<<16)|((v) & 0x0000ffff))
|
|
#define H(v) (((v)>>16)|((v) & 0xffff0000))
|
|
|
|
static inline int
|
|
NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
|
|
{
|
|
unsigned long *laddr;
|
|
void __iomem *dma = priv(host)->dma + 0x2000;
|
|
|
|
if(!len) return 0;
|
|
|
|
writeb(0x02, priv(host)->base + CTRL);
|
|
laddr = (unsigned long *)addr;
|
|
while(len >= 32)
|
|
{
|
|
unsigned int status;
|
|
unsigned long v;
|
|
status = readb(priv(host)->base + STAT);
|
|
if(status & 0x80)
|
|
goto end;
|
|
if(!(status & 0x40))
|
|
continue;
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
v=*laddr++; writew(L(v), dma); writew(H(v), dma);
|
|
len -= 32;
|
|
if(len == 0)
|
|
break;
|
|
}
|
|
|
|
addr = (unsigned char *)laddr;
|
|
writeb(0x12, priv(host)->base + CTRL);
|
|
|
|
while(len > 0)
|
|
{
|
|
unsigned int status;
|
|
status = readb(priv(host)->base + STAT);
|
|
if(status & 0x80)
|
|
goto end;
|
|
if(status & 0x40)
|
|
{
|
|
writeb(*addr++, dma);
|
|
if(--len == 0)
|
|
break;
|
|
}
|
|
|
|
status = readb(priv(host)->base + STAT);
|
|
if(status & 0x80)
|
|
goto end;
|
|
if(status & 0x40)
|
|
{
|
|
writeb(*addr++, dma);
|
|
if(--len == 0)
|
|
break;
|
|
}
|
|
}
|
|
end:
|
|
writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
|
|
return len;
|
|
}
|
|
|
|
static inline int
|
|
NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
|
|
{
|
|
unsigned long *laddr;
|
|
void __iomem *dma = priv(host)->dma + 0x2000;
|
|
|
|
if(!len) return 0;
|
|
|
|
writeb(0x00, priv(host)->base + CTRL);
|
|
laddr = (unsigned long *)addr;
|
|
while(len >= 32)
|
|
{
|
|
unsigned int status;
|
|
status = readb(priv(host)->base + STAT);
|
|
if(status & 0x80)
|
|
goto end;
|
|
if(!(status & 0x40))
|
|
continue;
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
*laddr++ = readw(dma) | (readw(dma) << 16);
|
|
len -= 32;
|
|
if(len == 0)
|
|
break;
|
|
}
|
|
|
|
addr = (unsigned char *)laddr;
|
|
writeb(0x10, priv(host)->base + CTRL);
|
|
|
|
while(len > 0)
|
|
{
|
|
unsigned int status;
|
|
status = readb(priv(host)->base + STAT);
|
|
if(status & 0x80)
|
|
goto end;
|
|
if(status & 0x40)
|
|
{
|
|
*addr++ = readb(dma);
|
|
if(--len == 0)
|
|
break;
|
|
}
|
|
|
|
status = readb(priv(host)->base + STAT);
|
|
if(status & 0x80)
|
|
goto end;
|
|
if(status & 0x40)
|
|
{
|
|
*addr++ = readb(dma);
|
|
if(--len == 0)
|
|
break;
|
|
}
|
|
}
|
|
end:
|
|
writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
|
|
return len;
|
|
}
|
|
|
|
static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
|
|
{
|
|
void __iomem *base = priv(host)->base;
|
|
unsigned char val;
|
|
|
|
writeb(0, base + CTRL);
|
|
|
|
val = readb(base + 0x2100 + (reg << 2));
|
|
|
|
priv(host)->ctrl = 0x40;
|
|
writeb(0x40, base + CTRL);
|
|
|
|
return val;
|
|
}
|
|
|
|
static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
|
|
{
|
|
void __iomem *base = priv(host)->base;
|
|
|
|
writeb(0, base + CTRL);
|
|
|
|
writeb(value, base + 0x2100 + (reg << 2));
|
|
|
|
priv(host)->ctrl = 0x40;
|
|
writeb(0x40, base + CTRL);
|
|
}
|
|
|
|
#include "../NCR5380.c"
|
|
|
|
static struct scsi_host_template cumanascsi_template = {
|
|
.module = THIS_MODULE,
|
|
.name = "Cumana 16-bit SCSI",
|
|
.info = cumanascsi_info,
|
|
.queuecommand = cumanascsi_queue_command,
|
|
.eh_abort_handler = NCR5380_abort,
|
|
.eh_bus_reset_handler = NCR5380_bus_reset,
|
|
.can_queue = 16,
|
|
.this_id = 7,
|
|
.sg_tablesize = SG_ALL,
|
|
.cmd_per_lun = 2,
|
|
.use_clustering = DISABLE_CLUSTERING,
|
|
.proc_name = "CumanaSCSI-1",
|
|
};
|
|
|
|
static int cumanascsi1_probe(struct expansion_card *ec,
|
|
const struct ecard_id *id)
|
|
{
|
|
struct Scsi_Host *host;
|
|
int ret;
|
|
|
|
ret = ecard_request_resources(ec);
|
|
if (ret)
|
|
goto out;
|
|
|
|
host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
|
|
if (!host) {
|
|
ret = -ENOMEM;
|
|
goto out_release;
|
|
}
|
|
|
|
priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
|
|
ecard_resource_len(ec, ECARD_RES_IOCSLOW));
|
|
priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
|
|
ecard_resource_len(ec, ECARD_RES_MEMC));
|
|
if (!priv(host)->base || !priv(host)->dma) {
|
|
ret = -ENOMEM;
|
|
goto out_unmap;
|
|
}
|
|
|
|
host->irq = ec->irq;
|
|
|
|
NCR5380_init(host, 0);
|
|
|
|
priv(host)->ctrl = 0;
|
|
writeb(0, priv(host)->base + CTRL);
|
|
|
|
host->n_io_port = 255;
|
|
if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
|
|
ret = -EBUSY;
|
|
goto out_unmap;
|
|
}
|
|
|
|
ret = request_irq(host->irq, cumanascsi_intr, 0,
|
|
"CumanaSCSI-1", host);
|
|
if (ret) {
|
|
printk("scsi%d: IRQ%d not free: %d\n",
|
|
host->host_no, host->irq, ret);
|
|
goto out_unmap;
|
|
}
|
|
|
|
ret = scsi_add_host(host, &ec->dev);
|
|
if (ret)
|
|
goto out_free_irq;
|
|
|
|
scsi_scan_host(host);
|
|
goto out;
|
|
|
|
out_free_irq:
|
|
free_irq(host->irq, host);
|
|
out_unmap:
|
|
iounmap(priv(host)->base);
|
|
iounmap(priv(host)->dma);
|
|
scsi_host_put(host);
|
|
out_release:
|
|
ecard_release_resources(ec);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void cumanascsi1_remove(struct expansion_card *ec)
|
|
{
|
|
struct Scsi_Host *host = ecard_get_drvdata(ec);
|
|
|
|
ecard_set_drvdata(ec, NULL);
|
|
|
|
scsi_remove_host(host);
|
|
free_irq(host->irq, host);
|
|
NCR5380_exit(host);
|
|
iounmap(priv(host)->base);
|
|
iounmap(priv(host)->dma);
|
|
scsi_host_put(host);
|
|
ecard_release_resources(ec);
|
|
}
|
|
|
|
static const struct ecard_id cumanascsi1_cids[] = {
|
|
{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },
|
|
{ 0xffff, 0xffff }
|
|
};
|
|
|
|
static struct ecard_driver cumanascsi1_driver = {
|
|
.probe = cumanascsi1_probe,
|
|
.remove = cumanascsi1_remove,
|
|
.id_table = cumanascsi1_cids,
|
|
.drv = {
|
|
.name = "cumanascsi1",
|
|
},
|
|
};
|
|
|
|
static int __init cumanascsi_init(void)
|
|
{
|
|
return ecard_register_driver(&cumanascsi1_driver);
|
|
}
|
|
|
|
static void __exit cumanascsi_exit(void)
|
|
{
|
|
ecard_remove_driver(&cumanascsi1_driver);
|
|
}
|
|
|
|
module_init(cumanascsi_init);
|
|
module_exit(cumanascsi_exit);
|
|
|
|
MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
|
|
MODULE_LICENSE("GPL");
|