#define AUTOSENSE
|
#define AUTOSENSE
|
/*#define PSEUDO_DMA*/
|
/*#define PSEUDO_DMA*/
|
|
|
/*
|
/*
|
* Oak Generic NCR5380 driver
|
* Oak Generic NCR5380 driver
|
*
|
*
|
* Copyright 1995, Russell King
|
* Copyright 1995, Russell King
|
*
|
*
|
* ALPHA RELEASE 1.
|
* ALPHA RELEASE 1.
|
*
|
*
|
* For more information, please consult
|
* For more information, please consult
|
*
|
*
|
* NCR 5380 Family
|
* NCR 5380 Family
|
* SCSI Protocol Controller
|
* SCSI Protocol Controller
|
* Databook
|
* Databook
|
*
|
*
|
* NCR Microelectronics
|
* NCR Microelectronics
|
* 1635 Aeroplaza Drive
|
* 1635 Aeroplaza Drive
|
* Colorado Springs, CO 80916
|
* Colorado Springs, CO 80916
|
* 1+ (719) 578-3400
|
* 1+ (719) 578-3400
|
* 1+ (800) 334-5454
|
* 1+ (800) 334-5454
|
*/
|
*/
|
|
|
/*
|
/*
|
* Options :
|
* Options :
|
*
|
*
|
* PARITY - enable parity checking. Not supported.
|
* PARITY - enable parity checking. Not supported.
|
*
|
*
|
* SCSI2 - enable support for SCSI-II tagged queueing. Untested.
|
* SCSI2 - enable support for SCSI-II tagged queueing. Untested.
|
*
|
*
|
* USLEEP - enable support for devices that don't disconnect. Untested.
|
* USLEEP - enable support for devices that don't disconnect. Untested.
|
*/
|
*/
|
|
|
/*
|
/*
|
* $Log: not supported by cvs2svn $
|
* $Log: not supported by cvs2svn $
|
* Revision 1.1.1.1 2001/09/10 07:43:54 simons
|
* Revision 1.1.1.1 2001/09/10 07:43:54 simons
|
* Initial import
|
* Initial import
|
*
|
*
|
* Revision 1.1.1.1 2001/07/02 17:58:40 simons
|
* Revision 1.1.1.1 2001/07/02 17:58:40 simons
|
* Initial revision
|
* Initial revision
|
*
|
*
|
* Revision 1.1.1.1 1999/11/15 13:42:32 vadim
|
* Revision 1.1.1.1 1999/11/15 13:42:32 vadim
|
* Initial import
|
* Initial import
|
*
|
*
|
*/
|
*/
|
|
|
#include <linux/module.h>
|
#include <linux/module.h>
|
#include <asm/system.h>
|
#include <asm/system.h>
|
#include <asm/io.h>
|
#include <asm/io.h>
|
#include <linux/signal.h>
|
#include <linux/signal.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
#include "../block/blk.h"
|
#include "../block/blk.h"
|
#include "scsi.h"
|
#include "scsi.h"
|
#include "hosts.h"
|
#include "hosts.h"
|
#include "oak.h"
|
#include "oak.h"
|
#include "NCR5380.h"
|
#include "NCR5380.h"
|
#include "constants.h"
|
#include "constants.h"
|
|
|
#undef START_DMA_INITIATOR_RECEIVE_REG
|
#undef START_DMA_INITIATOR_RECEIVE_REG
|
#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
|
#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
|
|
|
#include <asm/ecard.h>
|
#include <asm/ecard.h>
|
|
|
static const card_ids oakscsi_cids[] = {
|
static const card_ids oakscsi_cids[] = {
|
{ MANU_OAK, PROD_OAK_SCSI },
|
{ MANU_OAK, PROD_OAK_SCSI },
|
{ 0xffff, 0xffff }
|
{ 0xffff, 0xffff }
|
};
|
};
|
|
|
static struct proc_dir_entry proc_scsi_oakscsi = {
|
static struct proc_dir_entry proc_scsi_oakscsi = {
|
PROC_SCSI_PAS16, 7, "oakscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
|
PROC_SCSI_PAS16, 7, "oakscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
|
};
|
};
|
|
|
#define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0))
|
#define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0))
|
#define OAK_IRQ(card) (IRQ_NONE)
|
#define OAK_IRQ(card) (IRQ_NONE)
|
/*
|
/*
|
* Function : int oakscsi_detect(Scsi_Host_Template * tpnt)
|
* Function : int oakscsi_detect(Scsi_Host_Template * tpnt)
|
*
|
*
|
* Purpose : initializes oak NCR5380 driver based on the
|
* Purpose : initializes oak NCR5380 driver based on the
|
* command line / compile time port and irq definitions.
|
* command line / compile time port and irq definitions.
|
*
|
*
|
* Inputs : tpnt - template for this SCSI adapter.
|
* Inputs : tpnt - template for this SCSI adapter.
|
*
|
*
|
* Returns : 1 if a host adapter was found, 0 if not.
|
* Returns : 1 if a host adapter was found, 0 if not.
|
*
|
*
|
*/
|
*/
|
static struct expansion_card *ecs[4];
|
static struct expansion_card *ecs[4];
|
|
|
int oakscsi_detect(Scsi_Host_Template * tpnt)
|
int oakscsi_detect(Scsi_Host_Template * tpnt)
|
{
|
{
|
int count = 0;
|
int count = 0;
|
struct Scsi_Host *instance;
|
struct Scsi_Host *instance;
|
|
|
tpnt->proc_dir = &proc_scsi_oakscsi;
|
tpnt->proc_dir = &proc_scsi_oakscsi;
|
|
|
memset (ecs, 0, sizeof (ecs));
|
memset (ecs, 0, sizeof (ecs));
|
|
|
ecard_startfind ();
|
ecard_startfind ();
|
|
|
while(1) {
|
while(1) {
|
if ((ecs[count] = ecard_find(0, oakscsi_cids)) == NULL)
|
if ((ecs[count] = ecard_find(0, oakscsi_cids)) == NULL)
|
break;
|
break;
|
|
|
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
|
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
|
instance->io_port = OAK_ADDRESS(ecs[count]);
|
instance->io_port = OAK_ADDRESS(ecs[count]);
|
instance->irq = OAK_IRQ(ecs[count]);
|
instance->irq = OAK_IRQ(ecs[count]);
|
|
|
NCR5380_init(instance, 0);
|
NCR5380_init(instance, 0);
|
ecard_claim(ecs[count]);
|
ecard_claim(ecs[count]);
|
|
|
instance->n_io_port = 255;
|
instance->n_io_port = 255;
|
request_region (instance->io_port, instance->n_io_port, "Oak SCSI");
|
request_region (instance->io_port, instance->n_io_port, "Oak SCSI");
|
|
|
if (instance->irq != IRQ_NONE)
|
if (instance->irq != IRQ_NONE)
|
if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
|
if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
|
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
|
printk("scsi%d: IRQ%d not free, interrupts disabled\n",
|
instance->host_no, instance->irq);
|
instance->host_no, instance->irq);
|
instance->irq = IRQ_NONE;
|
instance->irq = IRQ_NONE;
|
}
|
}
|
|
|
if (instance->irq != IRQ_NONE) {
|
if (instance->irq != IRQ_NONE) {
|
printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
|
printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
|
printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
|
printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
|
}
|
}
|
|
|
printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
|
printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
|
if (instance->irq == IRQ_NONE)
|
if (instance->irq == IRQ_NONE)
|
printk ("s disabled");
|
printk ("s disabled");
|
else
|
else
|
printk (" %d", instance->irq);
|
printk (" %d", instance->irq);
|
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
|
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
|
CAN_QUEUE, CMD_PER_LUN, OAKSCSI_PUBLIC_RELEASE);
|
CAN_QUEUE, CMD_PER_LUN, OAKSCSI_PUBLIC_RELEASE);
|
printk("\nscsi%d:", instance->host_no);
|
printk("\nscsi%d:", instance->host_no);
|
NCR5380_print_options(instance);
|
NCR5380_print_options(instance);
|
printk("\n");
|
printk("\n");
|
|
|
++count;
|
++count;
|
}
|
}
|
#ifdef MODULE
|
#ifdef MODULE
|
if(count == 0)
|
if(count == 0)
|
printk("No oak scsi devices found\n");
|
printk("No oak scsi devices found\n");
|
#endif
|
#endif
|
return count;
|
return count;
|
}
|
}
|
|
|
int oakscsi_release (struct Scsi_Host *shpnt)
|
int oakscsi_release (struct Scsi_Host *shpnt)
|
{
|
{
|
int i;
|
int i;
|
|
|
if (shpnt->irq != IRQ_NONE)
|
if (shpnt->irq != IRQ_NONE)
|
free_irq (shpnt->irq, NULL);
|
free_irq (shpnt->irq, NULL);
|
if (shpnt->io_port)
|
if (shpnt->io_port)
|
release_region (shpnt->io_port, shpnt->n_io_port);
|
release_region (shpnt->io_port, shpnt->n_io_port);
|
|
|
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
if (shpnt->io_port == OAK_ADDRESS(ecs[i]))
|
if (shpnt->io_port == OAK_ADDRESS(ecs[i]))
|
ecard_release (ecs[i]);
|
ecard_release (ecs[i]);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
const char * oakscsi_info (struct Scsi_Host *spnt) {
|
const char * oakscsi_info (struct Scsi_Host *spnt) {
|
return "";
|
return "";
|
}
|
}
|
|
|
#define STAT(p) inw(p + 144)
|
#define STAT(p) inw(p + 144)
|
extern void inswb(int from, void *to, int len);
|
extern void inswb(int from, void *to, int len);
|
|
|
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
|
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
|
int len)
|
int len)
|
{
|
{
|
int iobase = instance->io_port;
|
int iobase = instance->io_port;
|
printk("writing %p len %d\n",addr, len);
|
printk("writing %p len %d\n",addr, len);
|
if(!len) return -1;
|
if(!len) return -1;
|
|
|
while(1)
|
while(1)
|
{
|
{
|
int status;
|
int status;
|
while(((status = STAT(iobase)) & 0x100)==0);
|
while(((status = STAT(iobase)) & 0x100)==0);
|
}
|
}
|
}
|
}
|
|
|
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
|
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
|
int len)
|
int len)
|
{
|
{
|
int iobase = instance->io_port;
|
int iobase = instance->io_port;
|
printk("reading %p len %d\n", addr, len);
|
printk("reading %p len %d\n", addr, len);
|
while(len > 0)
|
while(len > 0)
|
{
|
{
|
int status, timeout;
|
int status, timeout;
|
unsigned long b;
|
unsigned long b;
|
|
|
timeout = 0x01FFFFFF;
|
timeout = 0x01FFFFFF;
|
|
|
while(((status = STAT(iobase)) & 0x100)==0)
|
while(((status = STAT(iobase)) & 0x100)==0)
|
{
|
{
|
timeout--;
|
timeout--;
|
if(status & 0x200 || !timeout)
|
if(status & 0x200 || !timeout)
|
{
|
{
|
printk("status = %08X\n",status);
|
printk("status = %08X\n",status);
|
return 1;
|
return 1;
|
}
|
}
|
}
|
}
|
if(len >= 128)
|
if(len >= 128)
|
{
|
{
|
inswb(iobase + 136, addr, 128);
|
inswb(iobase + 136, addr, 128);
|
addr += 128;
|
addr += 128;
|
len -= 128;
|
len -= 128;
|
}
|
}
|
else
|
else
|
{
|
{
|
b = (unsigned long) inw(iobase + 136);
|
b = (unsigned long) inw(iobase + 136);
|
*addr ++ = b;
|
*addr ++ = b;
|
len -= 1;
|
len -= 1;
|
if(len)
|
if(len)
|
*addr ++ = b>>8;
|
*addr ++ = b>>8;
|
len -= 1;
|
len -= 1;
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
#define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg)))
|
#define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg)))
|
#define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg)))
|
#define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg)))
|
|
|
#undef STAT
|
#undef STAT
|
|
|
#include "NCR5380.c"
|
#include "NCR5380.c"
|
|
|
#ifdef MODULE
|
#ifdef MODULE
|
|
|
Scsi_Host_Template driver_template = OAK_NCR5380;
|
Scsi_Host_Template driver_template = OAK_NCR5380;
|
|
|
#include "scsi_module.c"
|
#include "scsi_module.c"
|
#endif
|
#endif
|
|
|