61e1ce588b
For timeout values adopt unsigned long, which is the type of jiffies etc. For chip register values and bit masks pass u8, which is the return type of readb, inb etc. For device register offsets adopt unsigned int, as it is suitable for adding to base addresses. Pass the NCR5380_hostdata pointer to the board-specific routines instead of the Scsi_Host pointer. The board-specific code is concerned with hardware and not with SCSI protocol or the mid-layer. Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Reviewed-by: Hannes Reinecke <hare@suse.com> Tested-by: Ondrej Zary <linux@rainbow-software.org> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Acked-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
212 lines
4.3 KiB
C
212 lines
4.3 KiB
C
/*
|
|
* Oak Generic NCR5380 driver
|
|
*
|
|
* Copyright 1995-2002, Russell King
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/init.h>
|
|
|
|
#include <asm/ecard.h>
|
|
#include <asm/io.h>
|
|
|
|
#include <scsi/scsi_host.h>
|
|
|
|
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
|
|
|
|
#define NCR5380_read(reg) readb(hostdata->io + ((reg) << 2))
|
|
#define NCR5380_write(reg, value) writeb(value, hostdata->io + ((reg) << 2))
|
|
|
|
#define NCR5380_dma_xfer_len(instance, cmd, phase) (0)
|
|
#define NCR5380_dma_recv_setup oakscsi_pread
|
|
#define NCR5380_dma_send_setup oakscsi_pwrite
|
|
#define NCR5380_dma_residual(instance) (0)
|
|
|
|
#define NCR5380_queue_command oakscsi_queue_command
|
|
#define NCR5380_info oakscsi_info
|
|
|
|
#define NCR5380_implementation_fields /* none */
|
|
|
|
#include "../NCR5380.h"
|
|
|
|
#undef START_DMA_INITIATOR_RECEIVE_REG
|
|
#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
|
|
|
|
#define STAT ((128 + 16) << 2)
|
|
#define DATA ((128 + 8) << 2)
|
|
|
|
static inline int oakscsi_pwrite(struct Scsi_Host *instance,
|
|
unsigned char *addr, int len)
|
|
{
|
|
u8 __iomem *base = priv(instance)->io;
|
|
|
|
printk("writing %p len %d\n",addr, len);
|
|
|
|
while(1)
|
|
{
|
|
int status;
|
|
while (((status = readw(base + STAT)) & 0x100)==0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline int oakscsi_pread(struct Scsi_Host *instance,
|
|
unsigned char *addr, int len)
|
|
{
|
|
u8 __iomem *base = priv(instance)->io;
|
|
printk("reading %p len %d\n", addr, len);
|
|
while(len > 0)
|
|
{
|
|
unsigned int status, timeout;
|
|
unsigned long b;
|
|
|
|
timeout = 0x01FFFFFF;
|
|
|
|
while (((status = readw(base + STAT)) & 0x100)==0)
|
|
{
|
|
timeout--;
|
|
if(status & 0x200 || !timeout)
|
|
{
|
|
printk("status = %08X\n", status);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(len >= 128)
|
|
{
|
|
readsw(base + DATA, addr, 128);
|
|
addr += 128;
|
|
len -= 128;
|
|
}
|
|
else
|
|
{
|
|
b = (unsigned long) readw(base + DATA);
|
|
*addr ++ = b;
|
|
len -= 1;
|
|
if(len)
|
|
*addr ++ = b>>8;
|
|
len -= 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#undef STAT
|
|
#undef DATA
|
|
|
|
#include "../NCR5380.c"
|
|
|
|
static struct scsi_host_template oakscsi_template = {
|
|
.module = THIS_MODULE,
|
|
.name = "Oak 16-bit SCSI",
|
|
.info = oakscsi_info,
|
|
.queuecommand = oakscsi_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 = "oakscsi",
|
|
.cmd_size = NCR5380_CMD_SIZE,
|
|
.max_sectors = 128,
|
|
};
|
|
|
|
static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
|
|
{
|
|
struct Scsi_Host *host;
|
|
int ret = -ENOMEM;
|
|
|
|
ret = ecard_request_resources(ec);
|
|
if (ret)
|
|
goto out;
|
|
|
|
host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
|
|
if (!host) {
|
|
ret = -ENOMEM;
|
|
goto release;
|
|
}
|
|
|
|
priv(host)->io = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
|
|
ecard_resource_len(ec, ECARD_RES_MEMC));
|
|
if (!priv(host)->io) {
|
|
ret = -ENOMEM;
|
|
goto unreg;
|
|
}
|
|
|
|
host->irq = NO_IRQ;
|
|
|
|
ret = NCR5380_init(host, FLAG_DMA_FIXUP | FLAG_LATE_DMA_SETUP);
|
|
if (ret)
|
|
goto out_unmap;
|
|
|
|
NCR5380_maybe_reset_bus(host);
|
|
|
|
ret = scsi_add_host(host, &ec->dev);
|
|
if (ret)
|
|
goto out_exit;
|
|
|
|
scsi_scan_host(host);
|
|
goto out;
|
|
|
|
out_exit:
|
|
NCR5380_exit(host);
|
|
out_unmap:
|
|
iounmap(priv(host)->io);
|
|
unreg:
|
|
scsi_host_put(host);
|
|
release:
|
|
ecard_release_resources(ec);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void oakscsi_remove(struct expansion_card *ec)
|
|
{
|
|
struct Scsi_Host *host = ecard_get_drvdata(ec);
|
|
void __iomem *base = priv(host)->io;
|
|
|
|
ecard_set_drvdata(ec, NULL);
|
|
scsi_remove_host(host);
|
|
|
|
NCR5380_exit(host);
|
|
scsi_host_put(host);
|
|
iounmap(base);
|
|
ecard_release_resources(ec);
|
|
}
|
|
|
|
static const struct ecard_id oakscsi_cids[] = {
|
|
{ MANU_OAK, PROD_OAK_SCSI },
|
|
{ 0xffff, 0xffff }
|
|
};
|
|
|
|
static struct ecard_driver oakscsi_driver = {
|
|
.probe = oakscsi_probe,
|
|
.remove = oakscsi_remove,
|
|
.id_table = oakscsi_cids,
|
|
.drv = {
|
|
.name = "oakscsi",
|
|
},
|
|
};
|
|
|
|
static int __init oakscsi_init(void)
|
|
{
|
|
return ecard_register_driver(&oakscsi_driver);
|
|
}
|
|
|
|
static void __exit oakscsi_exit(void)
|
|
{
|
|
ecard_remove_driver(&oakscsi_driver);
|
|
}
|
|
|
|
module_init(oakscsi_init);
|
|
module_exit(oakscsi_exit);
|
|
|
|
MODULE_AUTHOR("Russell King");
|
|
MODULE_DESCRIPTION("Oak SCSI driver");
|
|
MODULE_LICENSE("GPL");
|
|
|