summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-04-30 12:38:01 +1000
committerPaul Mackerras <paulus@samba.org>2007-04-30 12:38:01 +1000
commit49e1900d4cc2e7bcecb681fe60f0990bec2dcce8 (patch)
tree253801ebf57e0a23856a2c7be129c2c178f62fdf /drivers/scsi
parent34f6d749c0a328817d5e36274e53121c1db734dc (diff)
parentb9099ff63c75216d6ca10bce5a1abcd9293c27e6 (diff)
Merge branch 'linux-2.6' into for-2.6.22
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/3w-xxxx.c11
-rw-r--r--drivers/scsi/Kconfig6
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/esp.c4394
-rw-r--r--drivers/scsi/esp.h406
-rw-r--r--drivers/scsi/esp_scsi.c2711
-rw-r--r--drivers/scsi/esp_scsi.h560
-rw-r--r--drivers/scsi/hosts.c4
-rw-r--r--drivers/scsi/qlogicpti.c4
-rw-r--r--drivers/scsi/scsi_netlink.c5
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c4
-rw-r--r--drivers/scsi/sun_esp.c634
12 files changed, 3931 insertions, 4811 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index bf5d63e1beee..656bdb1352d8 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1864,10 +1864,17 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
/* This function will handle the request sense scsi command */
static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
{
+ char request_buffer[18];
+
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
- /* For now we just zero the request buffer */
- memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+ memset(request_buffer, 0, sizeof(request_buffer));
+ request_buffer[0] = 0x70; /* Immediate fixed format */
+ request_buffer[7] = 10; /* minimum size per SPC: 18 bytes */
+ /* leave all other fields zero, giving effectively NO_SENSE return */
+ tw_transfer_internal(tw_dev, request_id, request_buffer,
+ sizeof(request_buffer));
+
tw_dev->state[request_id] = TW_S_COMPLETED;
tw_state_request_finish(tw_dev, request_id);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4cd280e86966..fcc4cb6c7f46 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1763,9 +1763,15 @@ config SUN3X_ESP
The ESP was an on-board SCSI controller used on Sun 3/80
machines. Say Y here to compile in support for it.
+config SCSI_ESP_CORE
+ tristate "ESP Scsi Driver Core"
+ depends on SCSI
+ select SCSI_SPI_ATTRS
+
config SCSI_SUNESP
tristate "Sparc ESP Scsi Driver"
depends on SBUS && SCSI
+ select SCSI_ESP_CORE
help
This is the driver for the Sun ESP SCSI host adapter. The ESP
chipset is present in most SPARC SBUS-based computers.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 79ecf4ebe6eb..70cff4c599d7 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,7 +106,8 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
-obj-$(CONFIG_SCSI_SUNESP) += esp.o
+obj-$(CONFIG_SCSI_ESP_CORE) += esp_scsi.o
+obj-$(CONFIG_SCSI_SUNESP) += sun_esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o
obj-$(CONFIG_SCSI_INITIO) += initio.o
obj-$(CONFIG_SCSI_INIA100) += a100u2w.o
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
deleted file mode 100644
index 2c2fe80bc42a..000000000000
--- a/drivers/scsi/esp.c
+++ /dev/null
@@ -1,4394 +0,0 @@
-/* esp.c: ESP Sun SCSI driver.
- *
- * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
- */
-
-/* TODO:
- *
- * 1) Maybe disable parity checking in config register one for SCSI1
- * targets. (Gilmore says parity error on the SBus can lock up
- * old sun4c's)
- * 2) Add support for DMA2 pipelining.
- * 3) Add tagged queueing.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "esp.h"
-
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#ifndef __sparc_v9__
-#include <asm/machines.h>
-#include <asm/idprom.h>
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-
-#define DRV_VERSION "1.101"
-
-#define DEBUG_ESP
-/* #define DEBUG_ESP_HME */
-/* #define DEBUG_ESP_DATA */
-/* #define DEBUG_ESP_QUEUE */
-/* #define DEBUG_ESP_DISCONNECT */
-/* #define DEBUG_ESP_STATUS */
-/* #define DEBUG_ESP_PHASES */
-/* #define DEBUG_ESP_WORKBUS */
-/* #define DEBUG_STATE_MACHINE */
-/* #define DEBUG_ESP_CMDS */
-/* #define DEBUG_ESP_IRQS */
-/* #define DEBUG_SDTR */
-/* #define DEBUG_ESP_SG */
-
-/* Use the following to sprinkle debugging messages in a way which
- * suits you if combinations of the above become too verbose when
- * trying to track down a specific problem.
- */
-/* #define DEBUG_ESP_MISC */
-
-#if defined(DEBUG_ESP)
-#define ESPLOG(foo) printk foo
-#else
-#define ESPLOG(foo)
-#endif /* (DEBUG_ESP) */
-
-#if defined(DEBUG_ESP_HME)
-#define ESPHME(foo) printk foo
-#else
-#define ESPHME(foo)
-#endif
-
-#if defined(DEBUG_ESP_DATA)
-#define ESPDATA(foo) printk foo
-#else
-#define ESPDATA(foo)
-#endif
-
-#if defined(DEBUG_ESP_QUEUE)
-#define ESPQUEUE(foo) printk foo
-#else
-#define ESPQUEUE(foo)
-#endif
-
-#if defined(DEBUG_ESP_DISCONNECT)
-#define ESPDISC(foo) printk foo
-#else
-#define ESPDISC(foo)
-#endif
-
-#if defined(DEBUG_ESP_STATUS)
-#define ESPSTAT(foo) printk foo
-#else
-#define ESPSTAT(foo)
-#endif
-
-#if defined(DEBUG_ESP_PHASES)
-#define ESPPHASE(foo) printk foo
-#else
-#define ESPPHASE(foo)
-#endif
-
-#if defined(DEBUG_ESP_WORKBUS)
-#define ESPBUS(foo) printk foo
-#else
-#define ESPBUS(foo)
-#endif
-
-#if defined(DEBUG_ESP_IRQS)
-#define ESPIRQ(foo) printk foo
-#else
-#define ESPIRQ(foo)
-#endif
-
-#if defined(DEBUG_SDTR)
-#define ESPSDTR(foo) printk foo
-#else
-#define ESPSDTR(foo)
-#endif
-
-#if defined(DEBUG_ESP_MISC)
-#define ESPMISC(foo) printk foo
-#else
-#define ESPMISC(foo)
-#endif
-
-/* Command phase enumeration. */
-enum {
- not_issued = 0x00, /* Still in the issue_SC queue. */
-
- /* Various forms of selecting a target. */
-#define in_slct_mask 0x10
- in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */
- in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */
- in_slct_msg = 0x12, /* select, then send a message */
- in_slct_tag = 0x13, /* select and send tagged queue msg */
- in_slct_sneg = 0x14, /* select and acquire sync capabilities */
-
- /* Any post selection activity. */
-#define in_phases_mask 0x20
- in_datain = 0x20, /* Data is transferring from the bus */
- in_dataout = 0x21, /* Data is transferring to the bus */
- in_data_done = 0x22, /* Last DMA data operation done (maybe) */
- in_msgin = 0x23, /* Eating message from target */
- in_msgincont = 0x24, /* Eating more msg bytes from target */
- in_msgindone = 0x25, /* Decide what to do with what we got */
- in_msgout = 0x26, /* Sending message to target */
- in_msgoutdone = 0x27, /* Done sending msg out */
- in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */
- in_cmdend = 0x29, /* Done sending slow cmd */
- in_status = 0x2a, /* Was in status phase, finishing cmd */
- in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */
- in_the_dark = 0x2c, /* Don't know what bus phase we are in */
-
- /* Special states, ie. not normal bus transitions... */
-#define in_spec_mask 0x80
- in_abortone = 0x80, /* Aborting one command currently */
- in_abortall = 0x81, /* Blowing away all commands we have */
- in_resetdev = 0x82, /* SCSI target reset in progress */
- in_resetbus = 0x83, /* SCSI bus reset in progress */
- in_tgterror = 0x84, /* Target did something stupid */
-};
-
-enum {
- /* Zero has special meaning, see skipahead[12]. */
-/*0*/ do_never,
-
-/*1*/ do_phase_determine,
-/*2*/ do_reset_bus,
-/*3*/ do_reset_complete,
-/*4*/ do_work_bus,
-/*5*/ do_intr_end
-};
-
-/* Forward declarations. */
-static irqreturn_t esp_intr(int irq, void *dev_id);
-
-/* Debugging routines */
-struct esp_cmdstrings {
- u8 cmdchar;
- char *text;
-} esp_cmd_strings[] = {
- /* Miscellaneous */
- { ESP_CMD_NULL, "ESP_NOP", },
- { ESP_CMD_FLUSH, "FIFO_FLUSH", },
- { ESP_CMD_RC, "RSTESP", },
- { ESP_CMD_RS, "RSTSCSI", },
- /* Disconnected State Group */
- { ESP_CMD_RSEL, "RESLCTSEQ", },
- { ESP_CMD_SEL, "SLCTNATN", },
- { ESP_CMD_SELA, "SLCTATN", },
- { ESP_CMD_SELAS, "SLCTATNSTOP", },
- { ESP_CMD_ESEL, "ENSLCTRESEL", },
- { ESP_CMD_DSEL, "DISSELRESEL", },
- { ESP_CMD_SA3, "SLCTATN3", },
- { ESP_CMD_RSEL3, "RESLCTSEQ", },
- /* Target State Group */
- { ESP_CMD_SMSG, "SNDMSG", },
- { ESP_CMD_SSTAT, "SNDSTATUS", },
- { ESP_CMD_SDATA, "SNDDATA", },
- { ESP_CMD_DSEQ, "DISCSEQ", },
- { ESP_CMD_TSEQ, "TERMSEQ", },
- { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
- { ESP_CMD_DCNCT, "DISC", },
- { ESP_CMD_RMSG, "RCVMSG", },
- { ESP_CMD_RCMD, "RCVCMD", },
- { ESP_CMD_RDATA, "RCVDATA", },
- { ESP_CMD_RCSEQ, "RCVCMDSEQ", },
- /* Initiator State Group */
- { ESP_CMD_TI, "TRANSINFO", },
- { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
- { ESP_CMD_MOK, "MSGACCEPTED", },
- { ESP_CMD_TPAD, "TPAD", },
- { ESP_CMD_SATN, "SATN", },
- { ESP_CMD_RATN, "RATN", },
-};
-#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
-
-/* Print textual representation of an ESP command */
-static inline void esp_print_cmd(u8 espcmd)
-{
- u8 dma_bit = espcmd & ESP_CMD_DMA;
- int i;
-
- espcmd &= ~dma_bit;
- for (i = 0; i < NUM_ESP_COMMANDS; i++)
- if (esp_cmd_strings[i].cmdchar == espcmd)
- break;
- if (i == NUM_ESP_COMMANDS)
- printk("ESP_Unknown");
- else
- printk("%s%s", esp_cmd_strings[i].text,
- ((dma_bit) ? "+DMA" : ""));
-}
-
-/* Print the status register's value */
-static inline void esp_print_statreg(u8 statreg)
-{
- u8 phase;
-
- printk("STATUS<");
- phase = statreg & ESP_STAT_PMASK;
- printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
- (phase == ESP_DIP ? "DATA-IN" :
- (phase == ESP_CMDP ? "COMMAND" :
- (phase == ESP_STATP ? "STATUS" :
- (phase == ESP_MOP ? "MSG-OUT" :
- (phase == ESP_MIP ? "MSG_IN" :
- "unknown")))))));
- if (statreg & ESP_STAT_TDONE)
- printk("TRANS_DONE,");
- if (statreg & ESP_STAT_TCNT)
- printk("TCOUNT_ZERO,");
- if (statreg & ESP_STAT_PERR)
- printk("P_ERROR,");
- if (statreg & ESP_STAT_SPAM)
- printk("SPAM,");
- if (statreg & ESP_STAT_INTR)
- printk("IRQ,");
- printk(">");
-}
-
-/* Print the interrupt register's value */
-static inline void esp_print_ireg(u8 intreg)
-{
- printk("INTREG< ");
- if (intreg & ESP_INTR_S)
- printk("SLCT_NATN ");
- if (intreg & ESP_INTR_SATN)
- printk("SLCT_ATN ");
- if (intreg & ESP_INTR_RSEL)
- printk("RSLCT ");
- if (intreg & ESP_INTR_FDONE)
- printk("FDONE ");
- if (intreg & ESP_INTR_BSERV)
- printk("BSERV ");
- if (intreg & ESP_INTR_DC)
- printk("DISCNCT ");
- if (intreg & ESP_INTR_IC)
- printk("ILL_CMD ");
- if (intreg & ESP_INTR_SR)
- printk("SCSI_BUS_RESET ");
- printk(">");
-}
-
-/* Print the sequence step registers contents */
-static inline void esp_print_seqreg(u8 stepreg)
-{
- stepreg &= ESP_STEP_VBITS;
- printk("STEP<%s>",
- (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
- (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
- (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
- (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
- (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
- "UNKNOWN"))))));
-}
-
-static char *phase_string(int phase)
-{
- switch (phase) {
- case not_issued:
- return "UNISSUED";
- case in_slct_norm:
- return "SLCTNORM";
- case in_slct_stop:
- return "SLCTSTOP";
- case in_slct_msg:
- return "SLCTMSG";
- case in_slct_tag:
- return "SLCTTAG";
- case in_slct_sneg:
- return "SLCTSNEG";
- case in_datain:
- return "DATAIN";
- case in_dataout:
- return "DATAOUT";
- case in_data_done:
- return "DATADONE";
- case in_msgin:
- return "MSGIN";
- case in_msgincont:
- return "MSGINCONT";
- case in_msgindone:
- return "MSGINDONE";
- case in_msgout:
- return "MSGOUT";
- case in_msgoutdone:
- return "MSGOUTDONE";
- case in_cmdbegin:
- return "CMDBEGIN";
- case in_cmdend:
- return "CMDEND";
- case in_status:
- return "STATUS";
- case in_freeing:
- return "FREEING";
- case in_the_dark:
- return "CLUELESS";
- case in_abortone:
- return "ABORTONE";
- case in_abortall:
- return "ABORTALL";
- case in_resetdev:
- return "RESETDEV";
- case in_resetbus:
- return "RESETBUS";
- case in_tgterror:
- return "TGTERROR";
- default:
- return "UNKNOWN";
- };
-}
-
-#ifdef DEBUG_STATE_MACHINE
-static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase)
-{
- ESPLOG(("<%s>", phase_string(newphase)));
- s->SCp.sent_command = s->SCp.phase;
- s->SCp.phase = newphase;
-}
-#else
-#define esp_advance_phase(__s, __newphase) \
- (__s)->SCp.sent_command = (__s)->SCp.phase; \
- (__s)->SCp.phase = (__newphase);
-#endif
-
-#ifdef DEBUG_ESP_CMDS
-static inline void esp_cmd(struct esp *esp, u8 cmd)
-{
- esp->espcmdlog[esp->espcmdent] = cmd;
- esp->espcmdent = (esp->espcmdent + 1) & 31;
- sbus_writeb(cmd, esp->eregs + ESP_CMD);
-}
-#else
-#define esp_cmd(__esp, __cmd) \
- sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD)
-#endif
-
-#define ESP_INTSOFF(__dregs) \
- sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR)
-#define ESP_INTSON(__dregs) \
- sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR)
-#define ESP_IRQ_P(__dregs) \
- (sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR))
-
-/* How we use the various Linux SCSI data structures for operation.
- *
- * struct scsi_cmnd:
- *
- * We keep track of the synchronous capabilities of a target
- * in the device member, using sync_min_period and
- * sync_max_offset. These are the values we directly write
- * into the ESP registers while running a command. If offset
- * is zero the ESP will use asynchronous transfers.
- * If the borken flag is set we assume we shouldn't even bother
- * trying to negotiate for synchronous transfer as this target
- * is really stupid. If we notice the target is dropping the
- * bus, and we have been allowing it to disconnect, we clear
- * the disconnect flag.
- */
-
-
-/* Manipulation of the ESP command queues. Thanks to the aha152x driver
- * and its author, Juergen E. Fischer, for the methods used here.
- * Note that these are per-ESP queues, not global queues like
- * the aha152x driver uses.
- */
-static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
- struct scsi_cmnd *end;
-
- new_SC->host_scribble = (unsigned char *) NULL;
- if (!*SC)
- *SC = new_SC;
- else {
- for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble)
- ;
- end->host_scribble = (unsigned char *) new_SC;
- }
-}
-
-static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
- new_SC->host_scribble = (unsigned char *) *SC;
- *SC = new_SC;
-}
-
-static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC)
-{
- struct scsi_cmnd *ptr;
- ptr = *SC;
- if (ptr)
- *SC = (struct scsi_cmnd *) (*SC)->host_scribble;
- return ptr;
-}
-
-static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun)
-{
- struct scsi_cmnd *ptr, *prev;
-
- for (ptr = *SC, prev = NULL;
- ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
- prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble)
- ;
- if (ptr) {
- if (prev)
- prev->host_scribble=ptr->host_scribble;
- else
- *SC=(struct scsi_cmnd *)ptr->host_scribble;
- }
- return ptr;
-}
-
-/* Resetting various pieces of the ESP scsi driver chipset/buses. */
-static void esp_reset_dma(struct esp *esp)
-{
- int can_do_burst16, can_do_burst32, can_do_burst64;
- int can_do_sbus64;
- u32 tmp;
-
- can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
- can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
- can_do_burst64 = 0;
- can_do_sbus64 = 0;
- if (sbus_can_dma_64bit(esp->sdev))
- can_do_sbus64 = 1;
- if (sbus_can_burst64(esp->sdev))
- can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
-
- /* Punt the DVMA into a known state. */
- if (esp->dma->revision != dvmahme) {
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR);
- sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR);
- }
- switch (esp->dma->revision) {
- case dvmahme:
- /* This is the HME DVMA gate array. */
-
- sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR);
- sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
- esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
- esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
-
- if (can_do_burst64)
- esp->prev_hme_dmacsr |= DMA_BRST64;
- else if (can_do_burst32)
- esp->prev_hme_dmacsr |= DMA_BRST32;
-
- if (can_do_sbus64) {
- esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
- sbus_set_sbus64(esp->sdev, esp->bursts);
- }
-
- /* This chip is horrible. */
- while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ)
- udelay(1);
-
- sbus_writel(0, esp->dregs + DMA_CSR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
- /* This is necessary to avoid having the SCSI channel
- * engine lock up on us.
- */
- sbus_writel(0, esp->dregs + DMA_ADDR);
-
- break;
- case dvmarev2:
- /* This is the gate array found in the sun4m
- * NCR SBUS I/O subsystem.
- */
- if (esp->erev != esp100) {
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR);
- }
- break;
- case dvmarev3:
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp &= ~DMA_3CLKS;
- tmp |= DMA_2CLKS;
- if (can_do_burst32) {
- tmp &= ~DMA_BRST_SZ;
- tmp |= DMA_BRST32;
- }
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- break;
- case dvmaesc1:
- /* This is the DMA unit found on SCSI/Ether cards. */
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp |= DMA_ADD_ENABLE;
- tmp &= ~DMA_BCNT_ENAB;
- if (!can_do_burst32 && can_do_burst16) {
- tmp |= DMA_ESC_BURST;
- } else {
- tmp &= ~(DMA_ESC_BURST);
- }
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- break;
- default:
- break;
- };
- ESP_INTSON(esp->dregs);
-}
-
-/* Reset the ESP chip, _not_ the SCSI bus. */
-static void __init esp_reset_esp(struct esp *esp)
-{
- u8 family_code, version;
- int i;
-
- /* Now reset the ESP chip */
- esp_cmd(esp, ESP_CMD_RC);
- esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
- esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
-
- /* Reload the configuration registers */
- sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT);
- esp->prev_stp = 0;
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- esp->prev_soff = 0;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO);
-
- /* This is the only point at which it is reliable to read
- * the ID-code for a fast ESP chip variants.
- */
- esp->max_period = ((35 * esp->ccycle) / 1000);
- if (esp->erev == fast) {
- version = sbus_readb(esp->eregs + ESP_UID);
- family_code = (version & 0xf8) >> 3;
- if (family_code == 0x02)
- esp->erev = fas236;
- else if (family_code == 0x0a)
- esp->erev = fashme; /* Version is usually '5'. */
- else
- esp->erev = fas100a;
- ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
- esp->esp_id,
- (esp->erev == fas236) ? "fas236" :
- ((esp->erev == fas100a) ? "fas100a" :
- "fasHME"), family_code, (version & 7)));
-
- esp->min_period = ((4 * esp->ccycle) / 1000);
- } else {
- esp->min_period = ((5 * esp->ccycle) / 1000);
- }
- esp->max_period = (esp->max_period + 3)>>2;
- esp->min_period = (esp->min_period + 3)>>2;
-
- sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
- switch (esp->erev) {
- case esp100:
- /* nothing to do */
- break;
- case esp100a:
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- break;
- case esp236:
- /* Slow 236 */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- break;
- case fashme:
- esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
- /* fallthrough... */
- case fas236:
- /* Fast 236 or HME */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- for (i = 0; i < 16; i++) {
- if (esp->erev == fashme) {
- u8 cfg3;
-
- cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
- if (esp->scsi_id >= 8)
- cfg3 |= ESP_CONFIG3_IDBIT3;
- esp->config3[i] |= cfg3;
- } else {
- esp->config3[i] |= ESP_CONFIG3_FCLK;
- }
- }
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- if (esp->erev == fashme) {
- esp->radelay = 80;
- } else {
- if (esp->diff)
- esp->radelay = 0;
- else
- esp->radelay = 96;
- }
- break;
- case fas100a:
- /* Fast 100a */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- for (i = 0; i < 16; i++)
- esp->config3[i] |= ESP_CONFIG3_FCLOCK;
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- esp->radelay = 32;
- break;
- default:
- panic("esp: what could it be... I wonder...");
- break;
- };
-
- /* Eat any bitrot in the chip */
- sbus_readb(esp->eregs + ESP_INTRPT);
- udelay(100);
-}
-
-/* This places the ESP into a known state at boot time. */
-static void __init esp_bootup_reset(struct esp *esp)
-{
- u8 tmp;
-
- /* Reset the DMA */
- esp_reset_dma(esp);
-
- /* Reset the ESP */
- esp_reset_esp(esp);
-
- /* Reset the SCSI bus, but tell ESP not to generate an irq */
- tmp = sbus_readb(esp->eregs + ESP_CFG1);
- tmp |= ESP_CONFIG1_SRRDISAB;
- sbus_writeb(tmp, esp->eregs + ESP_CFG1);
-
- esp_cmd(esp, ESP_CMD_RS);
- udelay(400);
-
- sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
-
- /* Eat any bitrot in the chip and we are done... */
- sbus_readb(esp->eregs + ESP_INTRPT);
-}
-
-static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct sbus_dma *dma;
-
- if (dma_sdev != NULL) {
- for_each_dvma(dma) {
- if (dma->sdev == dma_sdev)
- break;
- }
- } else {
- for_each_dvma(dma) {
- /* If allocated already, can't use it. */
- if (dma->allocated)
- continue;
-
- if (dma->sdev == NULL)
- break;
-
- /* If bus + slot are the same and it has the
- * correct OBP name, it's ours.
- */
- if (sdev->bus == dma->sdev->bus &&
- sdev->slot == dma->sdev->slot &&
- (!strcmp(dma->sdev->prom_name, "dma") ||
- !strcmp(dma->sdev->prom_name, "espdma")))
- break;
- }
- }
-
- /* If we don't know how to handle the dvma,
- * do not use this device.
- */
- if (dma == NULL) {
- printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id);
- return -1;
- }
- if (dma->allocated) {
- printk("esp%d: can't use my espdma\n", esp->esp_id);
- return -1;
- }
- dma->allocated = 1;
- esp->dma = dma;
- esp->dregs = dma->regs;
-
- return 0;
-}
-
-static int __init esp_map_regs(struct esp *esp, int hme)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct resource *res;
-
- /* On HME, two reg sets exist, first is DVMA,
- * second is ESP registers.
- */
- if (hme)
- res = &sdev->resource[1];
- else
- res = &sdev->resource[0];
-
- esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers");
-
- if (esp->eregs == 0)
- return -1;
- return 0;
-}
-
-static int __init esp_map_cmdarea(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
-
- esp->esp_command = sbus_alloc_consistent(sdev, 16,
- &esp->esp_command_dvma);
- if (esp->esp_command == NULL ||
- esp->esp_command_dvma == 0)
- return -1;
- return 0;
-}
-
-static int __init esp_register_irq(struct esp *esp)
-{
- esp->ehost->irq = esp->irq = esp->sdev->irqs[0];
-
- /* We used to try various overly-clever things to
- * reduce the interrupt processing overhead on
- * sun4c/sun4m when multiple ESP's shared the
- * same IRQ. It was too complex and messy to
- * sanely maintain.
- */
- if (request_irq(esp->ehost->irq, esp_intr,
- IRQF_SHARED, "ESP SCSI", esp)) {
- printk("esp%d: Cannot acquire irq line\n",
- esp->esp_id);
- return -1;
- }
-
- printk("esp%d: IRQ %d ", esp->esp_id,
- esp->ehost->irq);
-
- return 0;
-}
-
-static void __init esp_get_scsi_id(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct device_node *dp = sdev->ofdev.node;
-
- esp->scsi_id = of_getintprop_default(dp,
- "initiator-id",
- -1);
- if (esp->scsi_id == -1)
- esp->scsi_id = of_getintprop_default(dp,
- "scsi-initiator-id",
- -1);
- if (esp->scsi_id == -1)
- esp->scsi_id = (sdev->bus == NULL) ? 7 :
- of_getintprop_default(sdev->bus->ofdev.node,
- "scsi-initiator-id",
- 7);
- esp->ehost->this_id = esp->scsi_id;
- esp->scsi_id_mask = (1 << esp->scsi_id);
-
-}
-
-static void __init esp_get_clock_params(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
- int prom_node = esp->prom_node;
- int sbus_prom_node;
- unsigned int fmhz;
- u8 ccf;
-
- if (sdev != NULL && sdev->bus != NULL)
- sbus_prom_node = sdev->bus->prom_node;
- else
- sbus_prom_node = 0;
-
- /* This is getting messy but it has to be done
- * correctly or else you get weird behavior all
- * over the place. We are trying to basically
- * figure out three pieces of information.
- *
- * a) Clock Conversion Factor
- *
- * This is a representation of the input
- * crystal clock frequency going into the
- * ESP on this machine. Any operation whose
- * timing is longer than 400ns depends on this
- * value being correct. For example, you'll
- * get blips for arbitration/selection during
- * high load or with multiple targets if this
- * is not set correctly.
- *
- * b) Selection Time-Out
- *
- * The ESP isn't very bright and will arbitrate
- * for the bus and try to select a target
- * forever if you let it. This value tells
- * the ESP when it has taken too long to
- * negotiate and that it should interrupt
- * the CPU so we can see what happened.
- * The value is computed as follows (from
- * NCR/Symbios chip docs).
- *
- * (Time Out Period) * (Input Clock)
- * STO = ----------------------------------
- * (8192) * (Clock Conversion Factor)
- *
- * You usually want the time out period to be
- * around 250ms, I think we'll set it a little
- * bit higher to account for fully loaded SCSI
- * bus's and slow devices that don't respond so
- * quickly to selection attempts. (yeah, I know
- * this is out of spec. but there is a lot of
- * buggy pieces of firmware out there so bite me)
- *
- * c) Imperical constants for synchronous offset
- * and transfer period register values
- *
- * This entails the smallest and largest sync
- * period we could ever handle on this ESP.
- */
-
- fmhz = prom_getintdefault(prom_node, "clock-frequency", -1);
- if (fmhz == -1)
- fmhz = (!sbus_prom_node) ? 0 :
- prom_getintdefault(sbus_prom_node, "clock-frequency", -1);
-
- if (fmhz <= (5000000))
- ccf = 0;
- else
- ccf = (((5000000 - 1) + (fmhz))/(5000000));
-
- if (!ccf || ccf > 8) {
- /* If we can't find anything reasonable,
- * just assume 20MHZ. This is the clock
- * frequency of the older sun4c's where I've
- * been unable to find the clock-frequency
- * PROM property. All other machines provide
- * useful values it seems.
- */
- ccf = ESP_CCF_F4;
- fmhz = (20000000);
- }
-
- if (ccf == (ESP_CCF_F7 + 1))
- esp->cfact = ESP_CCF_F0;
- else if (ccf == ESP_CCF_NEVER)
- esp->cfact = ESP_CCF_F2;
- else
- esp->cfact = ccf;
- esp->raw_cfact = ccf;
-
- esp->cfreq = fmhz;
- esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
- esp->ctick = ESP_TICK(ccf, esp->ccycle);
- esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
- esp->sync_defp = SYNC_DEFP_SLOW;
-
- printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ",
- esp->scsi_id, (fmhz / 1000000),
- (int)esp->ccycle, (int)ccf, (int) esp->neg_defp);
-}
-
-static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
-{
- struct sbus_dev *sdev = esp->sdev;
- u8 bursts;
-
- bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff);
-
- if (dma) {
- u8 tmp = prom_getintdefault(dma->prom_node,
- "burst-sizes", 0xff);
- if (tmp != 0xff)
- bursts &= tmp;
- }
-
- if (sdev->bus) {
- u8 tmp = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0xff);
- if (tmp != 0xff)
- bursts &= tmp;
- }
-
- if (bursts == 0xff ||
- (bursts & DMA_BURST16) == 0 ||
- (bursts & DMA_BURST32) == 0)
- bursts = (DMA_BURST32 - 1);
-
- esp->bursts = bursts;
-}
-
-static void __init esp_get_revision(struct esp *esp)
-{
- u8 tmp;
-
- esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
- esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-
- tmp = sbus_readb(esp->eregs + ESP_CFG2);
- tmp &= ~ESP_CONFIG2_MAGIC;
- if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
- /* If what we write to cfg2 does not come back, cfg2
- * is not implemented, therefore this must be a plain
- * esp100.
- */
- esp->erev = esp100;
- printk("NCR53C90(esp100)\n");
- } else {
- esp->config2 = 0;
- esp->prev_cfg3 = esp->config3[0] = 5;
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- sbus_writeb(0, esp->eregs + ESP_CFG3);
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- tmp = sbus_readb(esp->eregs + ESP_CFG3);
- if (tmp != 5) {
- /* The cfg2 register is implemented, however
- * cfg3 is not, must be esp100a.
- */
- esp->erev = esp100a;
- printk("NCR53C90A(esp100a)\n");
- } else {
- int target;
-
- for (target = 0; target < 16; target++)
- esp->config3[target] = 0;
- esp->prev_cfg3 = 0;
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- /* All of cfg{1,2,3} implemented, must be one of
- * the fas variants, figure out which one.
- */
- if (esp->raw_cfact > ESP_CCF_F5) {
- esp->erev = fast;
- esp->sync_defp = SYNC_DEFP_FAST;
- printk("NCR53C9XF(espfast)\n");
- } else {
- esp->erev = esp