diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-03-25 23:40:36 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-03-25 23:40:36 +0000 |
commit | 7206675c40394c78a90e74812bbdbf8cf3cca1be (patch) | |
tree | 251895cf5a0008e2b4ce438cb01ad4d55fb5b97b /drivers/scsi | |
parent | beb116954b9b7f3bb56412b2494b562f02b864b1 (diff) |
Import of Linux/MIPS 2.1.14.2
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/.cvsignore | 1 | ||||
-rw-r--r-- | drivers/scsi/Makefile | 8 | ||||
-rw-r--r-- | drivers/scsi/hosts.c | 9 | ||||
-rw-r--r-- | drivers/scsi/scsi.c | 6 | ||||
-rw-r--r-- | drivers/scsi/scsicam.c | 5 | ||||
-rw-r--r-- | drivers/scsi/seagate.c | 64 | ||||
-rw-r--r-- | drivers/scsi/sgiwd93.c | 246 | ||||
-rw-r--r-- | drivers/scsi/sgiwd93.h | 52 | ||||
-rw-r--r-- | drivers/scsi/wd33c93.c | 2962 | ||||
-rw-r--r-- | drivers/scsi/wd33c93.h | 371 |
10 files changed, 1961 insertions, 1763 deletions
diff --git a/drivers/scsi/.cvsignore b/drivers/scsi/.cvsignore new file mode 100644 index 000000000..4671378ae --- /dev/null +++ b/drivers/scsi/.cvsignore @@ -0,0 +1 @@ +.depend diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 0b5489bdf..617c80f5a 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -110,6 +110,14 @@ else endif endif +ifeq ($(CONFIG_SCSI_SGIWD93),y) +L_OBJS += sgiwd93.o wd33c93.o +else + ifeq ($(CONFIG_SCSI_SGIWD93),m) + M_OBJS += sgiwd93.o wd33c93.o + endif +endif + ifeq ($(CONFIG_ATARI_SCSI),y) L_OBJS += atari_scsi.o else diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index a77fe820f..759022208 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -165,13 +165,17 @@ #include "esp.h" #endif +#ifdef CONFIG_SCSI_SGIWD93 +#include "sgiwd93.h" +#endif + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif /* -static const char RCSid[] = "$Header: /usr/src/linux-1.3.95/drivers/scsi/RCS/hosts.c,v 1.7 1996/04/25 22:21:56 root Exp root $"; +static const char RCSid[] = "$Header: /export/home0/cvs/linux/drivers/scsi/hosts.c,v 1.5 1996/08/12 11:11:54 dm Exp $"; */ /* @@ -303,6 +307,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #ifdef CONFIG_SCSI_SUNESP SCSI_SPARC_ESP, #endif +#ifdef CONFIG_SCSI_SGIWD93 + SGIWD93_SCSI, +#endif #ifdef CONFIG_SCSI_DEBUG SCSI_DEBUG, #endif diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 40140e06d..ed45a57f7 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -64,7 +64,7 @@ #undef USE_STATIC_SCSI_MEMORY /* -static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $"; +static const char RCSid[] = "$Header: /export/home0/cvs/linux/drivers/scsi/scsi.c,v 1.8 1996/08/07 02:54:28 dm Exp $"; */ @@ -416,8 +416,12 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, /* Make sure we have something that is valid for DMA purposes */ +#ifndef CONFIG_SGI scsi_result = ( ( !shpnt->unchecked_isa_dma ) ? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA)); +#else + scsi_result = (scsi_init_malloc (512, GFP_DMA)); +#endif if (scsi_result == NULL) { printk ("Unable to obtain scsi_result buffer\n"); diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 044a06b39..e45d80f4e 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -22,7 +22,6 @@ #include <linux/genhd.h> #include <linux/kernel.h> #include <linux/blk.h> -#include <asm/segment.h> #include <asm/unaligned.h> #include "scsi.h" #include "hosts.h" @@ -129,8 +128,8 @@ static int partsize(struct buffer_head *bh, unsigned long capacity, end_head * end_sector + end_sector; /* This is the actual _sector_ number at the end */ - logical_end = get_unaligned(&largest->start_sect) + - get_unaligned(&largest->nr_sects); + logical_end = get_unaligned(&largest->start_sect) + + get_unaligned(&largest->nr_sects); /* This is for >1023 cylinders */ ext_cyl= (logical_end-(end_head * end_sector + end_sector)) diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 2a4062b90..c23fdb97e 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -49,7 +49,6 @@ #include <linux/module.h> #include <asm/io.h> -#include <asm/slot.h> #include <asm/system.h> #include <linux/signal.h> #include <linux/sched.h> @@ -100,7 +99,7 @@ static int incommand; /* in some command phase. */ -static unsigned int base_address = 0; /* +static const void *base_address = NULL; /* Where the card ROM starts, used to calculate memory mapped register location. @@ -109,7 +108,7 @@ static unsigned int base_address = 0; /* static volatile int abort_confirm = 0; #endif -static unsigned int st0x_cr_sr; /* +static volatile void *st0x_cr_sr; /* control register write, status register read. 256 bytes in length. @@ -120,7 +119,7 @@ static unsigned int st0x_cr_sr; /* */ -static unsigned int st0x_dr; /* +static volatile void *st0x_dr; /* data register, read write 256 bytes in length. */ @@ -134,31 +133,31 @@ static unsigned char controller_type = 0; /* set to SEAGATE for ST0x boards or F static unsigned char irq = IRQ; #define retcode(result) (((result) << 16) | (message << 8) | status) -#define STATUS (readb(st0x_cr_sr)) +#define STATUS (*(volatile unsigned char *) st0x_cr_sr) #define CONTROL STATUS -#define DATA (readb(st0x_dr)) +#define DATA (*(volatile unsigned char *) st0x_dr) void st0x_setup (char *str, int *ints) { controller_type = SEAGATE; - base_address = ints[1]; + base_address = (void *) ints[1]; irq = ints[2]; } void tmc8xx_setup (char *str, int *ints) { controller_type = FD; - base_address = ints[1]; + base_address = (void *) ints[1]; irq = ints[2]; } #ifndef OVERRIDE -static unsigned int seagate_bases[] = { - 0xc8000, 0xca000, 0xcc000, - 0xce000, 0xdc000, 0xde000 +static const char * seagate_bases[] = { + (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, + (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000 }; typedef struct { - const unsigned char *signature ; + const char *signature ; unsigned offset; unsigned length; unsigned char type; @@ -308,7 +307,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt) if (!controller_type) { #ifdef OVERRIDE - base_address = OVERRIDE; + base_address = (void *) OVERRIDE; /* CONTROLLER is used to override controller (SEAGATE or FD). PM: 07/01/93 */ #ifdef CONTROLLER @@ -331,11 +330,12 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt) * space for the on-board RAM instead. */ - for (i = 0; i < (sizeof (seagate_bases) / sizeof (unsigned int)); ++i) + for (i = 0; i < (sizeof (seagate_bases) / sizeof (char * )); ++i) for (j = 0; !base_address && j < NUM_SIGNATURES; ++j) - if (check_signature(seagate_bases[i] + signatures[j].offset, - signatures[j].signature, signatures[j].length)) { - base_address = seagate_bases[i]; + if (!memcmp ((const void *) (seagate_bases[i] + + signatures[j].offset), (const void *) signatures[j].signature, + signatures[j].length)) { + base_address = (const void *) seagate_bases[i]; controller_type = signatures[j].type; } #endif /* OVERRIDE */ @@ -346,8 +346,8 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt) if (base_address) { - st0x_cr_sr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00); - st0x_dr = st0x_cr_sr + 0x200; + st0x_cr_sr =(void *) (((const unsigned char *) base_address) + (controller_type == SEAGATE ? 0x1a00 : 0x1c00)); + st0x_dr = (void *) (((const unsigned char *) base_address ) + (controller_type == SEAGATE ? 0x1c00 : 0x1e00)); #ifdef DEBUG printk("%s detected. Base address = %x, cr = %x, dr = %x\n", tpnt->name, base_address, st0x_cr_sr, st0x_dr); #endif @@ -364,7 +364,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt) return 0; } instance->irq = irq; - instance->io_port = base_address; + instance->io_port = (unsigned int) base_address; #ifdef SLOW_HANDSHAKE borken_init(); #endif @@ -402,7 +402,7 @@ const char *seagate_st0x_info(struct Scsi_Host * shpnt) { static char buffer[64]; sprintf(buffer, "%s at irq %d, address 0x%05X", (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR, - irq, base_address); + irq, (unsigned int)base_address); return buffer; } @@ -1091,7 +1091,6 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize) SCint->transfersize, len, data); #endif -#warning This no longer works: rewrite in C and use readbwl/writebwl __asm__(" cld; " @@ -1128,7 +1127,6 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize) * We loop as long as we are in a data out phase, there is data to send, * and BSY is still active. */ -#warning This no longer works: rewrite in C and use readbwl/writebwl __asm__ ( /* @@ -1219,7 +1217,6 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize) " len = %d, data = %08x\n", hostno, SCint->underflow, SCint->transfersize, len, data); #endif -#warning This no longer works: rewrite in C and use readbwl/writebwl __asm__(" cld; " @@ -1268,7 +1265,6 @@ if (fast && transfersize && !(len % transfersize) && (len >= transfersize) * and BSY is still active */ -#warning This no longer works: rewrite in C and use readbwl/writebwl __asm__ ( /* Local variables : @@ -1634,14 +1630,13 @@ int seagate_st0x_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags) return SCSI_RESET_WAKEUP; } -#include <asm/uaccess.h> +#include <asm/segment.h> #include "sd.h" #include <scsi/scsi_ioctl.h> int seagate_st0x_biosparam(Disk * disk, kdev_t dev, int* ip) { - unsigned char buf[256 + sizeof (Scsi_Ioctl_Command)], cmd[6], *data, *page; - Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf; - int result, formatted_sectors, total_sectors; + unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page; + int *sizes, result, formatted_sectors, total_sectors; int cylinders, heads, sectors; int capacity; @@ -1653,7 +1648,8 @@ int seagate_st0x_biosparam(Disk * disk, kdev_t dev, int* ip) { if (disk->device->scsi_level < 2) return -1; - data = sic->data; + sizes = (int *) buf; + data = (unsigned char *) (sizes + 2); cmd[0] = MODE_SENSE; cmd[1] = (disk->device->lun << 5) & 0xe5; @@ -1667,12 +1663,12 @@ int seagate_st0x_biosparam(Disk * disk, kdev_t dev, int* ip) { * 24 bytes for each mode page. */ - sic->inlen = 0; - sic->outlen = 256; + sizes[0] = 0; + sizes[1] = 256; memcpy (data, cmd, 6); - if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, sic))) { + if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { /* * The mode page lies beyond the MODE SENSE header, with length 4, and * the BLOCK DESCRIPTOR, with length header[3]. @@ -1685,7 +1681,7 @@ int seagate_st0x_biosparam(Disk * disk, kdev_t dev, int* ip) { cmd[2] = 0x03; /* Read page 3, format page current values */ memcpy (data, cmd, 6); - if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, sic))) { + if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { page = data + 4 + data[3]; sectors = (page[10] << 8) | page[11]; diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c new file mode 100644 index 000000000..83affefb6 --- /dev/null +++ b/drivers/scsi/sgiwd93.c @@ -0,0 +1,246 @@ +/* $Id: sgiwd93.c,v 1.7 1996/07/23 09:00:16 dm Exp $ + * sgiwd93.c: SGI WD93 scsi driver. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * (In all truth, Jed Schimmel wrote all this code.) + */ +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/blk.h> +#include <linux/version.h> + +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/sgi.h> +#include <asm/sgialib.h> +#include <asm/sgimc.h> +#include <asm/sgihpc.h> +#include <asm/sgint23.h> +#include <asm/irq.h> + +#include "scsi.h" +#include "hosts.h" +#include "wd33c93.h" +#include "sgiwd93.h" + +#include <linux/stat.h> + +struct hpc_chunk { + struct hpc_dma_desc desc; + unsigned long padding; +}; + +struct proc_dir_entry proc_scsi_sgiwd93 = { + PROC_SCSI_SGIWD93, 5, "SGIWD93", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +struct Scsi_Host *sgiwd93_host = NULL; + +/* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */ +static inline void write_wd33c93_count(wd33c93_regs *regp, unsigned long value) +{ + regp->SASR = WD_TRANSFER_COUNT_MSB; + regp->SCMD = ((value >> 16) & 0xff); + regp->SCMD = ((value >> 8) & 0xff); + regp->SCMD = ((value >> 0) & 0xff); +} + +static inline unsigned long read_wd33c93_count(wd33c93_regs *regp) +{ + unsigned long value; + + regp->SASR = WD_TRANSFER_COUNT_MSB; + value = ((regp->SCMD & 0xff) << 16); + value |= ((regp->SCMD & 0xff) << 8); + value |= ((regp->SCMD & 0xff) << 0); + return value; +} + +/* XXX woof! */ +static void sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + wd33c93_intr(sgiwd93_host); +} + +#undef DEBUG_DMA + +static int dma_setup(Scsi_Cmnd *cmd, int datainp) +{ + struct WD33C93_hostdata *hdata = CMDHOSTDATA(cmd); + wd33c93_regs *regp = hdata->regp; + struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->host->base; + struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->dma_bounce_buffer; + +#ifdef DEBUG_DMA + printk("dma_setup: datainp<%d> hcp<%p> ", + datainp, hcp); +#endif + + hdata->dma_dir = datainp; + + if(cmd->use_sg) { + struct scatterlist *slp = cmd->SCp.buffer; + int i, totlen = 0; + +#ifdef DEBUG_DMA + printk("SCLIST<"); +#endif + for(i = 0; i <= (cmd->use_sg - 1); i++, hcp++) { +#ifdef DEBUG_DMA + printk("[%p,%d]", slp[i].address, slp[i].length); +#endif + flush_page_to_ram((unsigned long)slp[i].address); + hcp->desc.pbuf = PHYSADDR(slp[i].address); + hcp->desc.cntinfo = (slp[i].length & HPCDMA_BCNT); + totlen += slp[i].length; + } +#ifdef DEBUG_DMA + printk(">tlen<%d>", totlen); +#endif + hdata->dma_bounce_len = totlen; /* a trick... */ + write_wd33c93_count(regp, totlen); + } else { + /* Non-scattered dma. */ +#ifdef DEBUG_DMA + printk("ONEBUF<%p,%d>", cmd->SCp.ptr, cmd->SCp.this_residual); +#endif + flush_page_to_ram((unsigned long)cmd->SCp.ptr); + hcp->desc.pbuf = PHYSADDR(cmd->SCp.ptr); + hcp->desc.cntinfo = (cmd->SCp.this_residual & HPCDMA_BCNT); + hcp++; + write_wd33c93_count(regp, cmd->SCp.this_residual); + } + + /* To make sure, if we trip an HPC bug, that we transfer + * every single byte, we tag on an extra zero length dma + * descriptor at the end of the chain. + */ + hcp->desc.pbuf = 0; + hcp->desc.cntinfo = (HPCDMA_EOX); + +#ifdef DEBUG_DMA + printk(" HPCGO\n"); +#endif + + /* Start up the HPC. */ + hregs->ndptr = PHYSADDR(hdata->dma_bounce_buffer); + if(datainp) + hregs->ctrl = (HPC3_SCTRL_ACTIVE); + else + hregs->ctrl = (HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR); + return 0; +} + +static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, + int status) +{ + struct WD33C93_hostdata *hdata = INSTHOSTDATA(instance); + wd33c93_regs *regp = hdata->regp; + struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) SCpnt->host->base; + +#ifdef DEBUG_DMA + printk("dma_stop: status<%d> ", status); +#endif + + /* First stop the HPC and flush it's FIFO. */ + if(hdata->dma_dir) { + hregs->ctrl |= HPC3_SCTRL_FLUSH; + while(hregs->ctrl & HPC3_SCTRL_ACTIVE) + barrier(); + } + hregs->ctrl = 0; + + /* See how far we got and update scatterlist state if necessary. */ + if(SCpnt->use_sg) { + struct scatterlist *slp = SCpnt->SCp.buffer; + int totlen, wd93_residual, transferred, i; + + /* Yep, we were doing the scatterlist thang. */ + totlen = hdata->dma_bounce_len; + wd93_residual = read_wd33c93_count(regp); + transferred = totlen - wd93_residual; + +#ifdef DEBUG_DMA + printk("tlen<%d>resid<%d>transf<%d> ", + totlen, wd93_residual, transferred); +#endif + + /* Avoid long winded partial-transfer search for common case. */ + if(transferred != totlen) { + /* This is the nut case. */ +#ifdef DEBUG_DMA + printk("Jed was here..."); +#endif + for(i = 0; i <= (SCpnt->use_sg - 1); i++) { + if(slp[i].length >= transferred) + break; + transferred -= slp[i].length; + } + } else { + /* This is the common case. */ +#ifdef DEBUG_DMA + printk("did it all..."); +#endif + i = (SCpnt->use_sg - 1); + } + SCpnt->SCp.buffer = &slp[i]; + SCpnt->SCp.buffers_residual = (SCpnt->use_sg - 1 - i); + SCpnt->SCp.ptr = (char *) slp[i].address; + SCpnt->SCp.this_residual = slp[i].length; + } +#ifdef DEBUG_DMA + printk("\n"); +#endif +} + +static inline void init_hpc_chain(uchar *buf) +{ + struct hpc_chunk *hcp = (struct hpc_chunk *) buf; + unsigned long start, end; + + start = (unsigned long) buf; + end = start + PAGE_SIZE; + while(start < end) { + hcp->desc.pnext = PHYSADDR((hcp + 1)); + hcp->desc.cntinfo = HPCDMA_EOX; + hcp++; + start += sizeof(struct hpc_chunk); + }; + hcp--; + hcp->desc.pnext = PHYSADDR(buf); +} + +int sgiwd93_detect(Scsi_Host_Template *HPsUX) +{ + static unsigned char called = 0; + struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0; + struct WD33C93_hostdata *hdata; + uchar *buf; + + if(called) + return 0; /* Should bitch on the console about this... */ + + HPsUX->proc_dir = &proc_scsi_sgiwd93; + + sgiwd93_host = scsi_register(HPsUX, sizeof(struct WD33C93_hostdata)); + sgiwd93_host->base = (unsigned char *) hregs; + + buf = (uchar *) get_free_page(GFP_KERNEL); + init_hpc_chain(buf); + flush_page_to_ram((unsigned long) buf); + + wd33c93_init(sgiwd93_host, (wd33c93_regs *) 0xbfbc0003, + dma_setup, dma_stop, WD33C93_FS_16_20); + + hdata = INSTHOSTDATA(sgiwd93_host); + hdata->no_sync = 0; + hdata->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); + flush_page_to_ram((unsigned long) buf); + + request_irq(1, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host); + called = 1; + + return 1; /* Found one. */ +} diff --git a/drivers/scsi/sgiwd93.h b/drivers/scsi/sgiwd93.h new file mode 100644 index 000000000..83b5a29c6 --- /dev/null +++ b/drivers/scsi/sgiwd93.h @@ -0,0 +1,52 @@ +/* $Id: sgiwd93.h,v 1.4 1996/07/14 06:43:13 dm Exp $ + * sgiwd93.h: SGI WD93 scsi definitions. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#ifndef _SGIWD93_H +#define _SGIWD93_H + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 8 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +int sgiwd93_detect(Scsi_Host_Template *); +const char *wd33c93_info(void); +int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int wd33c93_abort(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *, unsigned int); + +extern struct proc_dir_entry proc_scsi_sgiwd93; + +#define SGIWD93_SCSI {/* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc_dir_entry */ &proc_scsi_sgiwd93, \ + /* proc_info */ NULL, \ + /* name */ "SGI WD93", \ + /* detect */ sgiwd93_detect, \ + /* release */ NULL, \ + /* info */ NULL, \ + /* command */ NULL, \ + /* queuecommand */ wd33c93_queuecommand, \ + /* abort */ wd33c93_abort, \ + /* reset */ wd33c93_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ NULL, \ + /* can_queue */ CAN_QUEUE, \ + /* this_id */ 7, \ + /* sg_tablesize */ SG_ALL, \ + /* cmd_per_lun */ CMD_PER_LUN, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING \ +} + +#endif /* !(_SGIWD93_H) */ diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index fa43592c8..67cbdcf7e 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -55,20 +55,18 @@ * almost as fast while being much easier to define, track, * and debug. * - * * TODO: * more speed. linked commands. * - * * People with bug reports, wish-lists, complaints, comments, * or improvements are asked to pah-leeez email me (John Shifflett) * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get * this thing into as good a shape as possible, and I'm positive * there are lots of lurking bugs and "Stupid Places". - * */ #include <asm/system.h> +#include <linux/config.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/delay.h> @@ -93,26 +91,24 @@ */ /*#define PROC_INTERFACE*/ /* add code for /proc/scsi/wd33c93/xxx interface */ -#define SYNC_DEBUG /* extra info on sync negotiation printed */ -#define DEBUGGING_ON /* enable command-line debugging bitmask */ -#define DEBUG_DEFAULTS 0 /* default debugging bitmask */ +#undef SYNC_DEBUG /* extra info on sync negotiation printed */ +#define DEBUGGING_ON /* enable command-line debugging bitmask */ +#define DEBUG_DEFAULTS 0x00 /* default debugging bitmask */ #define WD33C93_VERSION "1.21" #define WD33C93_DATE "20/Apr/1996" #ifdef DEBUGGING_ON -#define DB(f,a) if (hostdata->args & (f)) a; +#define DB(f,a) if (hostdata->args & (f)) (a) #else #define DB(f,a) #endif -#define IS_DIR_OUT(cmd) ((cmd)->cmnd[0] == WRITE_6 || \ - (cmd)->cmnd[0] == WRITE_10 || \ - (cmd)->cmnd[0] == WRITE_12) +#define IS_DIR_OUT(cmd) (((cmd)->cmnd[0] == WRITE_6) || \ + ((cmd)->cmnd[0] == WRITE_10) || \ + ((cmd)->cmnd[0] == WRITE_12)) - -/* - * setup_strings is an array of strings that define some of the operating +/* setup_strings is an array of strings that define some of the operating * parameters and settings for this driver. It is used unless an amiboot * or insmod command line has been specified, in which case those settings * are combined with the ones here. The driver recognizes the following @@ -166,1341 +162,1250 @@ unsigned long disc_allowed_total; unsigned long disc_taken_total; #endif - -inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num) +static inline uchar read_wd33c93(wd33c93_regs *regp, uchar reg_num) { - regp->SASR = reg_num; - return(regp->SCMD); + regp->SASR = reg_num; + return regp->SCMD; } - #define READ_AUX_STAT() (regp->SASR) - -inline void write_wd33c93(wd33c93_regs *regp,uchar reg_num, uchar value) +static inline void write_wd33c93(wd33c93_regs *regp, uchar reg_num, uchar value) { - regp->SASR = reg_num; - regp->SCMD = value; + regp->SASR = reg_num; + regp->SCMD = value; } - -inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd) +static inline void write_wd33c93_cmd(wd33c93_regs *regp, uchar cmd) { - regp->SASR = WD_COMMAND; - regp->SCMD = cmd; + regp->SASR = WD_COMMAND; + regp->SCMD = cmd; } - -inline uchar read_1_byte(wd33c93_regs *regp) +static inline uchar read_1_byte(wd33c93_regs *regp) { -uchar asr; -uchar x = 0; - - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO|0x80); - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - x = read_wd33c93(regp, WD_DATA); - } while (!(asr & ASR_INT)); - return x; + uchar asr; + uchar x = 0; + + write_wd33c93(regp, WD_CONTROL, (CTRL_IDI | CTRL_EDI | CTRL_POLLED)); + write_wd33c93_cmd(regp, (WD_CMD_TRANS_INFO | 0x80)); + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + x = read_wd33c93(regp, WD_DATA); + } while (!(asr & ASR_INT)); + return x; } - -void write_wd33c93_count(wd33c93_regs *regp,unsigned long value) +static inline void write_wd33c93_count(wd33c93_regs *regp, unsigned long value) { - regp->SASR = WD_TRANSFER_COUNT_MSB; - regp->SCMD = value >> 16; - regp->SCMD = value >> 8; - regp->SCMD = value; + regp->SASR = WD_TRANSFER_COUNT_MSB; + regp->SCMD = ((value >> 16) & 0xff); + regp->SCMD = ((value >> 8) & 0xff); + regp->SCMD = ((value >> 0) & 0xff); } - -unsigned long read_wd33c93_count(wd33c93_regs *regp) +static inline unsigned long read_wd33c93_count(wd33c93_regs *regp) { -unsigned long value; + unsigned long value; - regp->SASR = WD_TRANSFER_COUNT_MSB; - value = regp->SCMD << 16; - value |= regp->SCMD << 8; - value |= regp->SCMD; - return value; + regp->SASR = WD_TRANSFER_COUNT_MSB; + value = ((regp->SCMD & 0xff) << 16); + value |= ((regp->SCMD & 0xff) << 8); + value |= ((regp->SCMD & 0xff) << 0); + return value; } - - static struct sx_period sx_table[] = { - { 1, 0x20}, - {252, 0x20}, - {376, 0x30}, - {500, 0x40}, - {624, 0x50}, - {752, 0x60}, - {876, 0x70}, - {1000,0x00}, - {0, 0} }; - -int round_period(unsigned int period) + { 1, 0x20}, + {252, 0x20}, + {376, 0x30}, + {500, 0x40}, + {624, 0x50}, + {752, 0x60}, + {876, 0x70}, + {1000,0x00}, + {0, 0} +}; + +static inline int round_period(unsigned int period) { -int x; - - for (x=1; sx_table[x].period_ns; x++) { - if ((period <= sx_table[x-0].period_ns) && - (period > sx_table[x-1].period_ns)) { - return x; - } - } - return 7; + int x; + + for (x = 1; sx_table[x].period_ns; x++) { + if ((period <= sx_table[x-0].period_ns) && + (period > sx_table[x-1].period_ns)) { + return x; + } + } + return 7; } -uchar calc_sync_xfer(unsigned int period, unsigned int offset) +static inline uchar calc_sync_xfer(unsigned int period, unsigned int offset) { -uchar result; + uchar result; - period *= 4; /* convert SDTR code to ns */ - result = sx_table[round_period(period)].reg_value; - result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF; - return result; + /* convert SDTR code to ns */ + period *= 4; + result = sx_table[round_period(period)].reg_value; + result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF; + return result; } - - void wd33c93_execute(struct Scsi_Host *instance); int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { -struct WD33C93_hostdata *hostdata; -Scsi_Cmnd *tmp; -unsigned long flags; - - - save_flags(flags); - cli(); - hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - -DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) - -/* Set up a few fields in the Scsi_Cmnd structure for our own use: - * - host_scribble is the pointer to the next cmd in the input queue - * - scsi_done points to the routine we call when a cmd is finished - * - result is what you'd expect - */ - - cmd->host_scribble = NULL; - cmd->scsi_done = done; - cmd->result = 0; - -/* We use the Scsi_Pointer structure that's included with each command - * as a scratchpad (as it's intended to be used!). The handy thing about - * the SCp.xxx fields is that they're always associated with a given - * cmd, and are preserved across disconnect-reselect. This means we - * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages - * if we keep all the critical pointers and counters in SCp: - * - SCp.ptr is the pointer into the RAM buffer - * - SCp.this_residual is the size of that buffer - * - SCp.buffer points to the current scatter-gather buffer - * - SCp.buffers_residual tells us how many S.G. buffers there are - * - SCp.have_data_in is not used - * - SCp.sent_command is not used - * - SCp.phase records this command's SRCID_ER bit setting - */ - - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *)cmd->buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; - cmd->SCp.ptr = (char *)cmd->SCp.buffer->address; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } - else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *)cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; - } - -/* Preset the command status to GOOD, since that's the normal case */ - - cmd->SCp.Status = GOOD; - - /* - * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE - * commands are added to the head of the queue so that the desired - * sense data is not lost before REQUEST_SENSE executes. - */ - - if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { - cmd->host_scribble = (uchar *)hostdata->input_Q; - hostdata->input_Q = cmd; - } - else { /* find the end of the queue */ - for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble; - tmp=(Scsi_Cmnd *)tmp->host_scribble) - ; - tmp->host_scribble = (uchar *)cmd; - } - -/* We know that there's at least one command in 'input_Q' now. - * Go see if any of them are runnable! - */ - - wd33c93_execute(cmd->host); - -DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid)) - - restore_flags(flags); - return 0; + struct WD33C93_hostdata *hostdata = CMDHOSTDATA(cmd); + Scsi_Cmnd *tmp; + unsigned long flags; + + save_flags(flags); cli(); + DB(DB_QCMD,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)); + + /* Set up a few fields in the Scsi_Cmnd structure for our own use: + * - host_scribble is the pointer to the next cmd in the input queue + * - scsi_done points to the routine we call when a cmd is finished + * - result is what you'd expect + */ + cmd->host_scribble = NULL; + cmd->scsi_done = done; + cmd->result = 0; + + /* We use the Scsi_Pointer structure that's included with each command + * as a scratchpad (as it's intended to be used!). The handy thing about + * the SCp.xxx fields is that they're always associated with a given + * cmd, and are preserved across disconnect-reselect. This means we + * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages + * if we keep all the critical pointers and counters in SCp: + * - SCp.ptr is the pointer into the RAM buffer + * - SCp.this_residual is the size of that buffer + * - SCp.buffer points to the current scatter-gather buffer + * - SCp.buffers_residual tells us how many S.G. buffers there are + * - SCp.have_data_in is not used + * - SCp.sent_command is not used + * - SCp.phase records this command's SRCID_ER bit setting + */ + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } + + /* Preset the command status to GOOD, since that's the normal case */ + cmd->SCp.Status = GOOD; + + /* Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE + * commands are added to the head of the queue so that the desired + * sense data is not lost before REQUEST_SENSE executes. + */ + if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { + cmd->host_scribble = (uchar *) hostdata->input_Q; + hostdata->input_Q = cmd; + } else { + /* find the end of the queue */ + for (tmp = (Scsi_Cmnd *) hostdata->input_Q; + tmp->host_scribble; + tmp = (Scsi_Cmnd *) tmp->host_scribble) + ; + tmp->host_scribble = (uchar *) cmd; + } + + /* We know that there's at least one command in 'input_Q' now. + * Go see if any of them are runnable! + */ + wd33c93_execute(cmd->host); + + DB(DB_QCMD,printk(")Q-%ld ",cmd->pid)); + restore_flags(flags); + return 0; } - - -/* - * This routine attempts to start a scsi command. If the host_card is +/* This routine attempts to start a scsi command. If the host_card is * already connected, we give up immediately. Otherwise, look through * the input_Q, using the first command we find that's intended * for a currently non-busy target/lun. */ -void wd33c93_execute (struct Scsi_Host *instance) +void wd33c93_execute(struct Scsi_Host *instance) { -struct WD33C93_hostdata *hostdata; -wd33c93_regs *regp; -Scsi_Cmnd *cmd, *prev; -unsigned long flags; -int i; - - - save_flags(flags); - cli(); - hostdata = (struct WD33C93_hostdata *)instance->hostdata; - regp = hostdata->regp; - -DB(DB_EXECUTE,printk("EX(")) - - if (hostdata->selecting || hostdata->connected) { - -DB(DB_EXECUTE,printk(")EX-0 ")) - - restore_flags(flags); - return; - } - - /* - * Search through the input_Q for a command destined - * for an idle target/lun. - */ - - cmd = (Scsi_Cmnd *)hostdata->input_Q; - prev = 0; - while (cmd) { - if (!(hostdata->busy[cmd->target] & (1 << cmd->lun))) - break; - prev = cmd; - cmd = (Scsi_Cmnd *)cmd->host_scribble; - } - - /* quit if queue empty or all possible targets are busy */ - - if (!cmd) { - -DB(DB_EXECUTE,printk(")EX-1 ")) - - restore_flags(flags); - return; - } - - /* remove command from queue */ - - if (prev) - prev->host_scribble = cmd->host_scribble; - else - hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble; - - /* - * Start the selection process - */ - - if (IS_DIR_OUT(cmd)) - write_wd33c93(regp, WD_DESTINATION_ID, cmd->target); - else - write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD); - -/* Now we need to figure out whether or not this command is a good - * candidate for disconnect/reselect. We guess to the best of our - * ability, based on a set of hierarchical rules. When several - * devices are operating simultaneously, disconnects are usually - * an advantage. In a single device system, or if only 1 device - * is being accessed, transfers usually go faster if disconnects - * are not allowed: - * - * + Commands should NEVER disconnect if hostdata->disconnect = - * DIS_NEVER (this holds for tape drives also), and ALWAYS - * disconnect if hostdata->disconnect = DIS_ALWAYS. - * + Tape drive commands should always be allowed to disconnect. - * + Disconnect should be allowed if disconnected_Q isn't empty. - * + Commands should NOT disconnect if input_Q is empty. - * + Disconnect should be allowed if there are commands in input_Q - * for a different target/lun. In this case, the other commands - * should be made disconnect-able, if not already. - * - * I know, I know - this code would flunk me out of any - * "C Programming 101" class ever offered. But it's easy - * to change around and experiment with for now. - */ - - cmd->SCp.phase = 0; /* assume no disconnect */ - if (hostdata->disconnect == DIS_NEVER) - goto no; - if (hostdata->disconnect == DIS_ALWAYS) - goto yes; - if (cmd->device->type == 1) /* tape drive? */ - goto yes; - if (hostdata->disconnected_Q) /* other commands disconnected? */ - goto yes; - if (!(hostdata->input_Q)) /* input_Q empty? */ - goto no; - for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev; - prev=(Scsi_Cmnd *)prev->host_scribble) { - if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) { - for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev; - prev=(Scsi_Cmnd *)prev->host_scribble) - prev->SCp.phase = 1; - goto yes; - } - } - goto no; + struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance); + wd33c93_regs *regp = hostdata->regp; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->input_Q; + Scsi_Cmnd *prev = 0; + unsigned long flags; + int i; + + save_flags(flags); cli(); + DB(DB_EXECUTE, printk("EX(")); + + if (hostdata->selecting || hostdata->connected) { + DB(DB_EXECUTE, printk(")EX-0 ")); + goto execute_out; + } + + /* Search through the input_Q for a command destined + * for an idle target/lun. + */ + while (cmd) { + if (!(hostdata->busy[cmd->target] & (1 << cmd->lun))) + break; + prev = cmd; + cmd = (Scsi_Cmnd *) cmd->host_scribble; + } + + /* Quit if queue empty or all possible targets are busy. */ + if (!cmd) { + DB(DB_EXECUTE, printk(")EX-1 ")); + goto execute_out; + } + + /* Remove command from queue. */ + if (prev) + prev->host_scribble = cmd->host_scribble; + else + hostdata->input_Q = (Scsi_Cmnd *) cmd->host_scribble; + + /* Start the selection process. */ + if (IS_DIR_OUT(cmd)) + write_wd33c93(regp, WD_DESTINATION_ID, cmd->target); + else + write_wd33c93(regp, WD_DESTINATION_ID, (cmd->target | DSTID_DPD)); + + /* Now we need to figure out whether or not this command is a good + * candidate for disconnect/reselect. We guess to the best of our + * ability, based on a set of hierarchical rules. When several + * devices are operating simultaneously, disconnects are usually + * an advantage. In a single device system, or if only 1 device + * is being accessed, transfers usually go faster if disconnects + * are not allowed: + * + * + Commands should NEVER disconnect if hostdata->disconnect = + * DIS_NEVER (this holds for tape drives also), and ALWAYS + * disconnect if hostdata->disconnect = DIS_ALWAYS. + * + Tape drive commands should always be allowed to disconnect. + * + Disconnect should be allowed if disconnected_Q isn't empty. + * + Commands should NOT disconnect if input_Q is empty. + * + Disconnect should be allowed if there are commands in input_Q + * for a different target/lun. In this case, the other commands + * should be made disconnect-able, if not already. + * + * I know, I know - this code would flunk me out of any + * "C Programming 101" class ever offered. But it's easy + * to change around and experiment with for now. + */ + cmd->SCp.phase = 0; /* assume no disconnect */ + if (hostdata->disconnect == DIS_NEVER) + goto no; + if ((hostdata->disconnect == DIS_ALWAYS) || (cmd->device->type == 1) || + (hostdata->disconnected_Q)) + goto yes; + if (!(hostdata->input_Q)) /* input_Q empty? */ + goto no; + for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev; + prev=(Scsi_Cmnd *)prev->host_scribble) { + if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) { + for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev; + prev=(Scsi_Cmnd *)prev->host_scribble) + prev->SCp.phase = 1; + goto yes; + } + } + goto no; yes: - cmd->SCp.phase = 1; + cmd->SCp.phase = 1; #ifdef PROC_INTERFACE - disc_allowed_total++; + disc_allowed_total++; #endif no: - write_wd33c93(regp, WD_SOURCE_ID, ((cmd->SCp.phase)?SRCID_ER:0)); - - write_wd33c93(regp, WD_TARGET_LUN, cmd->lun); - write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]); - hostdata->busy[cmd->target] |= (1 << cmd->lun); - - if ((hostdata->level2 == L2_NONE) || - (hostdata->sync_stat[cmd->target] == SS_UNSET)) { - - /* - * Do a 'Select-With-ATN' command. This will end with - * one of the following interrupts: - * CSR_RESEL_AM: failure - can try again later. - * CSR_TIMEOUT: failure - give up. - * CSR_SELECT: success - proceed. - */ - - hostdata->selecting = cmd; - -/* Every target has its own synchronous transfer setting, kept in the - * sync_xfer array, and a corresponding status byte in sync_stat[]. - * Each target's sync_stat[] entry is initialized to SX_UNSET, and its - * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET - * means that the parameters are undetermined as yet, and that we - * need to send an SDTR message to this device after selection is - * complete. We set SS_FIRST to tell the interrupt routine to do so, - * unless we've been asked not to try synchronous transfers on this - * target (and _all_ luns within it): In this case we set SS_SET to - * make the defaults final. - */ - if (hostdata->sync_stat[cmd->target] == SS_UNSET) { - if (hostdata->no_sync & (1 << cmd->target)) - hostdata->sync_stat[cmd->target] = SS_SET; - else - hostdata->sync_stat[cmd->target] = SS_FIRST; - } - hostdata->state = S_SELECTING; - write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */ - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN); - } - - else { - - /* - * Do a 'Select-With-ATN-Xfer' command. This will end with - * one of the following interrupts: - * CSR_RESEL_AM: failure - can try again later. - * CSR_TIMEOUT: failure - give up. - * anything else: success - proceed. - */ - - hostdata->connected = cmd; - write_wd33c93(regp, WD_COMMAND_PHASE, 0); - - /* copy command_descriptor_block into WD chip - * (take advantage of auto-incrementing) - */ - - regp->SASR = WD_CDB_1; - for (i=0; i<cmd->cmd_len; i++) - regp->SCMD = cmd->cmnd[i]; - - /* The wd33c93 only knows about Group 0, 1, and 5 commands when - * it's doing a 'select-and-transfer'. To be safe, we write the - * size of the CDB into the OWN_ID register for every case. This - * way there won't be problems with vendor-unique, audio, etc. - */ - - write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len); - - /* When doing a non-disconnect command, we can save ourselves a DATA - * phase interrupt later by setting everything up now. - */ - - if (cmd->SCp.phase == 0) { - if (hostdata->dma_setup(cmd, - (IS_DIR_OUT(cmd))?DATA_OUT_DIR:DATA_IN_DIR)) - write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */ - else { - write_wd33c93_count(regp, cmd->SCp.this_residual); - write_wd33c93(regp,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); - hostdata->dma = D_DMA_RUNNING; - } - } - else - write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */ - - hostdata->state = S_RUNNING_LEVEL2; - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); - } - - /* - * Since the SCSI bus can handle only 1 connection at a time, - * we get out of here now. If the selection fails, or when - * the command disconnects, we'll come back to this routine - * to search the input_Q again... - */ - -DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid)) - - restore_flags(flags); + write_wd33c93(regp, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0)); + write_wd33c93(regp, WD_TARGET_LUN, cmd->lun); + write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER, + hostdata->sync_xfer[cmd->target]); + + hostdata->busy[cmd->target] |= (1 << cmd->lun); + if ((hostdata->level2 == L2_NONE) || + (hostdata->sync_stat[cmd->target] == SS_UNSET)) { + /* Do a 'Select-With-ATN' command. This will end with + * one of the following interrupts: + * CSR_RESEL_AM: failure - can try again later. + * CSR_TIMEOUT: failure - give up. + * CSR_SELECT: success - proceed. + */ + hostdata->selecting = cmd; + + /* Every target has its own synchronous transfer + * setting, kept in the sync_xfer array, and a + * corresponding status byte in sync_stat[]. Each + * target's sync_stat[] entry is initialized to + * SX_UNSET, and its sync_xfer[] entry is initialized + * to the default/safe value. SS_UNSET means that the + * parameters are undetermined as yet, and that we + * need to send an SDTR message to this device after + * selection is complete. We set SS_FIRST to tell the + * interrupt routine to do so, unless we've been asked + * not to try synchronous transfers on this target + * (and _all_ luns within it): In this case we set + * SS_SET to make the defaults final. + */ + if (hostdata->sync_stat[cmd->target] == SS_UNSET) { + if (hostdata->no_sync & (1 << cmd->target)) + hostdata->sync_stat[cmd->target] = SS_SET; + else + hostdata->sync_stat[cmd->target] = SS_FIRST; + } + hostdata->state = S_SELECTING; + + /* guarantee a DATA_PHASE interrupt */ + write_wd33c93_count(regp, 0); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN); + } else { + /* Do a 'Select-With-ATN-Xfer' command. This will end with + * one of the following interrupts: + * CSR_RESEL_AM: failure - can try again later. + * CSR_TIMEOUT: failure - give up. + * anything else: success - proceed. + */ + hostdata->connected = cmd; + write_wd33c93(regp, WD_COMMAND_PHASE, 0); + + /* copy command_descriptor_block into WD chip + * (take advantage of auto-incrementing) + */ + regp->SASR = WD_CDB_1; + for (i = 0; i < cmd->cmd_len; i++) + regp->SCMD = cmd->cmnd[i]; + + /* The wd33c93 only knows about Group 0, 1, and 5 commands when + * it's doing a 'select-and-transfer'. To be safe, we write the + * size of the CDB into the OWN_ID register for every case. This + * way there won't be problems with vendor-unique, audio, etc. + */ + write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len); + + /* When doing a non-disconnect command, we can save ourselves + * a DATA phase interrupt later by setting everything up now. + */ + if (cmd->SCp.phase == 0) { + if (hostdata->dma_setup(cmd, (IS_DIR_OUT(cmd)) ? + DATA_OUT_DIR : DATA_IN_DIR)) { + /* guarantee a DATA_PHASE interrupt */ + write_wd33c93_count(regp, 0); + } else { + /* write_wd33c93_count(regp, cmd->SCp.this_residual); */ + write_wd33c93(regp, WD_CONTROL, + (CTRL_IDI | CTRL_EDI | CTRL_DMA)); + hostdata->dma = D_DMA_RUNNING; + } + } else { + /* guarantee a DATA_PHASE interrupt */ + write_wd33c93_count(regp, 0); + } + + hostdata->state = S_RUNNING_LEVEL2; + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + } + + /* Since the SCSI bus can handle only 1 connection at a time, + * we get out of here now. If the selection fails, or when + * the command disconnects, we'll come back to this routine + * to search the input_Q again... + */ + DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:":"", cmd->pid)); +execute_out: + restore_flags(flags); } - - void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt, int data_in_dir, struct WD33C93_hostdata *hostdata) { -uchar asr; - -DB(DB_TRANSFER,printk("(%p,%d,%s)",buf,cnt,data_in_dir?"in":"out")) - - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_count(regp,cnt); - write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); - if (data_in_dir) { - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - *buf++ = read_wd33c93(regp, WD_DATA); - } while (!(asr & ASR_INT)); - } - else { - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - write_wd33c93(regp, WD_DATA, *buf++); - } while (!(asr & ASR_INT)); - } - - /* Note: we are returning with the interrupt UN-cleared. - * Since (presumably) an entire I/O operation has - * completed, the bus phase is probably different, and - * the interrupt routine will discover this when it - * responds to the uncleared int. - */ - + uchar asr; + + DB(DB_TRANS,printk("(%p,%d,%s)", buf, cnt, (data_in_dir ? "in" : "out"))); + write_wd33c93(regp, WD_CONTROL, (CTRL_IDI | CTRL_EDI | CTRL_POLLED)); + write_wd33c93_count(regp, cnt); + write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); + if (data_in_dir) { + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + *buf++ = read_wd33c93(regp, WD_DATA); + } while (!(asr & ASR_INT)); + } else { + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + write_wd33c93(regp, WD_DATA, *buf++); + } while (!(asr & ASR_INT)); + } + /* Note: we are returning with the interrupt UN-cleared. + * Since (presumably) an entire I/O operation has + * completed, the bus phase is probably different, and + * the interrupt routine will discover this when it + * responds to the uncleared int. + */ } - - void transfer_bytes(wd33c93_regs *regp, Scsi_Cmnd *cmd, int data_in_dir) { -struct WD33C93_hostdata *hostdata; - - hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata; - -/* Normally, you'd expect 'this_residual' to be non-zero here. - * In a series of scatter-gather transfers, however, this - * routine will usually be called with 'this_residual' equal - * to 0 and 'buffers_residual' non-zero. This means that a - * previous transfer completed, clearing 'this_residual', and - * now we need to setup the next scatter-gather buffer as the - * source or destination for THIS transfer. - */ - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; - } - - write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]); - -/* 'dma_setup()' will return TRUE if we can't do DMA. */ - - if (hostdata->dma_setup(cmd, data_in_dir)) { - transfer_pio(regp, (uchar *)&cmd->SCp.ptr, cmd->SCp.this_residual, - data_in_dir, hostdata); - } - -/* We are able to do DMA (in fact, the Amiga hardware is - * already going!), so start up the wd33c93 in DMA mode. - * We set 'hostdata->dma' = D_DMA_RUNNING so that when the - * transfer completes and causes an interrupt, we're - * reminded to tell the Amiga to shut down its end. We'll - * postpone the updating of 'this_residual' and 'ptr' - * until then. - */ - - else { - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); - write_wd33c93_count(regp,cmd->SCp.this_residual); - - if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) { - write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } - else - write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); - - hostdata->dma = D_DMA_RUNNING; - } + struct WD33C93_hostdata *hostdata = CMDHOSTDATA(cmd); + + /* Normally, you'd expect 'this_residual' to be non-zero here. + * In a series of scatter-gather transfers, however, this + * routine will usually be called with 'this_residual' equal + * to 0 and 'buffers_residual' non-zero. This means that a + * previous transfer completed, clearing 'this_residual', and + * now we need to setup the next scatter-gather buffer as the + * source or destination for THIS transfer. + */ + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; + } + + write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER, + hostdata->sync_xfer[cmd->target]); + + /* 'dma_setup()' will return TRUE if we can't do DMA. */ + if (hostdata->dma_setup(cmd, data_in_dir)) { + transfer_pio(regp, (uchar *) cmd->SCp.ptr, + cmd->SCp.this_residual, data_in_dir, hostdata); + } else { + /* We are able to do DMA (in fact, the Amiga hardware is + * already going!), so start up the wd33c93 in DMA mode. + * We set 'hostdata->dma' = D_DMA_RUNNING so that when the + * transfer completes and causes an interrupt, we're + * reminded to tell the Amiga to shut down its end. We'll + * postpone the updating of 'this_residual' and 'ptr' + * until then. + */ + write_wd33c93(regp, WD_CONTROL, (CTRL_IDI | CTRL_EDI | CTRL_DMA)); + /* write_wd33c93_count(regp, cmd->SCp.this_residual); */ + + if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) { + write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + hostdata->state = S_RUNNING_LEVEL2; + } else { + write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); + } + hostdata->dma = D_DMA_RUNNING; + } } - +#ifdef CONFIG_SGI +#define NOINTS_IN_WDINTR +#endif void wd33c93_intr (struct Scsi_Host *instance) { -struct WD33C93_hostdata *hostdata; -Scsi_Cmnd *patch, *cmd; -wd33c93_regs *regp; -unsigned long flags; -uchar asr, sr, phs, id, lun, *ucp, msg; -unsigned long length; - - - hostdata = (struct WD33C93_hostdata *)instance->hostdata; - regp = hostdata->regp; - - asr = READ_AUX_STAT(); - if (!(asr & ASR_INT) || (asr & ASR_BSY)) - return; - -/* OK - it should be safe to re-enable system interrupts */ - - save_flags(flags); - sti(); - - cmd = (Scsi_Cmnd *)hostdata->connected; /* assume we're connected */ - sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear the interrupt */ - phs = read_wd33c93(regp, WD_COMMAND_PHASE); - -DB(DB_INTR,printk("{%02x:%02x-",asr,sr)) - -/* After starting a DMA transfer, the next interrupt - * is guaranteed to be in response to completion of - * the transfer. Since the Amiga DMA hardware runs in - * in an open-ended fashion, it needs to be told when - * to stop; do that here if D_DMA_RUNNING is true. - * Also, we have to update 'this_residual' and 'ptr' - * based on the contents of the TRANSFER_COUNT register, - * in case the device decided to do an intermediate - * disconnect (a device may do this if it has to do a - * seek, or just to be nice and let other devices have - * some bus time during long transfers). After doing - * whatever is needed, we go on and service the WD3393 - * interrupt normally. - */ - - if (hostdata->dma == D_DMA_RUNNING) { -DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual)) - hostdata->dma_stop(cmd->host, cmd, 1); - hostdata->dma = D_DMA_OFF; - length = cmd->SCp.this_residual; - cmd->SCp.this_residual = read_wd33c93_count(regp); - cmd->SCp.ptr += (length - cmd->SCp.this_residual); -DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) - } - -/* Respond to the specific WD3393 interrupt - there are quite a few! */ - - switch (sr) { - - case CSR_TIMEOUT: -DB(DB_INTR,printk("TIMEOUT")) - - cli(); - if (hostdata->state == S_RUNNING_LEVEL2) - hostdata->connected = NULL; - else { - cmd = (Scsi_Cmnd *)hostdata->selecting; /* get a valid cmd */ - hostdata->selecting = NULL; - } - - cmd->result = DID_NO_CONNECT << 16; - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - hostdata->state = S_UNCONNECTED; - cmd->scsi_done(cmd); - -/* We are not connected to a target - check to see if there - * are commands waiting to be executed. - */ - - sti(); - wd33c93_execute(instance); - break; - - -/* Note: this interrupt should not occur in a LEVEL2 command */ + struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance); + wd33c93_regs *regp = hostdata->regp; + Scsi_Cmnd *patch, *cmd; + uchar asr, sr, phs, id, lun, *ucp, msg; + unsigned long length; +#ifndef NOINTS_IN_WDINTR + unsigned long flags; +#endif - case CSR_SELECT: - cli(); -DB(DB_INTR,printk("SELECT")) - hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting; - hostdata->selecting = NULL; + asr = READ_AUX_STAT(); + if (!(asr & ASR_INT) || (asr & ASR_BSY)) + return; - /* construct an IDENTIFY message with correct disconnect bit */ +#ifndef NOINTS_IN_WDINTR + /* OK - it should be safe to re-enable system interrupts */ + save_flags(flags); sti(); +#endif - hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun); - if (cmd->SCp.phase) - hostdata->outgoing_msg[0] |= 0x40; + cmd = (Scsi_Cmnd *) hostdata->connected; /* assume we're connected */ + sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear the interrupt */ + phs = read_wd33c93(regp, WD_COMMAND_PHASE); + DB(DB_INTR,printk("{%02x:%02x-", asr, sr)); + + /* After starting a DMA transfer, the next interrupt + * is guaranteed to be in response to completion of + * the transfer. Since the Amiga DMA hardware runs in + * in an open-ended fashion, it needs to be told when + * to stop; do that here if D_DMA_RUNNING is true. + * Also, we have to update 'this_residual' and 'ptr' + * based on the contents of the TRANSFER_COUNT register, + * in case the device decided to do an intermediate + * disconnect (a device may do this if it has to do a + * seek, or just to be nice and let other devices have + * some bus time during long transfers). After doing + * whatever is needed, we go on and service the WD3393 + * interrupt normally. + */ + if (hostdata->dma == D_DMA_RUNNING) { + DB(DB_TRANS,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual)); + hostdata->dma_stop(cmd->host, cmd, 1); + hostdata->dma = D_DMA_OFF; + length = cmd->SCp.this_residual; + cmd->SCp.this_residual = read_wd33c93_count(regp); + cmd->SCp.ptr += (length - cmd->SCp.this_residual); + DB(DB_TRANS,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)); + } + + /* Respond to the specific WD3393 interrupt - there are quite a few! */ + switch (sr) { + case CSR_TIMEOUT: + DB(DB_INTR, printk("TIMEOUT")); + +#ifndef NOINTS_IN_WDINTR + cli(); +#endif + if (hostdata->state == S_RUNNING_LEVEL2) { + hostdata->connected = NULL; + } else { + /* get a valid cmd */ + cmd = (Scsi_Cmnd *) hostdata->selecting; + hostdata->selecting = NULL; + } + cmd->result = (DID_NO_CONNECT << 16); + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + cmd->scsi_done(cmd); + + /* We are not connected to a target - check to see if there + * are commands waiting to be executed. + */ +#ifndef NOINTS_IN_WDINTR + sti(); +#endif + wd33c93_execute(instance); + break; - if (hostdata->sync_stat[cmd->target] == SS_FIRST) { + case CSR_SELECT: + /* Note: this interrupt should not occur in a LEVEL2 command */ +#ifndef NOINTS_IN_WDINTR + cli(); +#endif + DB(DB_INTR, printk("SELECT")); + hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting; + hostdata->selecting = NULL; + + /* construct an IDENTIFY message with correct disconnect bit */ + hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun); + if (cmd->SCp.phase) + hostdata->outgoing_msg[0] |= 0x40; + if (hostdata->sync_stat[cmd->target] == SS_FIRST) { #ifdef SYNC_DEBUG -printk(" sending SDTR "); + printk(" sending SDTR "); #endif - - hostdata->sync_stat[cmd->target] = SS_WAITING; - - /* tack on a 2nd message to ask about synchronous transfers */ - - hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[2] = 3; - hostdata->outgoing_msg[3] = EXTENDED_SDTR; - hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4; - hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; - hostdata->outgoing_len = 6; - } - else - hostdata->outgoing_len = 1; - - hostdata->state = S_CONNECTED; - break; - - - case CSR_XFER_DONE|PHS_DATA_IN: - case CSR_UNEXP |PHS_DATA_IN: - case CSR_SRV_REQ |PHS_DATA_IN: -DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) - transfer_bytes(regp, cmd, DATA_IN_DIR); - if (hostdata->state != S_RUNNING_LEVEL2) - hostdata->state = S_CONNECTED; - break; - - - case CSR_XFER_DONE|PHS_DATA_OUT: - case CSR_UNEXP |PHS_DATA_OUT: - case CSR_SRV_REQ |PHS_DATA_OUT: -DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) - transfer_bytes(regp, cmd, DATA_OUT_DIR); - if (hostdata->state != S_RUNNING_LEVEL2) - hostdata->state = S_CONNECTED; - break; - - -/* Note: this interrupt should not occur in a LEVEL2 command */ - - case CSR_XFER_DONE|PHS_COMMAND: - case CSR_UNEXP |PHS_COMMAND: - case CSR_SRV_REQ |PHS_COMMAND: -DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid)) - transfer_pio(regp, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); - hostdata->state = S_CONNECTED; - break; - - - case CSR_XFER_DONE|PHS_STATUS: - case CSR_UNEXP |PHS_STATUS: - case CSR_SRV_REQ |PHS_STATUS: -DB(DB_INTR,printk("STATUS")) - - cmd->SCp.Status = read_1_byte(regp); - if (hostdata->level2 >= L2_BASIC) { - sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ - hostdata->state = S_RUNNING_LEVEL2; - write_wd33c93(regp, WD_COMMAND_PHASE, 0x50); - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); - } - else { -DB(DB_INTR,printk("=%02x",cmd->SCp.Status)) - hostdata->state = S_CONNECTED; - } - break; - - - case CSR_XFER_DONE|PHS_MESS_IN: - case CSR_UNEXP |PHS_MESS_IN: - case CSR_SRV_REQ |PHS_MESS_IN: -DB(DB_INTR,printk("MSG_IN=")) - - cli(); - msg = read_1_byte(regp); - sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ - - hostdata->incoming_msg[hostdata->incoming_ptr] = msg; - if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) - msg = EXTENDED_MESSAGE; - else - hostdata->incoming_ptr = 0; - - cmd->SCp.Message = msg; - switch (msg) { - - case COMMAND_COMPLETE: -DB(DB_INTR,printk("CCMP-%ld",cmd->pid)) - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_PRE_CMP_DISC; - break; - - case SAVE_POINTERS: -DB(DB_INTR,printk("SDP")) - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - - case RESTORE_POINTERS: -DB(DB_INTR,printk("RDP")) - if (hostdata->level2 >= L2_BASIC) { - write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } - else { - write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - case DISCONNECT: -DB(DB_INTR,printk("DIS")) - cmd->device->disconnect = 1; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_PRE_TMP_DISC; - break; - - case MESSAGE_REJECT: -DB(DB_INTR,printk("REJ")) + hostdata->sync_stat[cmd->target] = SS_WAITING; + + /* tack on a 2nd message to ask about + * synchronous transfers + */ + hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; + hostdata->outgoing_msg[2] = 3; + hostdata->outgoing_msg[3] = EXTENDED_SDTR; + hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4; + hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; + hostdata->outgoing_len = 6; + } else { + hostdata->outgoing_len = 1; + } + hostdata->state = S_CONNECTED; + break; + + case CSR_XFER_DONE|PHS_DATA_IN: + case CSR_UNEXP |PHS_DATA_IN: + case CSR_SRV_REQ |PHS_DATA_IN: + DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)); + transfer_bytes(regp, cmd, DATA_IN_DIR); + if (hostdata->state != S_RUNNING_LEVEL2) + hostdata->state = S_CONNECTED; + break; + + case CSR_XFER_DONE|PHS_DATA_OUT: + case CSR_UNEXP |PHS_DATA_OUT: + case CSR_SRV_REQ |PHS_DATA_OUT: + DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)); + transfer_bytes(regp, cmd, DATA_OUT_DIR); + if (hostdata->state != S_RUNNING_LEVEL2) + hostdata->state = S_CONNECTED; + break; + + case CSR_XFER_DONE|PHS_COMMAND: + case CSR_UNEXP |PHS_COMMAND: + case CSR_SRV_REQ |PHS_COMMAND: + /* Note: this interrupt should not occur in a LEVEL2 command */ + DB(DB_INTR,printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid)); + transfer_pio(regp, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); + hostdata->state = S_CONNECTED; + break; + + case CSR_XFER_DONE|PHS_STATUS: + case CSR_UNEXP |PHS_STATUS: + case CSR_SRV_REQ |PHS_STATUS: + DB(DB_INTR,printk("STATUS")); + cmd->SCp.Status = read_1_byte(regp); + if (hostdata->level2 >= L2_BASIC) { + /* clear interrupt */ + sr = read_wd33c93(regp, WD_SCSI_STATUS); + hostdata->state = S_RUNNING_LEVEL2; + write_wd33c93(regp, WD_COMMAND_PHASE, 0x50); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + } else { + DB(DB_INTR, printk("=%02x", cmd->SCp.Status)); + hostdata->state = S_CONNECTED; + } + break; + + case CSR_XFER_DONE|PHS_MESS_IN: + case CSR_UNEXP |PHS_MESS_IN: + case CSR_SRV_REQ |PHS_MESS_IN: + DB(DB_INTR, printk("MSG_IN=")); + +#ifndef NOINTS_IN_WDINTR + cli(); +#endif + msg = read_1_byte(regp); + sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ + + hostdata->incoming_msg[hostdata->incoming_ptr] = msg; + if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) + msg = EXTENDED_MESSAGE; + else + hostdata->incoming_ptr = 0; + + cmd->SCp.Message = msg; + switch (msg) { + case COMMAND_COMPLETE: + DB(DB_INTR,printk("CCMP-%ld", cmd->pid)); + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_PRE_CMP_DISC; + break; + + case SAVE_POINTERS: + DB(DB_INTR,printk("SDP")); + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + + case RESTORE_POINTERS: + DB(DB_INTR,printk("RDP")); + if (hostdata->level2 >= L2_BASIC) { + write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + hostdata->state = S_RUNNING_LEVEL2; + } else { + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + } + break; + + case DISCONNECT: + DB(DB_INTR,printk("DIS")); + cmd->device->disconnect = 1; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_PRE_TMP_DISC; + break; + + case MESSAGE_REJECT: + DB(DB_INTR,printk("REJ")); #ifdef SYNC_DEBUG -printk("-REJ-"); + printk("-REJ-"); #endif - if (hostdata->sync_stat[cmd->target] == SS_WAITING) - hostdata->sync_stat[cmd->target] = SS_SET; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - - case EXTENDED_MESSAGE: -DB(DB_INTR,printk("EXT")) - - ucp = hostdata->incoming_msg; - + if (hostdata->sync_stat[cmd->target] == SS_WAITING) + hostdata->sync_stat[cmd->target] = SS_SET; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + + case EXTENDED_MESSAGE: + DB(DB_INTR,printk("EXT")); + ucp = hostdata->incoming_msg; #ifdef SYNC_DEBUG -printk("%02x",ucp[hostdata->incoming_ptr]); + printk("%02x",ucp[hostdata->incoming_ptr]); #endif - /* Is this the last byte of the extended message? */ - - if ((hostdata->incoming_ptr >= 2) && - (hostdata->incoming_ptr == (ucp[1] + 1))) { - - switch (ucp[2]) { /* what's the EXTENDED code? */ - case EXTENDED_SDTR: - id = calc_sync_xfer(ucp[3],ucp[4]); - if (hostdata->sync_stat[cmd->target] != SS_WAITING) { - -/* A device has sent an unsolicited SDTR message; rather than go - * through the effort of decoding it and then figuring out what - * our reply should be, we're just gonna say that we have a - * synchronous fifo depth of 0. This will result in asynchronous - * transfers - not ideal but so much easier. - * Actually, this is OK because it assures us that if we don't - * specifically ask for sync transfers, we won't do any. - */ - - write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[1] = 3; - hostdata->outgoing_msg[2] = EXTENDED_SDTR; - hostdata->outgoing_msg[3] = hostdata->default_sx_per/4; - hostdata->outgoing_msg[4] = 0; - hostdata->outgoing_len = 5; - hostdata->sync_xfer[cmd->target] = - calc_sync_xfer(hostdata->default_sx_per/4,0); - } - else { - hostdata->sync_xfer[cmd->target] = id; - } + /* Is this the last byte of the extended message? */ + if ((hostdata->incoming_ptr >= 2) && + (hostdata->incoming_ptr == (ucp[1] + 1))) { + switch (ucp[2]) { /* what's the EXTENDED code? */ + case EXTENDED_SDTR: + id = calc_sync_xfer(ucp[3],ucp[4]); + if (hostdata->sync_stat[cmd->target] != + SS_WAITING) { + /* A device has sent + * an unsolicited SDTR + * message; rather + * than go through the + * effort of decoding + * it and then + * figuring out what + * our reply should + * be, we're just + * gonna say that we + * have a synchronous + * fifo depth of + * 0. This will result + * in asynchronous + * transfers - not + * ideal but so much + * easier. Actually, + * this is OK because + * it assures us that + * if we don't + * specifically ask + * for sync transfers, + * we won't do any. */ + + /* want MESS_OUT */ + write_wd33c93_cmd(regp, + WD_CMD_ASSERT_ATN); + hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; + hostdata->outgoing_msg[1] = 3; + hostdata->outgoing_msg[2] = EXTENDED_SDTR; + hostdata->outgoing_msg[3] = hostdata->default_sx_per/4; + hostdata->outgoing_msg[4] = 0; + hostdata->outgoing_len = 5; + hostdata->sync_xfer[cmd->target] = + calc_sync_xfer(hostdata->default_sx_per/4,0); + } else { + hostdata->sync_xfer[cmd->target] = id; + } #ifdef SYNC_DEBUG -printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]); + printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]); +#endif + hostdata->sync_stat[cmd->target] = SS_SET; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + + case EXTENDED_WDTR: + /* want MESS_OUT */ + write_wd33c93_cmd(regp, WD_CMD_ASSERT_ATN); + printk("sending WDTR "); + hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; + hostdata->outgoing_msg[1] = 2; + hostdata->outgoing_msg[2] = EXTENDED_WDTR; + /* 8 bit transfer width */ + hostdata->outgoing_msg[3] = 0; + hostdata->outgoing_len = 4; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + + default: + /* want MESS_OUT */ + write_wd33c93_cmd(regp, WD_CMD_ASSERT_ATN); + printk("Rejecting Unknown Extended " + "Message(%02x). ",ucp[2]); + hostdata->outgoing_msg[0] = MESSAGE_REJECT; + hostdata->outgoing_len = 1; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + } + hostdata->incoming_ptr = 0; + } else { + /* We need to read more MESS_IN bytes for the + * extended message + */ + hostdata->incoming_ptr++; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + } + break; + + default: + printk("Rejecting Unknown Message(%02x) ",msg); + /* want MESS_OUT */ + write_wd33c93_cmd(regp, WD_CMD_ASSERT_ATN); + hostdata->outgoing_msg[0] = MESSAGE_REJECT; + hostdata->outgoing_len = 1; + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + } + break; + + + case CSR_SEL_XFER_DONE: + /* Note: this interrupt will occur only after a LEVEL2 command */ +#ifndef NOINTS_IN_WDINTR + cli(); #endif - hostdata->sync_stat[cmd->target] = SS_SET; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - case EXTENDED_WDTR: - write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - printk("sending WDTR "); - hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[1] = 2; - hostdata->outgoing_msg[2] = EXTENDED_WDTR; - hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */ - hostdata->outgoing_len = 4; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - default: - write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]); - hostdata->outgoing_msg[0] = MESSAGE_REJECT; - hostdata->outgoing_len = 1; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - } - hostdata->incoming_ptr = 0; - } - - /* We need to read more MESS_IN bytes for the extended message */ - - else { - hostdata->incoming_ptr++; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - default: - printk("Rejecting Unknown Message(%02x) ",msg); - write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = MESSAGE_REJECT; - hostdata->outgoing_len = 1; - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - -/* Note: this interrupt will occur only after a LEVEL2 command */ - - case CSR_SEL_XFER_DONE: - cli(); - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER); - if (phs == 0x60) { -DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) - cmd->SCp.Message = COMMAND_COMPLETE; - lun = read_wd33c93(regp, WD_TARGET_LUN); - if (cmd->SCp.Status == GOOD) - cmd->SCp.Status = lun; - hostdata->connected = NULL; - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - hostdata->state = S_UNCONNECTED; - cmd->scsi_done(cmd); - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - - wd33c93_execute(instance); - } - else { - printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid); - } - break; - - -/* Note: this interrupt will occur only after a LEVEL2 command */ - - case CSR_SDP: -DB(DB_INTR,printk("SDP")) - hostdata->state = S_RUNNING_LEVEL2; - write_wd33c93(regp, WD_COMMAND_PHASE, 0x41); - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); - break; - - - case CSR_XFER_DONE|PHS_MESS_OUT: - case CSR_UNEXP |PHS_MESS_OUT: - case CSR_SRV_REQ |PHS_MESS_OUT: -DB(DB_INTR,printk("MSG_OUT=")) - -/* To get here, we've probably requested MESSAGE_OUT and have - * already put the correct bytes in outgoing_msg[] and filled - * in outgoing_len. We simply send them out to the SCSI bus. - * Sometimes we get MESSAGE_OUT phase when we're not expecting - * it - like when our SDTR message is rejected by a target. Some - * targets send the REJECT before receiving all of the extended - * message, and then seem to go back to MESSAGE_OUT for a byte - * or two. Not sure why, or if I'm doing something wrong to - * cause this to happen. Regardless, it seems that sending - * NOP messages in these situations results in no harm and - * makes everyone happy. - */ - - if (hostdata->outgoing_len == 0) { - hostdata->outgoing_len = 1; - hostdata->outgoing_msg[0] = NOP; - } - transfer_pio(regp, hostdata->outgoing_msg, hostdata->outgoing_len, - DATA_OUT_DIR, hostdata); -DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0])) - hostdata->outgoing_len = 0; - hostdata->state = S_CONNECTED; - break; - - - case CSR_UNEXP_DISC: - -/* I think I've seen this after a request-sense that was in response - * to an error condition, but not sure. We certainly need to do - * something when we get this interrupt - the question is 'what?'. - * Let's think positively, and assume some command has finished - * in a legal manner (like a command that provokes a request-sense), - * so we treat it as a normal command-complete-disconnect. - */ - - cli(); - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER); - if (cmd == NULL) { - printk(" - Already disconnected! "); - hostdata->state = S_UNCONNECTED; - return; - } -DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid)) - hostdata->connected = NULL; - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - hostdata->state = S_UNCONNECTED; - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - cmd->scsi_done(cmd); - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - - wd33c93_execute(instance); - break; - - - case CSR_DISC: - cli(); -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ + /* Make sure that reselection is enabled at this point - it may + * have been turned off for the command that just completed. + */ + write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER); + if (phs == 0x60) { + DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid)); + cmd->SCp.Message = COMMAND_COMPLETE; + lun = read_wd33c93(regp, WD_TARGET_LUN); + if (cmd->SCp.Status == GOOD) + cmd->SCp.Status = lun; + hostdata->connected = NULL; + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = (cmd->SCp.Status | + (cmd->SCp.Message << 8)); + else if (cmd->SCp.Status != GOOD) + cmd->result = ((cmd->result & 0x00ffff) | + (DID_ERROR << 16)); + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + cmd->scsi_done(cmd); + + /* We are no longer connected to a target - check to see if + * there are commands waiting to be executed. + */ + wd33c93_execute(instance); + } else { + printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE " + "phase!!---", asr, sr, phs, cmd->pid); + } + break; + + case CSR_SDP: + /* Note: this interrupt will occur only after a LEVEL2 command */ + DB(DB_INTR, printk("SDP")); + hostdata->state = S_RUNNING_LEVEL2; + write_wd33c93(regp, WD_COMMAND_PHASE, 0x41); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + break; + + case CSR_XFER_DONE|PHS_MESS_OUT: + case CSR_UNEXP |PHS_MESS_OUT: + case CSR_SRV_REQ |PHS_MESS_OUT: + DB(DB_INTR, printk("MSG_OUT=")); + + /* To get here, we've probably requested MESSAGE_OUT and have + * already put the correct bytes in outgoing_msg[] and filled + * in outgoing_len. We simply send them out to the SCSI bus. + * Sometimes we get MESSAGE_OUT phase when we're not expecting + * it - like when our SDTR message is rejected by a target. Some + * targets send the REJECT before receiving all of the extended + * message, and then seem to go back to MESSAGE_OUT for a byte + * or two. Not sure why, or if I'm doing something wrong to + * cause this to happen. Regardless, it seems that sending + * NOP messages in these situations results in no harm and + * makes everyone happy. + */ + if (hostdata->outgoing_len == 0) { + hostdata->outgoing_len = 1; + hostdata->outgoing_msg[0] = NOP; + } + transfer_pio(regp, hostdata->outgoing_msg, hostdata->outgoing_len, + DATA_OUT_DIR, hostdata); + DB(DB_INTR,printk("%02x", hostdata->outgoing_msg[0])); + hostdata->outgoing_len = 0; + hostdata->state = S_CONNECTED; + break; + + case CSR_UNEXP_DISC: + /* I think I've seen this after a request-sense that was in response + * to an error condition, but not sure. We certainly need to do + * something when we get this interrupt - the question is 'what?'. + * Let's think positively, and assume some command has finished + * in a legal manner (like a command that provokes a request-sense), + * so we treat it as a normal command-complete-disconnect. + */ +#ifndef NOINTS_IN_WDINTR + cli(); +#endif - write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER); -DB(DB_INTR,printk("DISC-%ld",cmd->pid)) - if (cmd == NULL) { - printk(" - Already disconnected! "); - hostdata->state = S_UNCONNECTED; - } - switch (hostdata->state) { - case S_PRE_CMP_DISC: - hostdata->connected = NULL; - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - hostdata->state = S_UNCONNECTED; - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - cmd->scsi_done(cmd); - break; - case S_PRE_TMP_DISC: - case S_RUNNING_LEVEL2: - cmd->host_scribble = (uchar *)hostdata->disconnected_Q; - hostdata->disconnected_Q = cmd; - hostdata->connected = NULL; - hostdata->state = S_UNCONNECTED; + /* Make sure that reselection is enabled at this point - it may + * have been turned off for the command that just completed. + */ + write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER); + if (cmd == NULL) { + printk(" - Already disconnected! "); + hostdata->state = S_UNCONNECTED; + return; + } + DB(DB_INTR,printk("UNEXP_DISC-%ld", cmd->pid)); + hostdata->connected = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = (cmd->SCp.Status | (cmd->SCp.Message << 8)); + else if (cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + cmd->scsi_done(cmd); + + /* We are no longer connected to a target - check to see if + * there are commands waiting to be executed. + */ + wd33c93_execute(instance); + break; + + case CSR_DISC: +#ifndef NOINTS_IN_WDINTR + cli(); +#endif + /* Make sure that reselection is enabled at this point - it may + * have been turned off for the command that just completed. + */ + write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER); + DB(DB_INTR, printk("DISC-%ld", cmd->pid)); + if (cmd == NULL) { + printk(" - Already disconnected! "); + hostdata->state = S_UNCONNECTED; + } + switch (hostdata->state) { + case S_PRE_CMP_DISC: + hostdata->connected = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = (cmd->SCp.Status | + (cmd->SCp.Message << 8)); + else if (cmd->SCp.Status != GOOD) + cmd->result = ((cmd->result & 0x00ffff) | + (DID_ERROR << 16)); + cmd->scsi_done(cmd); + break; + case S_PRE_TMP_DISC: + case S_RUNNING_LEVEL2: + cmd->host_scribble = (uchar *) hostdata->disconnected_Q; + hostdata->disconnected_Q = cmd; + hostdata->connected = NULL; + hostdata->state = S_UNCONNECTED; #ifdef PROC_INTERFACE - disc_taken_total++; + disc_taken_total++; #endif + break; - break; - default: - printk("*** Unexpected DISCONNECT interrupt! ***"); - hostdata->state = S_UNCONNECTED; - } + default: + printk("*** Unexpected DISCONNECT interrupt! ***"); + hostdata->state = S_UNCONNECTED; + } -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ + /* We are no longer connected to a target - check to see if + * there are commands waiting to be executed. + */ + wd33c93_execute(instance); + break; - wd33c93_execute(instance); - break; - - - case CSR_RESEL_AM: -DB(DB_INTR,printk("RESEL")) - - cli(); - - /* First we have to make sure this reselection didn't */ - /* happen during Arbitration/Selection of some other device. */ - /* If yes, put losing command back on top of input_Q. */ - - if (hostdata->level2 <= L2_NONE) { - - if (hostdata->selecting) { - cmd = (Scsi_Cmnd *)hostdata->selecting; - hostdata->selecting = NULL; - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - cmd->host_scribble = (uchar *)hostdata->input_Q; - hostdata->input_Q = cmd; - } - } - - else { - - if (cmd) { - if (phs == 0x00) { - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - cmd->host_scribble = (uchar *)hostdata->input_Q; - hostdata->input_Q = cmd; - } - else { - printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs); - while (1) - printk("\r"); - } - } - - } - - /* OK - find out which device reselected us. */ - - id = read_wd33c93(regp, WD_SOURCE_ID); - id &= SRCID_MASK; - - /* and extract the lun from the ID message. (Note that we don't - * bother to check for a valid message here - I guess this is - * not the right way to go, but...) - */ - - lun = read_wd33c93(regp, WD_DATA); - if (hostdata->level2 < L2_RESELECT) - write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); - lun &= 7; - - /* Now we look for the command that's reconnecting. */ - - cmd = (Scsi_Cmnd *)hostdata->disconnected_Q; - patch = NULL; - while (cmd) { - if (id == cmd->target && lun == cmd->lun) - break; - patch = cmd; - cmd = (Scsi_Cmnd *)cmd->host_scribble; - } - - /* Hmm. Couldn't find a valid command.... What to do? */ - - if (!cmd) { - printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun); - return; - } - - /* Ok, found the command - now start it up again. */ - - if (patch) - patch->host_scribble = cmd->host_scribble; - else - hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble; - hostdata->connected = cmd; - - /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' - * because these things are preserved over a disconnect. - * But we DO need to fix the DPD bit so it's correct for this command. - */ - - if (IS_DIR_OUT(cmd)) - write_wd33c93(regp, WD_DESTINATION_ID, cmd->target); - else - write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD); - if (hostdata->level2 >= L2_RESELECT) { - write_wd33c93_count(regp, 0); /* we want a DATA_PHASE interrupt */ - write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); - write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } - else - hostdata->state = S_CONNECTED; - -DB(DB_INTR,printk("-%ld",cmd->pid)) - break; - - default: - printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs); - } - - restore_flags(flags); + case CSR_RESEL_AM: + DB(DB_INTR,printk("RESEL")); -DB(DB_INTR,printk("} ")) +#ifndef NOINTS_IN_WDINTR + cli(); +#endif + /* First we have to make sure this reselection didn't + * happen during Arbitration/Selection of some other device. + * If yes, put losing command back on top of input_Q. + */ + if (hostdata->level2 <= L2_NONE) { + if (hostdata->selecting) { + cmd = (Scsi_Cmnd *) hostdata->selecting; + hostdata->selecting = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + cmd->host_scribble = (uchar *) hostdata->input_Q; + hostdata->input_Q = cmd; + } + } else { + if (cmd) { + if (phs == 0x00) { + hostdata->busy[cmd->target] &= + ~(1 << cmd->lun); + cmd->host_scribble = + (uchar *) hostdata->input_Q; + hostdata->input_Q = cmd; + } else { + printk("---%02x:%02x:%02x-TROUBLE: " + "Intrusive ReSelect!---", + asr, sr, phs); + while (1) + printk("\r"); + } + } + } + + /* OK - find out which device reselected us. */ + id = read_wd33c93(regp, WD_SOURCE_ID); + id &= SRCID_MASK; + + /* and extract the lun from the ID message. (Note that we don't + * bother to check for a valid message here - I guess this is + * not the right way to go, but...) + */ + lun = read_wd33c93(regp, WD_DATA); + if (hostdata->level2 < L2_RESELECT) + write_wd33c93_cmd(regp, WD_CMD_NEGATE_ACK); + lun &= 7; + + /* Now we look for the command that's reconnecting. */ + cmd = (Scsi_Cmnd *) hostdata->disconnected_Q; + patch = NULL; + while (cmd) { + if ((id == cmd->target) && (lun == cmd->lun)) + break; + patch = cmd; + cmd = (Scsi_Cmnd *) cmd->host_scribble; + } + + /* Hmm. Couldn't find a valid command.... What to do? */ + if (!cmd) { + printk("---TROUBLE: target %d.%d not in disconnect " + "queue---", id, lun); + return; + } + + /* Ok, found the command - now start it up again. */ + if (patch) + patch->host_scribble = cmd->host_scribble; + else + hostdata->disconnected_Q = (Scsi_Cmnd *) cmd->host_scribble; + hostdata->connected = cmd; + + /* We don't need to worry about 'initialize_SCp()' or + * 'hostdata->busy[]' because these things are preserved + * over a disconnect. But we DO need to fix the DPD bit so + * it's correct for this command. + */ + if (IS_DIR_OUT(cmd)) + write_wd33c93(regp, WD_DESTINATION_ID, cmd->target); + else + write_wd33c93(regp, WD_DESTINATION_ID, + (cmd->target | DSTID_DPD)); + if (hostdata->level2 >= L2_RESELECT) { + /* we want a DATA_PHASE interrupt */ + write_wd33c93_count(regp, 0); + write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); + write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); + hostdata->state = S_RUNNING_LEVEL2; + } else { + hostdata->state = S_CONNECTED; + } + + DB(DB_INTR,printk("-%ld", cmd->pid)); + break; + + default: + printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs); + } +#ifndef NOINTS_IN_WDINTR + restore_flags(flags); +#endif + DB(DB_INTR,printk("} ")); } - - void reset_wd33c93(struct Scsi_Host *instance) { -struct WD33C93_hostdata *hostdata; -wd33c93_regs *regp; -uchar sr; - - hostdata = (struct WD33C93_hostdata *)instance->hostdata; - regp = hostdata->regp; - - write_wd33c93(regp, WD_OWN_ID, OWNID_EAF | OWNID_RAF | - instance->this_id | hostdata->clock_freq); - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER, - calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF)); - write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET); - - while (!(READ_AUX_STAT() & ASR_INT)) - ; - sr = read_wd33c93(regp, WD_SCSI_STATUS); - - hostdata->microcode = read_wd33c93(regp, WD_CDB_1); - if (sr == 0x00) - hostdata->chip = C_WD33C93; - else if (sr == 0x01) { - write_wd33c93(regp, WD_QUEUE_TAG, 0xa5); /* any random number */ - sr = read_wd33c93(regp, WD_QUEUE_TAG); - if (sr == 0xa5) { - hostdata->chip = C_WD33C93B; - write_wd33c93(regp, WD_QUEUE_TAG, 0); - } - else - hostdata->chip = C_WD33C93A; - } - else - hostdata->chip = C_UNKNOWN_CHIP; - - write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); + struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance); + wd33c93_regs *regp = hostdata->regp; + uchar sr; + + write_wd33c93(regp, WD_OWN_ID, (OWNID_EAF | OWNID_RAF | + instance->this_id | hostdata->clock_freq)); + write_wd33c93(regp, WD_CONTROL, (CTRL_IDI | CTRL_EDI | CTRL_POLLED)); + write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER, + calc_sync_xfer(hostdata->default_sx_per/4, DEFAULT_SX_OFF)); + write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET); + + while (!(READ_AUX_STAT() & ASR_INT)) + ; + + sr = read_wd33c93(regp, WD_SCSI_STATUS); + hostdata->microcode = read_wd33c93(regp, WD_CDB_1); + if (sr == 0x00) + hostdata->chip = C_WD33C93; + else if (sr == 0x01) { + write_wd33c93(regp, WD_QUEUE_TAG, 0xa5); /* any random number */ + sr = read_wd33c93(regp, WD_QUEUE_TAG); + if (sr == 0xa5) { + hostdata->chip = C_WD33C93B; + write_wd33c93(regp, WD_QUEUE_TAG, 0); + } else { + hostdata->chip = C_WD33C93A; + } + } else { + hostdata->chip = C_UNKNOWN_CHIP; + } + + write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); + write_wd33c93(regp, WD_CONTROL, (CTRL_IDI | CTRL_EDI | CTRL_POLLED)); } - - #if LINUX_VERSION_CODE >= 0x010300 int wd33c93_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) #else int wd33c93_reset(Scsi_Cmnd *SCpnt) #endif { -unsigned long flags; -struct Scsi_Host *instance; -struct WD33C93_hostdata *hostdata; -int i; - - instance = SCpnt->host; - hostdata = (struct WD33C93_hostdata *)instance->hostdata; - - printk("scsi%d: reset. ", instance->host_no); - save_flags(flags); - cli(); - - ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0); - for (i = 0; i < 8; i++) { - hostdata->busy[i] = 0; - hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF); - hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ - } - hostdata->input_Q = NULL; - hostdata->selecting = NULL; - hostdata->connected = NULL; - hostdata->disconnected_Q = NULL; - hostdata->state = S_UNCONNECTED; - hostdata->dma = D_DMA_OFF; - hostdata->incoming_ptr = 0; - hostdata->outgoing_len = 0; - - reset_wd33c93(instance); - SCpnt->result = DID_RESET << 16; - restore_flags(flags); - return 0; + struct Scsi_Host *instance = SCpnt->host; + struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance); + unsigned long flags; + int i; + + printk("scsi%d: reset. ", instance->host_no); + save_flags(flags); + cli(); + + ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0); + for (i = 0; i < 8; i++) { + hostdata->busy[i] = 0; + hostdata->sync_xfer[i] = + calc_sync_xfer(DEFAULT_SX_PER/4, DEFAULT_SX_OFF); + hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ + } + hostdata->input_Q = NULL; + hostdata->selecting = NULL; + hostdata->connected = NULL; + hostdata->disconnected_Q = NULL; + hostdata->state = S_UNCONNECTED; + hostdata->dma = D_DMA_OFF; + hostdata->incoming_ptr = 0; + hostdata->outgoing_len = 0; + + reset_wd33c93(instance); + SCpnt->result = (DID_RESET << 16); + restore_flags(flags); + return 0; } - - int wd33c93_abort (Scsi_Cmnd *cmd) { -struct Scsi_Host *instance; -struct WD33C93_hostdata *hostdata; -wd33c93_regs *regp; -Scsi_Cmnd *tmp, *prev; -unsigned long flags; - - save_flags (flags); - cli(); - - instance = cmd->host; - hostdata = (struct WD33C93_hostdata *)instance->hostdata; - regp = hostdata->regp; - -/* - * Case 1 : If the command hasn't been issued yet, we simply remove it - * from the input_Q. - */ - - tmp = (Scsi_Cmnd *)hostdata->input_Q; - prev = 0; - while (tmp) { - if (tmp == cmd) { - if (prev) - prev->host_scribble = cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->result = DID_ABORT << 16; - printk("scsi%d: Abort - removing command %ld from input_Q. ", - instance->host_no, cmd->pid); - cmd->scsi_done(cmd); - restore_flags(flags); - return SCSI_ABORT_SUCCESS; - } - prev = tmp; - tmp = (Scsi_Cmnd *)tmp->host_scribble; - } - -/* - * Case 2 : If the command is connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected == cmd) { - uchar sr, asr; - unsigned long timeout; - - printk("scsi%d: Aborting connected command %ld - ", - instance->host_no, cmd->pid); - - printk("stopping DMA - "); - if (hostdata->dma == D_DMA_RUNNING) { - hostdata->dma_stop(instance, cmd, 0); - hostdata->dma = D_DMA_OFF; - } - - printk("sending wd33c93 ABORT command - "); - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_cmd(regp, WD_CMD_ABORT); - -/* Now we have to attempt to flush out the FIFO... */ - - printk("flushing fifo - "); - timeout = 1000000; - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - read_wd33c93(regp, WD_DATA); - } while (!(asr & ASR_INT) && timeout-- > 0); - sr = read_wd33c93(regp, WD_SCSI_STATUS); - printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", - asr, sr, read_wd33c93_count(regp), timeout); - - /* - * Abort command processed. - * Still connected. - * We must disconnect. - */ - - printk("sending wd33c93 DISCONNECT command - "); - write_wd33c93_cmd(regp, WD_CMD_DISCONNECT); - - timeout = 1000000; - asr = READ_AUX_STAT(); - while ((asr & ASR_CIP) && timeout-- > 0) - asr = READ_AUX_STAT(); - sr = read_wd33c93(regp, WD_SCSI_STATUS); - printk("asr=%02x, sr=%02x.",asr,sr); - - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - hostdata->connected = NULL; - hostdata->state = S_UNCONNECTED; - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); - -/* sti();*/ - wd33c93_execute (instance); - - restore_flags(flags); - return SCSI_ABORT_SUCCESS; - } - -/* - * Case 3: If the command is currently disconnected from the bus, - * we're not going to expend much effort here: Let's just return - * an ABORT_SNOOZE and hope for the best... - */ - - tmp = (Scsi_Cmnd *)hostdata->disconnected_Q; - while (tmp) { - if (tmp == cmd) { - printk("scsi%d: Abort - command %ld found on disconnected_Q - ", - instance->host_no, cmd->pid); - printk("returning ABORT_SNOOZE. "); - restore_flags(flags); - return SCSI_ABORT_SNOOZE; - } - tmp = (Scsi_Cmnd *)tmp->host_scribble; - } - -/* - * Case 4 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ - -/* sti();*/ - wd33c93_execute (instance); - - restore_flags(flags); - printk("scsi%d: warning : SCSI command probably completed successfully" - " before abortion. ", instance->host_no); - return SCSI_ABORT_NOT_RUNNING; + struct Scsi_Host *instance = cmd->host; + struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance); + wd33c93_regs *regp = hostdata->regp; + Scsi_Cmnd *tmp, *prev; + unsigned long flags; + + save_flags (flags); + cli(); + + /* Case 1 : If the command hasn't been issued yet, we simply remove it + * from the input_Q. + */ + tmp = (Scsi_Cmnd *) hostdata->input_Q; + prev = 0; + while (tmp) { + if (tmp == cmd) { + if (prev) + prev->host_scribble = cmd->host_scribble; + cmd->host_scribble = NULL; + cmd->result = (DID_ABORT << 16); + printk("scsi%d: Abort - removing command %ld from " + "input_Q. ", instance->host_no, cmd->pid); + cmd->scsi_done(cmd); + restore_flags(flags); + return SCSI_ABORT_SUCCESS; + } + prev = tmp; + tmp = (Scsi_Cmnd *) tmp->host_scribble; + } + + /* Case 2 : If the command is connected, we're going to fail the abort + * and let the high level SCSI driver retry at a later time or + * issue a reset. + * + * Timeouts, and therefore aborted commands, will be highly unlikely + * and handling them cleanly in this situation would make the common + * case of noresets less efficient, and would pollute our code. So, + * we fail. + */ + if (hostdata->connected == cmd) { + uchar sr, asr; + unsigned long timeout; + + printk("scsi%d: Aborting connected command %ld - ", + instance->host_no, cmd->pid); + + printk("stopping DMA - "); + if (hostdata->dma == D_DMA_RUNNING) { + hostdata->dma_stop(instance, cmd, 0); + hostdata->dma = D_DMA_OFF; + } + + printk("sending wd33c93 ABORT command - "); + write_wd33c93(regp, WD_CONTROL, + (CTRL_IDI | CTRL_EDI | CTRL_POLLED)); + write_wd33c93_cmd(regp, WD_CMD_ABORT); + + /* Now we have to attempt to flush out the FIFO... */ + printk("flushing fifo - "); + timeout = 1000000; + do { + asr = READ_AUX_STAT(); + if (asr & ASR_DBR) + read_wd33c93(regp, WD_DATA); + } while (!(asr & ASR_INT) && timeout-- > 0); + + sr = read_wd33c93(regp, WD_SCSI_STATUS); + printk("asr=%02x, sr=%02x, %ld bytes un-transferred " + "(timeout=%ld) - ", asr, sr, read_wd33c93_count(regp), + timeout); + + /* Abort command processed. + * Still connected. + * We must disconnect. + */ + printk("sending wd33c93 DISCONNECT command - "); + write_wd33c93_cmd(regp, WD_CMD_DISCONNECT); + + timeout = 1000000; + asr = READ_AUX_STAT(); + while ((asr & ASR_CIP) && timeout-- > 0) + asr = READ_AUX_STAT(); + sr = read_wd33c93(regp, WD_SCSI_STATUS); + printk("asr=%02x, sr=%02x.", asr, sr); + + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->connected = NULL; + hostdata->state = S_UNCONNECTED; + cmd->result = (DID_ABORT << 16); + cmd->scsi_done(cmd); + + /* sti();*/ + wd33c93_execute (instance); + + restore_flags(flags); + return SCSI_ABORT_SUCCESS; + } + + /* Case 3: If the command is currently disconnected from the bus, + * we're not going to expend much effort here: Let's just return + * an ABORT_SNOOZE and hope for the best... + */ + + tmp = (Scsi_Cmnd *) hostdata->disconnected_Q; + while (tmp) { + if (tmp == cmd) { + printk("scsi%d: Abort - command %ld found on " + "disconnected_Q - ", instance->host_no, cmd->pid); + printk("returning ABORT_SNOOZE. "); + restore_flags(flags); + return SCSI_ABORT_SNOOZE; + } + tmp = (Scsi_Cmnd *) tmp->host_scribble; + } + + /* Case 4 : If we reached this point, the command was not found in any of + * the queues. + * + * We probably reached this point because of an unlikely race condition + * between the command completing successfully and the abortion code, + * so we won't panic, but we will notify the user in case something really + * broke. + */ + + /* sti();*/ + wd33c93_execute (instance); + + restore_flags(flags); + printk("scsi%d: warning : SCSI command probably completed successfully" + " before abortion. ", instance->host_no); + return SCSI_ABORT_NOT_RUNNING; } - - #define MAX_WD33C93_HOSTS 4 #define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *)) #define SETUP_BUFFER_SIZE 200 @@ -1509,322 +1414,305 @@ static char setup_used[MAX_SETUP_STRINGS]; void wd33c93_setup (char *str, int *ints) { -int i,x; -char *p1,*p2; - - /* The kernel does some processing of the command-line before calling - * this function: If it begins with any decimal or hex number arguments, - * ints[0] = how many numbers found and ints[1] through [n] are the values - * themselves. str points to where the non-numeric arguments (if any) - * start: We do our own parsing of those. We construct synthetic 'nosync' - * keywords out of numeric args (to maintain compatibility with older - * versions) and then add the rest of the arguments. - */ - - p1 = setup_buffer; - *p1 = '\0'; - if (ints[0]) { - for (i=0; i<ints[0]; i++) { - x = vsprintf(p1,"nosync:0x%02x,",&(ints[i+1])); - p1 += x; - } - } - if (str) - strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer)); - setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; - p1 = setup_buffer; - i = 0; - while (*p1 && (i < MAX_SETUP_STRINGS)) { - p2 = strchr(p1, ','); - if (p2) { - *p2 = '\0'; - if (p1 != p2) - setup_strings[i] = p1; - p1 = p2 + 1; - i++; - } - else { - setup_strings[i] = p1; - break; - } - } - for (i=0; i<MAX_SETUP_STRINGS; i++) - setup_used[i] = 0; + int i, x; + char *p1, *p2; + + /* The kernel does some processing of the command-line before calling + * this function: If it begins with any decimal or hex number arguments, + * ints[0] = how many numbers found and ints[1] through [n] are the values + * themselves. str points to where the non-numeric arguments (if any) + * start: We do our own parsing of those. We construct synthetic 'nosync' + * keywords out of numeric args (to maintain compatibility with older + * versions) and then add the rest of the arguments. + */ + p1 = setup_buffer; + *p1 = '\0'; + if (ints[0]) { + for (i = 0; i < ints[0]; i++) { + x = vsprintf(p1, "nosync:0x%02x,", &(ints[i+1])); + p1 += x; + } + } + if (str) + strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer)); + setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; + p1 = setup_buffer; + i = 0; + while (*p1 && (i < MAX_SETUP_STRINGS)) { + p2 = strchr(p1, ','); + if (p2) { + *p2 = '\0'; + if (p1 != p2) + setup_strings[i] = p1; + p1 = p2 + 1; + i++; + } else { + setup_strings[i] = p1; + break; + } + } + for (i = 0; i < MAX_SETUP_STRINGS; i++) + setup_used[i] = 0; } - -/* check_setup_strings() returns index if key found, 0 if not - */ - +/* check_setup_strings() returns index if key found, 0 if not */ int check_setup_strings(char *key, int *flags, int *val, char *buf) { -int x; -char *cp; - - for (x=0; x<MAX_SETUP_STRINGS; x++) { - if (setup_used[x]) - continue; - if (!strncmp(setup_strings[x], key, strlen(key))) - break; - if (!strncmp(setup_strings[x], "next", strlen("next"))) - return 0; - } - if (x == MAX_SETUP_STRINGS) - return 0; - setup_used[x] = 1; - cp = setup_strings[x] + strlen(key); - *val = -1; - if (*cp != ':') - return ++x; - cp++; - if ((*cp >= '0') && (*cp <= '9')) { - *val = simple_strtoul(cp,NULL,0); - } - return ++x; + int x; + char *cp; + + for (x = 0; x < MAX_SETUP_STRINGS; x++) { + if (setup_used[x]) + continue; + if (!strncmp(setup_strings[x], key, strlen(key))) + break; + if (!strncmp(setup_strings[x], "next", strlen("next"))) + return 0; + } + if (x == MAX_SETUP_STRINGS) + return 0; + setup_used[x] = 1; + cp = setup_strings[x] + strlen(key); + *val = -1; + if (*cp != ':') + return ++x; + cp++; + if ((*cp >= '0') && (*cp <= '9')) + *val = simple_strtoul(cp, NULL, 0); + + return ++x; } - - void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs, - dma_setup_t setup, dma_stop_t stop, int clock_freq) + dma_setup_t setup, dma_stop_t stop, int clock_freq) { -struct WD33C93_hostdata *hostdata; -int i; -int flags; -int val; -char buf[32]; - - hostdata = (struct WD33C93_hostdata *)instance->hostdata; - - hostdata->regp = regs; - hostdata->clock_freq = clock_freq; - hostdata->dma_setup = setup; - hostdata->dma_stop = stop; - hostdata->dma_bounce_buffer = NULL; - hostdata->dma_bounce_len = 0; - for (i = 0; i < 8; i++) { - hostdata->busy[i] = 0; - hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF); - hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ - } - hostdata->input_Q = NULL; - hostdata->selecting = NULL; - hostdata->connected = NULL; - hostdata->disconnected_Q = NULL; - hostdata->state = S_UNCONNECTED; - hostdata->dma = D_DMA_OFF; - hostdata->level2 = L2_BASIC; - hostdata->disconnect = DIS_ADAPTIVE; - hostdata->args = DEBUG_DEFAULTS; - hostdata->incoming_ptr = 0; - hostdata->outgoing_len = 0; - hostdata->default_sx_per = DEFAULT_SX_PER; - hostdata->no_sync = 0xff; /* sync defaults to off */ + static int shown = 0; + struct WD33C93_hostdata *hostdata = INSTHOSTDATA(instance); + int i; + int flags; + int val; + char buf[32]; + + hostdata->regp = regs; + hostdata->clock_freq = clock_freq; + hostdata->dma_setup = setup; + hostdata->dma_stop = stop; + hostdata->dma_bounce_buffer = NULL; + hostdata->dma_bounce_len = 0; + for (i = 0; i < 8; i++) { + hostdata->busy[i] = 0; + hostdata->sync_xfer[i] = + calc_sync_xfer(DEFAULT_SX_PER/4, DEFAULT_SX_OFF); + hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ + } + hostdata->input_Q = NULL; + hostdata->selecting = NULL; + hostdata->connected = NULL; + hostdata->disconnected_Q = NULL; + hostdata->state = S_UNCONNECTED; + hostdata->dma = D_DMA_OFF; + hostdata->level2 = L2_BASIC; + hostdata->disconnect = DIS_ADAPTIVE; + hostdata->args = DEBUG_DEFAULTS; + hostdata->incoming_ptr = 0; + hostdata->outgoing_len = 0; + hostdata->default_sx_per = DEFAULT_SX_PER; + hostdata->no_sync = 0xff; /* sync defaults to off */ #ifdef PROC_INTERFACE - hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS| - PR_CONNECTED|PR_INPUTQ|PR_DISCQ| - PR_STOP; + hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS| + PR_CONNECTED|PR_INPUTQ|PR_DISCQ| + PR_STOP; - disc_allowed_total = 0; - disc_taken_total = 0; + disc_allowed_total = 0; + disc_taken_total = 0; #endif - - if (check_setup_strings("nosync",&flags,&val,buf)) - hostdata->no_sync = val; - - if (check_setup_strings("period",&flags,&val,buf)) - hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns; - - if (check_setup_strings("disconnect",&flags,&val,buf)) { - if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) - hostdata->disconnect = val; - else - hostdata->disconnect = DIS_ADAPTIVE; - } - - if (check_setup_strings("debug",&flags,&val,buf)) - hostdata->args = val & DB_MASK; - - if (check_setup_strings("clock",&flags,&val,buf)) { - if (val>7 && val<11) - val = WD33C93_FS_8_10; - else if (val>11 && val<16) - val = WD33C93_FS_12_15; - else if (val>15 && val<21) - val = WD33C93_FS_16_20; - else - val = WD33C93_FS_8_10; - hostdata->clock_freq = val; - } - - if ((i = check_setup_strings("next",&flags,&val,buf))) { - while (i) - setup_used[--i] = 1; - } + if (check_setup_strings("nosync", &flags, &val, buf)) + hostdata->no_sync = val; + + if (check_setup_strings("period", &flags, &val, buf)) + hostdata->default_sx_per = + sx_table[round_period((unsigned int)val)].period_ns; + + if (check_setup_strings("disconnect", &flags, &val, buf)) { + if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) + hostdata->disconnect = val; + else + hostdata->disconnect = DIS_ADAPTIVE; + } + + if (check_setup_strings("debug", &flags, &val, buf)) + hostdata->args = val & DB_MASK; + + if (check_setup_strings("clock", &flags, &val, buf)) { + if ((val > 7) && (val < 11)) + val = WD33C93_FS_8_10; + else if ((val > 11) && (val < 16)) + val = WD33C93_FS_12_15; + else if ((val > 15) && (val < 21)) + val = WD33C93_FS_16_20; + else + val = WD33C93_FS_8_10; + hostdata->clock_freq = val; + } + + if ((i = check_setup_strings("next", &flags, &val, buf))) { + while (i) + setup_used[--i] = 1; + } #ifdef PROC_INTERFACE - if (check_setup_strings("proc",&flags,&val,buf)) - hostdata->proc = val; + if (check_setup_strings("proc", &flags, &val, buf)) + hostdata->proc = val; #endif - - cli(); - reset_wd33c93(instance); - sti(); - - printk("wd33c93-%d: chip=%s microcode=%02x\n",instance->host_no, - (hostdata->chip==C_WD33C93)?"WD33c93": - (hostdata->chip==C_WD33C93A)?"WD33c93A": - (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown", - hostdata->microcode); - -#ifdef DEBUGGING_ON - printk("wd33c93-%d: setup_strings=",instance->host_no); - for (i=0; i<MAX_SETUP_STRINGS; i++) - printk("%s,",setup_strings[i]); - printk("\n"); - printk("wd33c93-%d: debug_flags = %04x\n",instance->host_no,hostdata->args); + cli(); + reset_wd33c93(instance); + sti(); + + if(!shown++) { + printk("WD93: Driver version %s ", WD33C93_VERSION); + printk("compiled on %s at %s\n", __DATE__, __TIME__); +#if 0 + printk("wd33c93-%d: setup_strings=", instance->host_no); + for (i = 0; i < MAX_SETUP_STRINGS; i++) + printk("%s,", setup_strings[i]); + printk("\n"); + printk("wd33c93-%d: debug_flags = %04x\n", + instance->host_no, hostdata->args); #endif - printk("wd33c93-%d: driver version %s - %s\n",instance->host_no, - WD33C93_VERSION,WD33C93_DATE); - printk("wd33c93-%d: compiled on %s at %s\n",instance->host_no, - __DATE__,__TIME__); -} + } + printk("wd33c93-%d: chip=%s microcode=%02x\n", instance->host_no, + (hostdata->chip==C_WD33C93) ? "WD33c93" : + (hostdata->chip==C_WD33C93A) ? "WD33c93A" : + (hostdata->chip==C_WD33C93B) ? "WD33c93B" : "unknown", + hostdata->microcode); +} int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in) { - #ifdef PROC_INTERFACE - -char *bp; -char tbuf[128]; -unsigned long flags; -struct Scsi_Host *instance; -struct WD33C93_hostdata *hd; -Scsi_Cmnd *cmd; -int x,i; -static int stop = 0; - - for (instance=instance_list; instance; instance=instance->next) { - if (instance->host_no == hn) - break; - } - if (!instance) { - printk("*** Hmm... Can't find host #%d!\n",hn); - return (-ESRCH); - } - hd = (struct WD33C93_hostdata *)instance->hostdata; - -/* If 'in' is TRUE we need to _read_ the proc file. We accept the following - * keywords (same format as command-line, but only ONE per read): - * debug - * disconnect - * period - * resync - * proc - */ - - if (in) { - buf[len] = '\0'; - bp = buf; - if (!strncmp(bp,"debug:",6)) { - bp += 6; - hd->args = simple_strtoul(bp,NULL,0) & DB_MASK; - } - else if (!strncmp(bp,"disconnect:",11)) { - bp += 11; - x = simple_strtoul(bp,NULL,0); - if (x < DIS_NEVER || x > DIS_ALWAYS) - x = DIS_ADAPTIVE; - hd->disconnect = x; - } - else if (!strncmp(bp,"period:",7)) { - bp += 7; - x = simple_strtoul(bp,NULL,0); - hd->default_sx_per = sx_table[round_period((unsigned int)x)].period_ns; - } - else if (!strncmp(bp,"resync:",7)) { - bp += 7; - x = simple_strtoul(bp,NULL,0); - for (i=0; i<7; i++) - if (x & (1<<i)) - hd->sync_stat[i] = SS_UNSET; - } - else if (!strncmp(bp,"proc:",5)) { - bp += 5; - hd->proc = simple_strtoul(bp,NULL,0); - } - return len; - } - - save_flags(flags); - cli(); - bp = buf; - *bp = '\0'; - if (hd->proc & PR_VERSION) { - sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s", - WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__); - strcat(bp,tbuf); - } - if (hd->proc & PR_INFO) { - ; - } - if (hd->proc & PR_TOTALS) { - sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken", - disc_allowed_total,disc_taken_total); - strcat(bp,tbuf); - } - if (hd->proc & PR_CONNECTED) { - strcat(bp,"\nconnected: "); - if (hd->connected) { - cmd = (Scsi_Cmnd *)hd->connected; - sprintf(tbuf," %ld-%d:%d(%02x)", - cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); - strcat(bp,tbuf); - } - } - if (hd->proc & PR_INPUTQ) { - strcat(bp,"\ninput_Q: "); - cmd = (Scsi_Cmnd *)hd->input_Q; - while (cmd) { - sprintf(tbuf," %ld-%d:%d(%02x)", - cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); - strcat(bp,tbuf); - cmd = (Scsi_Cmnd *)cmd->host_scribble; - } - } - if (hd->proc & PR_DISCQ) { - strcat(bp,"\ndisconnected_Q:"); - cmd = (Scsi_Cmnd *)hd->disconnected_Q; - while (cmd) { - sprintf(tbuf," %ld-%d:%d(%02x)", - cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); - strcat(bp,tbuf); - cmd = (Scsi_Cmnd *)cmd->host_scribble; - } - } - strcat(bp,"\n"); - restore_flags(flags); - *start = buf; - if (stop) { - stop = 0; - return 0; - } - if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ - stop = 1;; - if (hd->proc & PR_STOP) /* stop every other time */ - stop = 1; - return strlen(bp); + char *bp; + char tbuf[128]; + unsigned long flags; + struct Scsi_Host *instance; + struct WD33C93_hostdata *hd; + Scsi_Cmnd *cmd; + int x,i; + static int stop = 0; + + for (instance = instance_list; instance; instance = instance->next) { + if (instance->host_no == hn) + break; + } + if (!instance) { + printk("*** Hmm... Can't find host #%d!\n",hn); + return (-ESRCH); + } + hd = (struct WD33C93_hostdata *) instance->hostdata; + + /* If 'in' is TRUE we need to _read_ the proc file. We accept the following + * keywords (same format as command-line, but only ONE per read): + * debug + * disconnect + * period + * resync + * proc + */ + if (in) { + buf[len] = '\0'; + bp = buf; + if (!strncmp(bp, "debug:", 6)) { + bp += 6; + hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK; + } else if (!strncmp(bp, "disconnect:", 11)) { + bp += 11; + x = simple_strtoul(bp, NULL, 0); + if ((x < DIS_NEVER) || (x > DIS_ALWAYS)) + x = DIS_ADAPTIVE; + hd->disconnect = x; + } else if (!strncmp(bp, "period:", 7)) { + bp += 7; + x = simple_strtoul(bp, NULL, 0); + hd->default_sx_per = + sx_table[round_period((unsigned int)x)].period_ns; + } else if (!strncmp(bp, "resync:", 7)) { + bp += 7; + x = simple_strtoul(bp, NULL, 0); + for (i = 0; i < 7; i++) + if (x & (1<<i)) + hd->sync_stat[i] = SS_UNSET; + } else if (!strncmp(bp, "proc:", 5)) { + bp += 5; + hd->proc = simple_strtoul(bp, NULL, 0); + } + return len; + } + + save_flags(flags); cli(); + + bp = buf; + *bp = '\0'; + if (hd->proc & PR_VERSION) { + sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s", + WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__); + strcat(bp, tbuf); + } + if (hd->proc & PR_INFO) { + ; + } + if (hd->proc & PR_TOTALS) { + sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken", + disc_allowed_total, disc_taken_total); + strcat(bp, tbuf); + } + if (hd->proc & PR_CONNECTED) { + strcat(bp, "\nconnected: "); + if (hd->connected) { + cmd = (Scsi_Cmnd *) hd->connected; + sprintf(tbuf," %ld-%d:%d(%02x)", + cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); + strcat(bp, tbuf); + } + } + if (hd->proc & PR_INPUTQ) { + strcat(bp, "\ninput_Q: "); + cmd = (Scsi_Cmnd *) hd->input_Q; + while (cmd) { + sprintf(tbuf," %ld-%d:%d(%02x)", + cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); + strcat(bp, tbuf); + cmd = (Scsi_Cmnd *) cmd->host_scribble; + } + } + if (hd->proc & PR_DISCQ) { + strcat(bp, "\ndisconnected_Q:"); + cmd = (Scsi_Cmnd *) hd->disconnected_Q; + while (cmd) { + sprintf(tbuf," %ld-%d:%d(%02x)", + cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); + strcat(bp, tbuf); + cmd = (Scsi_Cmnd *) cmd->host_scribble; + } + } + strcat(bp, "\n"); + restore_flags(flags); + *start = buf; + if (stop) { + stop = 0; + return 0; + } + if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ + stop = 1;; + if (hd->proc & PR_STOP) /* stop every other time */ + stop = 1; + return strlen(bp); #else /* PROC_INTERFACE */ - - return 0; - + return 0; #endif /* PROC_INTERFACE */ - } diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index 123590d5e..82a26cb96 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -17,147 +17,146 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * */ #ifndef WD33C93_H #define WD33C93_H +#include <linux/config.h> #define uchar unsigned char - -/* wd register names */ -#define WD_OWN_ID 0x00 -#define WD_CONTROL 0x01 -#define WD_TIMEOUT_PERIOD 0x02 -#define WD_CDB_1 0x03 -#define WD_CDB_2 0x04 -#define WD_CDB_3 0x05 -#define WD_CDB_4 0x06 -#define WD_CDB_5 0x07 -#define WD_CDB_6 0x08 -#define WD_CDB_7 0x09 -#define WD_CDB_8 0x0a -#define WD_CDB_9 0x0b -#define WD_CDB_10 0x0c -#define WD_CDB_11 0x0d -#define WD_CDB_12 0x0e -#define WD_TARGET_LUN 0x0f -#define WD_COMMAND_PHASE 0x10 -#define WD_SYNCHRONOUS_TRANSFER 0x11 -#define WD_TRANSFER_COUNT_MSB 0x12 -#define WD_TRANSFER_COUNT 0x13 -#define WD_TRANSFER_COUNT_LSB 0x14 -#define WD_DESTINATION_ID 0x15 -#define WD_SOURCE_ID 0x16 -#define WD_SCSI_STATUS 0x17 -#define WD_COMMAND 0x18 -#define WD_DATA 0x19 -#define WD_QUEUE_TAG 0x1a -#define WD_AUXILIARY_STATUS 0x1f - -/* WD commands */ -#define WD_CMD_RESET 0x00 -#define WD_CMD_ABORT 0x01 -#define WD_CMD_ASSERT_ATN 0x02 -#define WD_CMD_NEGATE_ACK 0x03 -#define WD_CMD_DISCONNECT 0x04 -#define WD_CMD_RESELECT 0x05 -#define WD_CMD_SEL_ATN 0x06 -#define WD_CMD_SEL 0x07 -#define WD_CMD_SEL_ATN_XFER 0x08 -#define WD_CMD_SEL_XFER 0x09 -#define WD_CMD_RESEL_RECEIVE 0x0a -#define WD_CMD_RESEL_SEND 0x0b -#define WD_CMD_WAIT_SEL_RECEIVE 0x0c -#define WD_CMD_TRANS_ADDR 0x18 -#define WD_CMD_TRANS_INFO 0x20 -#define WD_CMD_TRANSFER_PAD 0x21 -#define WD_CMD_SBT_MODE 0x80 - -/* ASR register */ -#define ASR_INT (0x80) -#define ASR_LCI (0x40) -#define ASR_BSY (0x20) -#define ASR_CIP (0x10) -#define ASR_PE (0x02) -#define ASR_DBR (0x01) - -/* SCSI Bus Phases */ -#define PHS_DATA_OUT 0x00 -#define PHS_DATA_IN 0x01 -#define PHS_COMMAND 0x02 -#define PHS_STATUS 0x03 -#define PHS_MESS_OUT 0x06 -#define PHS_MESS_IN 0x07 +/* WD register names. */ +#define WD_OWN_ID 0x00 /* Own ID register */ +#define WD_CONTROL 0x01 /* Control bits */ +#define WD_TIMEOUT_PERIOD 0x02 /* SCSI timeout period */ +#define WD_CDB_1 0x03 /* SCSI command byte 1 */ +#define WD_CDB_2 0x04 /* SCSI command byte 2 */ +#define WD_CDB_3 0x05 /* SCSI command byte 3 */ +#define WD_CDB_4 0x06 /* SCSI command byte 4 */ +#define WD_CDB_5 0x07 /* SCSI command byte 5 */ +#define WD_CDB_6 0x08 /* SCSI command byte 6 */ +#define WD_CDB_7 0x09 /* SCSI command byte 7 */ +#define WD_CDB_8 0x0a /* SCSI command byte 8 */ +#define WD_CDB_9 0x0b /* SCSI command byte 9 */ +#define WD_CDB_10 0x0c /* SCSI command byte 10 */ +#define WD_CDB_11 0x0d /* SCSI command byte 11 */ +#define WD_CDB_12 0x0e /* SCSI command byte 12 */ +#define WD_TARGET_LUN 0x0f /* Target | Lun */ +#define WD_COMMAND_PHASE 0x10 /* Phase register */ +#define WD_SYNCHRONOUS_TRANSFER 0x11 /* Synchronous indicator */ +#define WD_TRANSFER_COUNT_MSB 0x12 /* Trans cnt, bits<23:16> */ +#define WD_TRANSFER_COUNT 0x13 /* Trans cnt, bits<15:8> */ +#define WD_TRANSFER_COUNT_LSB 0x14 /* Trans cnt, bits<7:0> */ +#define WD_DESTINATION_ID 0x15 /* Dest ID register */ +#define WD_SOURCE_ID 0x16 /* Src ID register */ +#define WD_SCSI_STATUS 0x17 /* Status register */ +#define WD_COMMAND 0x18 /* Command reg */ +#define WD_DATA 0x19 /* Data bus bit reg */ +#define WD_QUEUE_TAG 0x1a /* Queue TAG reg (wd93b) */ +#define WD_AUXILIARY_STATUS 0x1f /* Aux status reg */ + +/* WD commands. */ +#define WD_CMD_RESET 0x00 /* Reset SCSI bus and wd93x chip */ +#define WD_CMD_ABORT 0x01 /* Stop and abort current action */ +#define WD_CMD_ASSERT_ATN 0x02 /* Assert ATN on SCSI bus */ +#define WD_CMD_NEGATE_ACK 0x03 /* De-assert ACK on SCSI bus */ +#define WD_CMD_DISCONNECT 0x04 /* Causes wd93x to force disconnect */ +#define WD_CMD_RESELECT 0x05 /* Causes wd93x to reselect as targ */ +#define WD_CMD_SEL_ATN 0x06 /* Tells wd93x to select w/ATN assrt */ +#define WD_CMD_SEL 0x07 /* Tells wd93x to select w/o ATN assrt */ +#define WD_CMD_SEL_ATN_XFER 0x08 /* Select w/ATN and transfer data */ +#define WD_CMD_SEL_XFER 0x09 /* Select w/o ATN and transfer data */ +#define WD_CMD_RESEL_RECEIVE 0x0a /* Reselect and into receive mode */ +#define WD_CMD_RESEL_SEND 0x0b /* Reselect and into send mode */ +#define WD_CMD_WAIT_SEL_RECEIVE 0x0c /* Await selection, into receive mode */ +#define WD_CMD_TRANS_ADDR 0x18 /* Address translate */ +#define WD_CMD_TRANS_INFO 0x20 /* Information transfer */ +#define WD_CMD_TRANSFER_PAD 0x21 /* Information pad */ +#define WD_CMD_SBT_MODE 0x80 /* XXX investigate for this comment */ + +/* ASR (Auxiliary Status) register values. */ +#define ASR_INT (0x80) /* Showing an interrupt */ +#define ASR_LCI (0x40) /* Ignored most recent command */ +#define ASR_BSY (0x20) /* A level II command in progress, therefore busy */ +#define ASR_CIP (0x10) /* A command is in progress */ +#define ASR_PE (0x02) /* Detected a parity error */ +#define ASR_DBR (0x01) /* The data buffer is ready */ + +/* SCSI Bus Phases. */ +#define PHS_DATA_OUT (0x00) +#define PHS_DATA_IN (0x01) +#define PHS_COMMAND (0x02) +#define PHS_STATUS (0x03) +#define PHS_MESS_OUT (0x06) +#define PHS_MESS_IN (0x07) /* Command Status Register definitions */ - /* reset state interrupts */ -#define CSR_RESET 0x00 -#define CSR_RESET_AF 0x01 +/* reset state interrupts */ +#define CSR_RESET 0x00 +#define CSR_RESET_AF 0x01 - /* successful completion interrupts */ -#define CSR_RESELECT 0x10 -#define CSR_SELECT 0x11 +/* successful completion interrupts */ +#define CSR_RESELECT 0x10 +#define CSR_SELECT 0x11 #define CSR_SEL_XFER_DONE 0x16 #define CSR_XFER_DONE 0x18 - /* paused or aborted interrupts */ -#define CSR_MSGIN 0x20 -#define CSR_SDP 0x21 +/* paused or aborted interrupts */ +#define CSR_MSGIN 0x20 +#define CSR_SDP 0x21 #define CSR_SEL_ABORT 0x22 #define CSR_RESEL_ABORT 0x25 #define CSR_RESEL_ABORT_AM 0x27 -#define CSR_ABORT 0x28 +#define CSR_ABORT 0x28 - /* terminated interrupts */ -#define CSR_INVALID 0x40 +/* terminated interrupts */ +#define CSR_INVALID 0x40 #define CSR_UNEXP_DISC 0x41 -#define CSR_TIMEOUT 0x42 -#define CSR_PARITY 0x43 +#define CSR_TIMEOUT 0x42 +#define CSR_PARITY 0x43 #define CSR_PARITY_ATN 0x44 #define CSR_BAD_STATUS 0x45 -#define CSR_UNEXP 0x48 - - /* service required interrupts */ -#define CSR_RESEL 0x80 -#define CSR_RESEL_AM 0x81 -#define CSR_DISC 0x85 -#define CSR_SRV_REQ 0x88 - - /* Own ID/CDB Size register */ -#define OWNID_EAF 0x08 -#define OWNID_EHP 0x10 -#define OWNID_RAF 0x20 -#define OWNID_FS_8 0x00 -#define OWNID_FS_12 0x40 -#define OWNID_FS_16 0x80 - - /* define these so we don't have to change a2091.c, etc. */ -#define WD33C93_FS_8_10 OWNID_FS_8 -#define WD33C93_FS_12_15 OWNID_FS_12 -#define WD33C93_FS_16_20 OWNID_FS_16 - - /* Control register */ -#define CTRL_HSP 0x01 -#define CTRL_HA 0x02 -#define CTRL_IDI 0x04 -#define CTRL_EDI 0x08 -#define CTRL_HHP 0x10 -#define CTRL_POLLED 0x00 -#define CTRL_BURST 0x20 -#define CTRL_BUS 0x40 -#define CTRL_DMA 0x80 - - /* Timeout Period register */ +#define CSR_UNEXP 0x48 + +/* service required interrupts */ +#define CSR_RESEL 0x80 +#define CSR_RESEL_AM 0x81 +#define CSR_DISC 0x85 +#define CSR_SRV_REQ 0x88 + +/* Own ID/CDB Size register */ +#define OWNID_EAF 0x08 +#define OWNID_EHP 0x10 +#define OWNID_RAF 0x20 +#define OWNID_FS_8 0x00 +#define OWNID_FS_12 0x40 +#define OWNID_FS_16 0x80 + +/* define these so we don't have to change a2091.c, etc. */ +#define WD33C93_FS_8_10 OWNID_FS_8 +#define WD33C93_FS_12_15 OWNID_FS_12 +#define WD33C93_FS_16_20 OWNID_FS_16 + +/* Control register */ +#define CTRL_HSP 0x01 +#define CTRL_HA 0x02 +#define CTRL_IDI 0x04 +#define CTRL_EDI 0x08 +#define CTRL_HHP 0x10 +#define CTRL_POLLED 0x00 +#define CTRL_BURST 0x20 +#define CTRL_BUS 0x40 +#define CTRL_DMA 0x80 + +/* Timeout Period register */ #define TIMEOUT_PERIOD_VALUE 20 /* 20 = 200 ms */ - /* Synchronous Transfer Register */ +/* Synchronous Transfer Register */ #define STR_FSS 0x80 - /* Destination ID register */ +/* Destination ID register */ #define DSTID_DPD 0x40 #define DATA_OUT_DIR 0 #define DATA_IN_DIR 1 @@ -172,16 +171,17 @@ /* This is what the 3393 chip looks like to us */ typedef struct { - volatile unsigned char SASR; - char pad; - volatile unsigned char SCMD; + volatile unsigned char SASR; + char pad; +#ifdef CONFIG_SGI + char pad2, pad3; /* HPC is funny like this... */ +#endif + volatile unsigned char SCMD; } wd33c93_regs; - typedef int (*dma_setup_t) (Scsi_Cmnd *SCpnt, int dir_in); typedef void (*dma_stop_t) (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, - int status); - + int status); #define DEFAULT_SX_PER 500 /* (ns) fairly safe */ #define DEFAULT_SX_OFF 0 /* aka async */ @@ -190,60 +190,59 @@ typedef void (*dma_stop_t) (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, #define OPTIMUM_SX_OFF 12 /* size of wd3393 fifo */ struct sx_period { - unsigned int period_ns; - uchar reg_value; - }; + unsigned int period_ns; + uchar reg_value; +}; /* FEF: defines for hostdata->dma_buffer_pool */ - #define BUF_CHIP_ALLOCED 0 #define BUF_SCSI_ALLOCED 1 struct WD33C93_hostdata { - struct Scsi_Host *next; - wd33c93_regs *regp; - uchar clock_freq; - uchar chip; /* what kind of wd33c93? */ - uchar microcode; /* microcode rev */ - int dma_dir; /* data transfer dir. */ - dma_setup_t dma_setup; - dma_stop_t dma_stop; - uchar *dma_bounce_buffer; - unsigned int dma_bounce_len; - uchar dma_buffer_pool; /* FEF: buffer from chip_ram? */ - volatile uchar busy[8]; /* index = target, bit = lun */ - volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ - volatile Scsi_Cmnd *selecting; /* trying to select this command */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */ - uchar state; /* what we are currently doing */ - uchar dma; /* current state of DMA (on/off) */ - uchar level2; /* extent to which Level-2 commands are used */ - uchar disconnect; /* disconnect/reselect policy */ - unsigned int args; /* set from command-line argument */ - uchar incoming_msg[8]; /* filled during message_in phase */ - int incoming_ptr; /* mainly used with EXTENDED messages */ - uchar outgoing_msg[8]; /* send this during next message_out */ - int outgoing_len; /* length of outgoing message */ - unsigned int default_sx_per; /* default transfer period for SCSI bus */ - uchar sync_xfer[8]; /* sync_xfer reg settings per target */ - uchar sync_stat[8]; /* status of sync negotiation per target */ - uchar no_sync; /* bitmask: don't do sync on these targets */ + struct Scsi_Host *next; + wd33c93_regs *regp; + uchar clock_freq; + uchar chip; /* what kind of wd33c93? */ + uchar microcode; /* microcode rev */ + int dma_dir; /* data transfer dir. */ + dma_setup_t dma_setup; + dma_stop_t dma_stop; + uchar *dma_bounce_buffer; + unsigned int dma_bounce_len; + uchar dma_buffer_pool; /* FEF: buffer from chip_ram? */ + volatile uchar busy[8]; /* index = target, bit = lun */ + volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ + volatile Scsi_Cmnd *selecting; /* trying to select this command */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */ + uchar state; /* what we are currently doing */ + uchar dma; /* current state of DMA (on/off) */ + uchar level2; /* extent to which Level-2 commands are used */ + uchar disconnect; /* disconnect/reselect policy */ + unsigned int args; /* set from command-line argument */ + uchar incoming_msg[8]; /* filled during message_in phase */ + int incoming_ptr; /* mainly used with EXTENDED messages */ + uchar outgoing_msg[8]; /* send this during next message_out */ + int outgoing_len; /* length of outgoing message */ + unsigned int default_sx_per; /* default transfer period for SCSI bus */ + uchar sync_xfer[8]; /* sync_xfer reg settings per target */ + uchar sync_stat[8]; /* status of sync negotiation per target */ + uchar no_sync; /* bitmask: don't do sync on these targets */ #if 0 - uchar proc; /* bitmask: what's in proc output */ + uchar proc; /* bitmask: what's in proc output */ #endif - }; +}; +#define CMDHOSTDATA(cmd) ((struct WD33C93_hostdata *) (cmd)->host->hostdata) +#define INSTHOSTDATA(inst) ((struct WD33C93_hostdata *) (inst)->hostdata) /* defines for hostdata->chip */ - -#define C_WD33C93 0 -#define C_WD33C93A 1 -#define C_WD33C93B 2 -#define C_UNKNOWN_CHIP 100 +#define C_WD33C93 0 +#define C_WD33C93A 1 +#define C_WD33C93B 2 +#define C_UNKNOWN_CHIP 100 /* defines for hostdata->state */ - #define S_UNCONNECTED 0 #define S_SELECTING 1 #define S_RUNNING_LEVEL2 2 @@ -252,15 +251,18 @@ struct WD33C93_hostdata { #define S_PRE_CMP_DISC 5 /* defines for hostdata->dma */ - -#define D_DMA_OFF 0 -#define D_DMA_RUNNING 1 +#define D_DMA_OFF 0 +#define D_DMA_RUNNING 1 /* defines for hostdata->level2 */ /* NOTE: only the first 3 are implemented so far */ -#define L2_NONE 1 /* no combination commands - we get lots of ints */ +/* (The first 8 bits are reserved for compatibility. They function */ +#if 0 #define L2_SELECT 2 /* start with SEL_ATN_XFER, but never resume it */ +#endif + +#define L2_NONE 0 #define L2_BASIC 3 /* resume after STATUS ints & RDP messages */ #define L2_DATA 4 /* resume after DATA_IN/OUT ints */ #define L2_MOST 5 /* resume after anything except a RESELECT int */ @@ -268,42 +270,37 @@ struct WD33C93_hostdata { #define L2_ALL 7 /* always resume */ /* defines for hostdata->disconnect */ - #define DIS_NEVER 0 #define DIS_ADAPTIVE 1 #define DIS_ALWAYS 2 /* defines for hostdata->args */ - -#define DB_TEST1 1<<0 -#define DB_TEST2 1<<1 -#define DB_QUEUE_COMMAND 1<<2 -#define DB_EXECUTE 1<<3 -#define DB_INTR 1<<4 -#define DB_TRANSFER 1<<5 -#define DB_MASK 0x3f +#define DB_TEST1 (1<<0) +#define DB_TEST2 (1<<1) +#define DB_QCMD (1<<2) +#define DB_EXECUTE (1<<3) +#define DB_INTR (1<<4) +#define DB_TRANS (1<<5) +#define DB_MASK (0x3f) /* defines for hostdata->sync_stat[] */ - #define SS_UNSET 0 #define SS_FIRST 1 #define SS_WAITING 2 #define SS_SET 3 /* defines for hostdata->proc */ - -#define PR_VERSION 1<<0 -#define PR_INFO 1<<1 -#define PR_TOTALS 1<<2 -#define PR_CONNECTED 1<<3 -#define PR_INPUTQ 1<<4 -#define PR_DISCQ 1<<5 -#define PR_TEST 1<<6 -#define PR_STOP 1<<7 - +#define PR_VERSION (1<<0) +#define PR_INFO (1<<1) +#define PR_TOTALS (1<<2) +#define PR_CONNECTED (1<<3) +#define PR_INPUTQ (1<<4) +#define PR_DISCQ (1<<5) +#define PR_TEST (1<<6) +#define PR_STOP (1<<7) void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs, - dma_setup_t setup, dma_stop_t stop, int clock_freq); + dma_setup_t setup, dma_stop_t stop, int clock_freq); int wd33c93_abort (Scsi_Cmnd *cmd); int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); void wd33c93_intr (struct Scsi_Host *instance); |