patch-2.2.4 linux/drivers/scsi/esp.c
Next file: linux/drivers/scsi/esp.h
Previous file: linux/drivers/scsi/Makefile
Back to the patch index
Back to the overall index
- Lines: 2124
- Date:
Mon Mar 15 16:11:31 1999
- Orig file:
v2.2.3/linux/drivers/scsi/esp.c
- Orig date:
Thu Nov 19 09:56:28 1998
diff -u --recursive --new-file v2.2.3/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
@@ -1,6 +1,6 @@
/* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
*/
/* TODO:
@@ -162,6 +162,17 @@
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
+};
+
struct proc_dir_entry proc_scsi_esp = {
PROC_SCSI_ESP, 3, "esp",
S_IFDIR | S_IRUGO | S_IXUGO, 2
@@ -354,24 +365,30 @@
};
}
+#ifdef DEBUG_STATE_MACHINE
static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase)
{
-#ifdef DEBUG_STATE_MACHINE
ESPLOG(("<%s>", phase_string(newphase)));
-#endif
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
extern inline void esp_cmd(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
unchar cmd)
{
-#ifdef DEBUG_ESP_CMDS
esp->espcmdlog[esp->espcmdent] = cmd;
esp->espcmdent = (esp->espcmdent + 1) & 31;
-#endif
eregs->esp_cmd = cmd;
}
+#else
+#define esp_cmd(__esp, __eregs, __cmd) (__eregs)->esp_cmd = (__cmd)
+#endif
/* How we use the various Linux SCSI data structures for operation.
*
@@ -442,14 +459,23 @@
}
/* Resetting various pieces of the ESP scsi driver chipset/buses. */
-static inline void esp_reset_dma(struct Sparc_ESP *esp)
+static void esp_reset_dma(struct Sparc_ESP *esp)
{
struct sparc_dma_registers *dregs = esp->dregs;
- unsigned long tmp, flags;
- int can_do_burst16, can_do_burst32;
+ unsigned long flags;
+ int can_do_burst16, can_do_burst32, can_do_burst64;
+ int can_do_sbus64;
can_do_burst16 = esp->bursts & DMA_BURST16;
can_do_burst32 = esp->bursts & DMA_BURST32;
+ can_do_burst64 = 0;
+ can_do_sbus64 = 0;
+#ifdef __sparc_v9__
+ /* XXX Can sun4d do these too? */
+ can_do_burst64 = esp->bursts & DMA_BURST64;
+ can_do_sbus64 = 1;
+ mmu_set_sbus64(esp->edev, esp->bursts);
+#endif
/* Punt the DVMA into a known state. */
if(esp->dma->revision != dvmahme) {
@@ -462,14 +488,19 @@
save_flags(flags); cli(); /* I really hate this chip. */
- dregs->cond_reg = 0x08000000; /* Reset interface to FAS */
- dregs->cond_reg = DMA_RST_SCSI; /* Reset DVMA itself */
+ dregs->cond_reg = DMA_RESET_FAS366; /* Reset interface to FAS */
+ dregs->cond_reg = DMA_RST_SCSI; /* Reset DVMA itself */
- tmp = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
- tmp &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
+ 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_burst32)
- tmp |= DMA_BRST32;
+ esp->prev_hme_dmacsr |= DMA_BRST32;
+ else if(can_do_burst64)
+ esp->prev_hme_dmacsr |= DMA_BRST64;
+
+ if(can_do_sbus64)
+ esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
/* This chip is horrible. */
while(dregs->cond_reg & DMA_PEND_READ)
@@ -477,8 +508,14 @@
dregs->cond_reg = 0;
- dregs->cond_reg = tmp; /* bite me */
- restore_flags(flags); /* ugh... */
+ dregs->cond_reg = esp->prev_hme_dmacsr;
+
+ /* This is necessary to avoid having the SCSI channel
+ * engine lock up on us.
+ */
+ dregs->st_addr = 0;
+
+ restore_flags(flags);
break;
case dvmarev2:
/* This is the gate array found in the sun4m
@@ -512,7 +549,7 @@
}
/* Reset the ESP chip, _not_ the SCSI bus. */
-static inline void esp_reset_esp(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+static void esp_reset_esp(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
{
int family_code, version, i;
volatile int trash;
@@ -524,8 +561,8 @@
/* Reload the configuration registers */
eregs->esp_cfact = esp->cfact;
- eregs->esp_stp = 0;
- eregs->esp_soff = 0;
+ eregs->esp_stp = esp->prev_stp = 0;
+ eregs->esp_soff = esp->prev_soff = 0;
eregs->esp_timeo = esp->neg_defp;
/* This is the only point at which it is reliable to read
@@ -541,11 +578,11 @@
esp->erev = fashme; /* Version is usually '5'. */
else
esp->erev = fas100a;
- printk("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));
+ 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 {
@@ -565,7 +602,7 @@
case esp236:
/* Slow 236 */
eregs->esp_cfg2 = esp->config2;
- eregs->esp_cfg3 = esp->config3[0];
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0];
break;
case fashme:
esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
@@ -574,13 +611,18 @@
/* Fast 236 or HME */
eregs->esp_cfg2 = esp->config2;
for(i=0; i<8; i++) {
- if(esp->erev == fashme)
- esp->config3[i] |=
- (ESP_CONFIG3_FCLOCK | ESP_CONFIG3_BIGID | ESP_CONFIG3_OBPUSH);
- else
+ if(esp->erev == fashme) {
+ unsigned char 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;
+ }
}
- eregs->esp_cfg3 = esp->config3[0];
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0];
if(esp->erev == fashme) {
esp->radelay = 80;
} else {
@@ -595,7 +637,7 @@
eregs->esp_cfg2 = esp->config2;
for(i=0; i<8; i++)
esp->config3[i] |= ESP_CONFIG3_FCLOCK;
- eregs->esp_cfg3 = esp->config3[0];
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0];
esp->radelay = 32;
break;
default:
@@ -609,7 +651,7 @@
}
/* This places the ESP into a known state at boot time. */
-static inline void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+static void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
{
volatile unchar trash;
@@ -654,6 +696,10 @@
esp->edev = esp_dev;
esp->esp_id = id;
+#ifdef __sparc_v9__
+ esp_host->unchecked_isa_dma = 1;
+#endif
+
/* Put into the chain of esp chips detected */
if(espchain) {
elink = espchain;
@@ -877,7 +923,7 @@
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 Clock %d MHz CCF=%d Time-Out %d ",
+ printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ",
esp->scsi_id, (fmhz / 1000000),
ccf, (int) esp->neg_defp);
@@ -910,28 +956,28 @@
eregs->esp_cfg2 = esp->config2;
if((eregs->esp_cfg2 & ~(ESP_CONFIG2_MAGIC)) !=
(ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
- printk("NCR53C90(esp100) detected\n");
+ printk("NCR53C90(esp100)\n");
esp->erev = esp100;
} else {
eregs->esp_cfg2 = esp->config2 = 0;
eregs->esp_cfg3 = 0;
- eregs->esp_cfg3 = esp->config3[0] = 5;
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[0] = 5;
if(eregs->esp_cfg3 != 5) {
- printk("NCR53C90A(esp100a) detected\n");
+ printk("NCR53C90A(esp100a)\n");
esp->erev = esp100a;
} else {
int target;
for(target=0; target<8; target++)
esp->config3[target] = 0;
- eregs->esp_cfg3 = 0;
+ eregs->esp_cfg3 = esp->prev_cfg3 = 0;
if(ccf > ESP_CCF_F5) {
- printk("NCR53C9XF(espfast) detected\n");
+ printk("NCR53C9XF(espfast)\n");
esp->erev = fast;
eregs->esp_cfg2 = esp->config2 = 0;
esp->sync_defp = SYNC_DEFP_FAST;
} else {
- printk("NCR53C9x(esp236) detected\n");
+ printk("NCR53C9x(esp236)\n");
esp->erev = esp236;
eregs->esp_cfg2 = esp->config2 = 0;
}
@@ -958,6 +1004,10 @@
esp->prevmsgout = esp->prevmsgin = 0;
esp->msgout_len = esp->msgin_len = 0;
+ /* Clear the one behind caches to hold unmatchable values. */
+ esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
+ esp->prev_hme_dmacsr = 0xffffffff;
+
/* Reset the thing before we try anything... */
esp_bootup_reset(esp, eregs);
@@ -1238,6 +1288,59 @@
return esp_host_info(esp, buffer, offset, length);
}
+static void esp_get_dmabufs(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
+{
+ if(sp->use_sg == 0) {
+ sp->SCp.this_residual = sp->request_bufflen;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
+ sp->SCp.buffers_residual = 0;
+ sp->SCp.have_data_in = mmu_get_scsi_one((char *)sp->SCp.buffer,
+ sp->SCp.this_residual,
+ esp->edev->my_bus);
+ sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
+ } else {
+ sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffers_residual = sp->use_sg - 1;
+ sp->SCp.this_residual = sp->SCp.buffer->length;
+ mmu_get_scsi_sgl((struct mmu_sglist *) sp->SCp.buffer,
+ sp->SCp.buffers_residual,
+ esp->edev->my_bus);
+ sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.buffer->dvma_address);
+ }
+}
+
+static void esp_release_dmabufs(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
+{
+ if(sp->use_sg == 0)
+ mmu_release_scsi_one(sp->SCp.have_data_in,
+ sp->request_bufflen,
+ esp->edev->my_bus);
+ else
+ mmu_release_scsi_sgl((struct mmu_sglist *)
+ sp->buffer, sp->use_sg - 1,
+ esp->edev->my_bus);
+}
+
+static void esp_restore_pointers(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
+{
+ struct esp_pointers *ep = &esp->data_pointers[sp->target];
+
+ sp->SCp.ptr = ep->saved_ptr;
+ sp->SCp.buffer = ep->saved_buffer;
+ sp->SCp.this_residual = ep->saved_this_residual;
+ sp->SCp.buffers_residual = ep->saved_buffers_residual;
+}
+
+static void esp_save_pointers(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
+{
+ struct esp_pointers *ep = &esp->data_pointers[sp->target];
+
+ ep->saved_ptr = sp->SCp.ptr;
+ ep->saved_buffer = sp->SCp.buffer;
+ ep->saved_this_residual = sp->SCp.this_residual;
+ ep->saved_buffers_residual = sp->SCp.buffers_residual;
+}
+
/* Some rules:
*
* 1) Never ever panic while something is live on the bus.
@@ -1307,7 +1410,7 @@
esp->msgout_len = 4;
}
-static inline void esp_exec_cmd(struct Sparc_ESP *esp)
+static void esp_exec_cmd(struct Sparc_ESP *esp)
{
struct sparc_dma_registers *dregs = esp->dregs;
struct Sparc_ESP_regs *eregs = esp->eregs;
@@ -1318,15 +1421,18 @@
int lun, target;
int i;
- /* Hold off if we've been reselected or an IRQ is showing... */
- if(esp->disconnected_SC || DMA_IRQ_P(dregs))
+ /* Hold off if we have disconnected commands and
+ * an IRQ is showing...
+ */
+ if(esp->disconnected_SC && DMA_IRQ_P(dregs))
return;
/* Grab first member of the issue queue. */
SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
/* Safe to panic here because current_SC is null. */
- if(!SCptr) panic("esp: esp_exec_cmd and issue queue is NULL");
+ if(!SCptr)
+ panic("esp: esp_exec_cmd and issue queue is NULL");
SDptr = SCptr->device;
lun = SCptr->lun;
@@ -1402,7 +1508,10 @@
SDptr->sync_max_offset = 0;
SDptr->sync_min_period = 0;
} else {
- int toshiba_cdrom_hwbug_wkaround = 0;
+ /* Sorry, I have had way too many problems with
+ * various CDROM devices on ESP. -DaveM
+ */
+ int cdrom_hwbug_wkaround = 0;
/* Never allow disconnects or synchronous transfers on
* SparcStation1 and SparcStation1+. Allowing those
@@ -1429,8 +1538,7 @@
*/
if(esp->erev == fashme && !SDptr->wide) {
if(!SDptr->borken &&
- (SDptr->type != TYPE_ROM ||
- strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+ SDptr->type != TYPE_ROM) {
build_wide_nego_msg(esp, 16);
SDptr->wide = 1;
esp->wnip = 1;
@@ -1442,12 +1550,11 @@
}
if(!SDptr->borken) {
- if((SDptr->type == TYPE_ROM) &&
- (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+ if((SDptr->type == TYPE_ROM)) {
/* Nice try sucker... */
- printk(KERN_INFO "esp%d: Disabling sync for buggy "
- "Toshiba CDROM.\n", esp->esp_id);
- toshiba_cdrom_hwbug_wkaround = 1;
+ ESPMISC(("esp%d: Disabling sync for buggy "
+ "CDROM.\n", esp->esp_id));
+ cdrom_hwbug_wkaround = 1;
build_sync_nego_msg(esp, 0, 0);
} else {
build_sync_nego_msg(esp, esp->sync_defp, 15);
@@ -1483,13 +1590,9 @@
* thank you very much. ;-)
*/
if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
-#if 1 /* Until I find out why HME barfs with disconnects enabled... */
- toshiba_cdrom_hwbug_wkaround || SDptr->borken || esp->erev == fashme) {
-#else
- toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
-#endif
- printk(KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
- "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun);
+ cdrom_hwbug_wkaround || SDptr->borken) {
+ ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+ "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
SDptr->disconnect = 0;
*cmdp++ = IDENTIFY(0, lun);
} else {
@@ -1517,16 +1620,20 @@
(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
else
eregs->esp_busid = (target & 7);
- eregs->esp_soff = SDptr->sync_max_offset;
- eregs->esp_stp = SDptr->sync_min_period;
- if(esp->erev > esp100a)
- eregs->esp_cfg3 = esp->config3[target];
-
+ if (esp->prev_soff != SDptr->sync_max_offset ||
+ esp->prev_stp != SDptr->sync_min_period ||
+ (esp->erev > esp100a &&
+ esp->prev_cfg3 != esp->config3[target])) {
+ eregs->esp_soff = esp->prev_soff = SDptr->sync_max_offset;
+ eregs->esp_stp = esp->prev_stp = SDptr->sync_min_period;
+ if(esp->erev > esp100a)
+ eregs->esp_cfg3 =
+ esp->prev_cfg3 =
+ esp->config3[target];
+ }
i = (cmdp - esp->esp_command);
if(esp->erev == fashme) {
- unsigned long tmp;
-
esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* Grrr! */
/* Set up the DMA and HME counters */
@@ -1537,12 +1644,12 @@
esp_cmd(esp, eregs, the_esp_command);
/* Talk about touchy hardware... */
- tmp = dregs->cond_reg;
- tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
- tmp &= ~(DMA_ST_WRITE);
+ esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+ (DMA_SCSI_DISAB | DMA_ENABLE)) &
+ ~(DMA_ST_WRITE));
dregs->cnt = 16;
dregs->st_addr = esp->esp_command_dvma;
- dregs->cond_reg = tmp;
+ dregs->cond_reg = esp->prev_hme_dmacsr;
} else {
/* Set up the DMA and ESP counters */
eregs->esp_tclow = i;
@@ -1575,35 +1682,10 @@
/* We use the scratch area. */
ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
- if(!SCpnt->use_sg) {
- ESPQUEUE(("!use_sg\n"));
- SCpnt->SCp.this_residual = SCpnt->request_bufflen;
- SCpnt->SCp.buffer =
- (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->SCp.buffers_residual = 0;
- /* Sneaky. */
- SCpnt->SCp.have_data_in = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
- SCpnt->SCp.this_residual,
- esp->edev->my_bus);
- /* XXX The casts are extremely gross, but with 64-bit kernel
- * XXX and 32-bit SBUS what am I to do? -DaveM
- */
- SCpnt->SCp.ptr = (char *)((unsigned long)SCpnt->SCp.have_data_in);
- } else {
- ESPQUEUE(("use_sg "));
-#ifdef DEBUG_ESP_SG
- printk("esp%d: sglist at %p with %d buffers\n",
- esp->esp_id, SCpnt->buffer, SCpnt->use_sg);
-#endif
- SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
- SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
- SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
- SCpnt->SCp.buffers_residual,
- esp->edev->my_bus);
- /* XXX Again these casts are sick... -DaveM */
- SCpnt->SCp.ptr=(char *)((unsigned long)SCpnt->SCp.buffer->dvma_address);
- }
+
+ esp_get_dmabufs(esp, SCpnt);
+ esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
+
SCpnt->SCp.Status = CHECK_CONDITION;
SCpnt->SCp.Message = 0xff;
SCpnt->SCp.sent_command = 0;
@@ -1634,7 +1716,7 @@
}
/* Dump driver state. */
-static inline void esp_dump_cmd(Scsi_Cmnd *SCptr)
+static void esp_dump_cmd(Scsi_Cmnd *SCptr)
{
ESPLOG(("[tgt<%02x> lun<%02x> "
"pphase<%s> cphase<%s>]",
@@ -1643,8 +1725,8 @@
phase_string(SCptr->SCp.phase)));
}
-static inline void esp_dump_state(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static void esp_dump_state(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
Scsi_Cmnd *SCptr = esp->current_SC;
#ifdef DEBUG_ESP_CMDS
@@ -1735,6 +1817,7 @@
if(this == SCptr) {
*prev = (Scsi_Cmnd *) this->host_scribble;
this->host_scribble = NULL;
+ esp_release_dmabufs(esp, this);
this->result = DID_ABORT << 16;
this->done(this);
if(don)
@@ -1749,8 +1832,11 @@
* on the bus at this time. So, we let the SCSI code wait
* a little bit and try again later.
*/
- if(esp->current_SC)
+ if(esp->current_SC) {
+ if(don)
+ DMA_INTSON(dregs);
return SCSI_ABORT_BUSY;
+ }
/* It's disconnected, we have to reconnect to re-establish
* the nexus and tell the device to abort. However, we really
@@ -1759,20 +1845,70 @@
* happens, we are really hung so reset the bus.
*/
+ if(don)
+ DMA_INTSON(dregs);
return SCSI_ABORT_SNOOZE;
}
+/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
+ * arrived indicating the end of the SCSI bus reset. Our job
+ * is to clean out the command queues and begin re-execution
+ * of SCSI commands once more.
+ */
+static int esp_finish_reset(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ Scsi_Cmnd *sp = esp->current_SC;
+
+ /* Clean up currently executing command, if any. */
+ if (sp != NULL) {
+ esp_release_dmabufs(esp, sp);
+ sp->result = (DID_RESET << 16);
+ sp->scsi_done(sp);
+ esp->current_SC = NULL;
+ }
+
+ /* Clean up disconnected queue, they have been invalidated
+ * by the bus reset.
+ */
+ if (esp->disconnected_SC) {
+ while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
+ esp_release_dmabufs(esp, sp);
+ sp->result = (DID_RESET << 16);
+ sp->scsi_done(sp);
+ }
+ }
+
+ /* SCSI bus reset is complete. */
+ esp->resetting_bus = 0;
+
+ /* Ok, now it is safe to get commands going once more. */
+ if(esp->issue_SC)
+ esp_exec_cmd(esp);
+
+ return do_intr_end;
+}
+
+static int esp_do_resetbus(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+ esp->resetting_bus = 1;
+ esp_cmd(esp, eregs, ESP_CMD_RS);
+
+ return do_intr_end;
+}
+
/* Reset ESP chip, reset hanging bus, then kill active and
* disconnected commands for targets without soft reset.
*/
int esp_reset(Scsi_Cmnd *SCptr, unsigned int how)
{
struct Sparc_ESP *esp = (struct Sparc_ESP *) SCptr->host->hostdata;
- struct Sparc_ESP_regs *eregs = esp->eregs;
- ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
- esp->resetting_bus = 1;
- esp_cmd(esp, eregs, ESP_CMD_RS);
+ (void) esp_do_resetbus(esp, esp->eregs, esp->dregs);
return SCSI_RESET_PENDING;
}
@@ -1784,25 +1920,7 @@
if(esp->current_SC) {
done_SC = esp->current_SC;
esp->current_SC = NULL;
-
- /* Free dvma entry. */
- if(!done_SC->use_sg) {
- /* Sneaky. */
- mmu_release_scsi_one(done_SC->SCp.have_data_in,
- done_SC->request_bufflen,
- esp->edev->my_bus);
- } else {
-#ifdef DEBUG_ESP_SG
- printk("esp%d: unmapping sg ", esp->esp_id);
-#endif
- mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
- done_SC->use_sg - 1,
- esp->edev->my_bus);
-#ifdef DEBUG_ESP_SG
- printk("done.\n");
-#endif
- }
-
+ esp_release_dmabufs(esp, done_SC);
done_SC->result = error;
done_SC->scsi_done(done_SC);
@@ -1820,11 +1938,6 @@
/* Wheee, ESP interrupt engine. */
-enum {
- do_phase_determine, do_reset_bus, do_reset_complete,
- do_work_bus, do_intr_end,
-};
-
/* Forward declarations. */
static int esp_do_phase_determine(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
struct sparc_dma_registers *dregs);
@@ -1843,29 +1956,29 @@
static int esp_do_cmdbegin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
struct sparc_dma_registers *dregs);
-static inline int sreg_datainp(unchar sreg)
-{
- return (sreg & ESP_STAT_PMASK) == ESP_DIP;
-}
-
-static inline int sreg_dataoutp(unchar sreg)
-{
- return (sreg & ESP_STAT_PMASK) == ESP_DOP;
-}
+#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
+#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
-/* Did they drop these fabs on the floor or what?!?!! */
-static inline void hme_fifo_hwbug_workaround(struct Sparc_ESP *esp,
- struct Sparc_ESP_regs *eregs)
+/* Read any bytes found in the FAS366 fifo, storing them into
+ * the ESP driver software state structure.
+ */
+static void hme_fifo_read(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs)
{
+ unsigned long count = 0;
unchar status = esp->sreg;
- /* Cannot safely frob the fifo for these following cases. */
- if(sreg_datainp(status) || sreg_dataoutp(status) ||
- (esp->current_SC && esp->current_SC->SCp.phase == in_data_done)) {
+ /* Cannot safely frob the fifo for these following cases, but
+ * we must always read the fifo when the reselect interrupt
+ * is pending.
+ */
+ if(((esp->ireg & ESP_INTR_RSEL) == 0) &&
+ (sreg_datainp(status) ||
+ sreg_dataoutp(status) ||
+ (esp->current_SC &&
+ esp->current_SC->SCp.phase == in_data_done))) {
ESPHME(("<wkaround_skipped>"));
- return;
} else {
- unsigned long count = 0;
unsigned long fcnt = eregs->esp_fflags & ESP_FF_FBYTES;
/* The HME stores bytes in multiples of 2 in the fifo. */
@@ -1886,9 +1999,9 @@
} else {
ESPHME(("no_xtra_byte"));
}
- esp->hme_fifo_workaround_count = count;
- ESPHME(("wkarnd_cnt=%d]", (int)count));
}
+ ESPHME(("wkarnd_cnt=%d]", (int)count));
+ esp->hme_fifo_workaround_count = count;
}
static inline void hme_fifo_push(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
@@ -1913,7 +2026,10 @@
return 0;
if(DMA_IRQ_P(dregs)) {
/* Yes, we are able to save an interrupt. */
- esp->sreg = eregs->esp_status;
+ if (esp->erev == fashme)
+ esp->sreg2 = eregs->esp_status2;
+ esp->sreg = (eregs->esp_status & ~(ESP_STAT_INTR));
+ esp->ireg = eregs->esp_intrpt;
if(esp->erev == fashme) {
/* This chip is really losing. */
ESPHME(("HME["));
@@ -1923,10 +2039,10 @@
* Happy Meal indeed....
*/
ESPHME(("fifo_workaround]"));
- hme_fifo_hwbug_workaround(esp, eregs);
+ if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+ (esp->sreg2 & ESP_STAT2_F1BYTE))
+ hme_fifo_read(esp, eregs);
}
- esp->ireg = eregs->esp_intrpt;
- esp->sreg &= ~(ESP_STAT_INTR);
if(!(esp->ireg & ESP_INTR_SR))
return 0;
else
@@ -1947,7 +2063,10 @@
return 0;
if(DMA_IRQ_P(dregs)) {
/* Yes, we are able to save an interrupt. */
- esp->sreg = eregs->esp_status;
+ if (esp->erev == fashme)
+ esp->sreg2 = eregs->esp_status2;
+ esp->sreg = (eregs->esp_status & ~(ESP_STAT_INTR));
+ esp->ireg = eregs->esp_intrpt;
if(esp->erev == fashme) {
/* This chip is really losing. */
ESPHME(("HME["));
@@ -1958,10 +2077,10 @@
* Happy Meal indeed....
*/
ESPHME(("fifo_workaround]"));
- hme_fifo_hwbug_workaround(esp, eregs);
+ if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+ (esp->sreg2 & ESP_STAT2_F1BYTE))
+ hme_fifo_read(esp, eregs);
}
- esp->ireg = eregs->esp_intrpt;
- esp->sreg &= ~(ESP_STAT_INTR);
if(!(esp->ireg & ESP_INTR_SR))
return 0;
else
@@ -2012,21 +2131,27 @@
}
}
-static inline void dma_invalidate(struct sparc_dma_registers *dregs, enum dvma_rev drev)
+static inline void dma_invalidate(struct Sparc_ESP *esp,
+ struct sparc_dma_registers *dregs,
+ enum dvma_rev drev)
{
unsigned int tmp;
if(drev == dvmahme) {
- /* SMCC can bite me. */
- tmp = dregs->cond_reg;
dregs->cond_reg = DMA_RST_SCSI;
- /* This would explain a lot. */
- tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB);
+ esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+ (DMA_PARITY_OFF | DMA_2CLKS |
+ DMA_SCSI_DISAB | DMA_INT_ENAB)) &
+ ~(DMA_ST_WRITE | DMA_ENABLE));
- tmp &= ~(DMA_ENABLE|DMA_ST_WRITE);
dregs->cond_reg = 0;
- dregs->cond_reg = tmp;
+ dregs->cond_reg = esp->prev_hme_dmacsr;
+
+ /* This is necessary to avoid having the SCSI channel
+ * engine lock up on us.
+ */
+ dregs->st_addr = 0;
} else {
while(dregs->cond_reg & DMA_PEND_READ)
udelay(1);
@@ -2039,10 +2164,12 @@
}
}
-static inline void dma_flashclear(struct sparc_dma_registers *dregs, enum dvma_rev drev)
+static inline void dma_flashclear(struct Sparc_ESP *esp,
+ struct sparc_dma_registers *dregs,
+ enum dvma_rev drev)
{
dma_drain(dregs, drev);
- dma_invalidate(dregs, drev);
+ dma_invalidate(esp, dregs, drev);
}
static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
@@ -2064,56 +2191,38 @@
return sz;
}
-/* Misc. esp helper routines. */
-static inline void esp_setcount(struct Sparc_ESP_regs *eregs, int cnt, int hme)
-{
- eregs->esp_tclow = (cnt & 0xff);
- eregs->esp_tcmed = ((cnt >> 8) & 0xff);
- if(hme) {
- eregs->fas_rlo = 0;
- eregs->fas_rhi = 0;
- }
-}
-
-static inline int esp_getcount(struct Sparc_ESP_regs *eregs)
-{
- return (((eregs->esp_tclow)&0xff) |
- (((eregs->esp_tcmed)&0xff) << 8));
-}
-
-static inline int fcount(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
-{
- if(esp->erev == fashme)
- return esp->hme_fifo_workaround_count;
- else
- return eregs->esp_fflags & ESP_FF_FBYTES;
-}
-
-static inline int fnzero(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
-{
- if(esp->erev == fashme)
- return 0;
- else
- return eregs->esp_fflags & ESP_FF_ONOTZERO;
-}
+/* Misc. esp helper macros. */
+#define esp_setcount(__eregs, __cnt, __hme) \
+ (__eregs)->esp_tclow = ((__cnt) & 0xff); \
+ (__eregs)->esp_tcmed = (((__cnt) >> 8) & 0xff); \
+ if(__hme) { \
+ (__eregs)->fas_rlo = 0; \
+ (__eregs)->fas_rhi = 0; \
+ }
+
+#define esp_getcount(__eregs) \
+ ((((__eregs)->esp_tclow)&0xff) | \
+ ((((__eregs)->esp_tcmed)&0xff) << 8))
+
+#define fcount(__esp, __eregs) \
+ (((__esp)->erev == fashme) ? \
+ (__esp)->hme_fifo_workaround_count : \
+ (__eregs)->esp_fflags & ESP_FF_FBYTES)
+
+#define fnzero(__esp, __eregs) \
+ (((__esp)->erev == fashme) ? 0 : \
+ (__eregs)->esp_fflags & ESP_FF_ONOTZERO)
/* XXX speculative nops unnecessary when continuing amidst a data phase
* XXX even on esp100!!! another case of flooding the bus with I/O reg
* XXX writes...
*/
-static inline void esp_maybe_nop(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
-{
- if(esp->erev == esp100)
- esp_cmd(esp, eregs, ESP_CMD_NULL);
-}
+#define esp_maybe_nop(__esp, __eregs) \
+ if((__esp)->erev == esp100) \
+ esp_cmd((__esp), (__eregs), ESP_CMD_NULL)
-static inline int sreg_to_dataphase(unchar sreg)
-{
- if((sreg & ESP_STAT_PMASK) == ESP_DOP)
- return in_dataout;
- else
- return in_datain;
-}
+#define sreg_to_dataphase(__sreg) \
+ ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
/* The ESP100 when in synchronous data phase, can mistake a long final
* REQ pulse from the target as an extra byte, it places whatever is on
@@ -2205,10 +2314,19 @@
lun = esp->hme_fifo_workaround_buffer[1];
else
lun = eregs->esp_fdata;
+
+ /* Yes, you read this correctly. We report lun of zero
+ * if we see parity error. ESP reports parity error for
+ * the lun byte, and this is the only way to hope to recover
+ * because the target is connected.
+ */
if(esp->sreg & ESP_STAT_PERR)
return 0;
+
+ /* Check for illegal bits being set in the lun. */
if((lun & 0x40) || !(lun & 0x80))
return -1;
+
return lun & 7;
}
@@ -2219,13 +2337,18 @@
Scsi_Cmnd *sp)
{
Scsi_Device *dp = sp->device;
- eregs->esp_soff = dp->sync_max_offset;
- eregs->esp_stp = dp->sync_min_period;
- if(esp->erev > esp100a)
- eregs->esp_cfg3 = esp->config3[sp->target];
- if(esp->erev == fashme)
- eregs->esp_busid = (sp->target & 0xf) |
- (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+
+ if(esp->prev_soff != dp->sync_max_offset ||
+ esp->prev_stp != dp->sync_min_period ||
+ (esp->erev > esp100a &&
+ esp->prev_cfg3 != esp->config3[sp->target])) {
+ eregs->esp_soff = esp->prev_soff = dp->sync_max_offset;
+ eregs->esp_stp = esp->prev_stp = dp->sync_min_period;
+ if(esp->erev > esp100a)
+ eregs->esp_cfg3 =
+ esp->prev_cfg3 =
+ esp->config3[sp->target];
+ }
esp->current_SC = sp;
}
@@ -2235,8 +2358,8 @@
static inline void esp_reconnect(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
{
if(!esp->disconnected_SC)
- printk("esp%d: Weird, being reselected but disconnected "
- "command queue is empty.\n", esp->esp_id);
+ ESPLOG(("esp%d: Weird, being reselected but disconnected "
+ "command queue is empty.\n", esp->esp_id));
esp->snip = 0;
esp->current_SC = 0;
sp->SCp.phase = not_issued;
@@ -2244,8 +2367,8 @@
}
/* Begin message in phase. */
-static inline int esp_do_msgin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_msgin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
/* Must be very careful with the fifo on the HME */
if((esp->erev != fashme) || !(eregs->esp_status2 & ESP_STAT2_FEMPTY))
@@ -2298,8 +2421,8 @@
* within a buffer or sub-buffer should not upset us at all no matter
* how bad the target and/or ESP fucks things up.
*/
-static inline int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
Scsi_Cmnd *SCptr = esp->current_SC;
int thisphase, hmuch;
@@ -2313,19 +2436,28 @@
ESPDATA(("hmuch<%d> ", hmuch));
esp->current_transfer_size = hmuch;
if(esp->erev == fashme) {
- unsigned long tmp = dregs->cond_reg;
+ unsigned long tmp = esp->prev_hme_dmacsr;
- /* Touchy chip, this stupid HME scsi adapter... */
+ /* Always set the ESP count registers first. */
esp_setcount(eregs, hmuch, 1);
- esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
- dregs->cnt = hmuch;
+
+ /* Get the DMA csr computed. */
tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
- if(thisphase == in_datain)
+ if (thisphase == in_datain)
tmp |= DMA_ST_WRITE;
else
tmp &= ~(DMA_ST_WRITE);
+ esp->prev_hme_dmacsr = tmp;
+
+ if (thisphase == in_datain) {
+ dregs->cnt = hmuch;
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ } else {
+ esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+ dregs->cnt = hmuch;
+ }
dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr));
- dregs->cond_reg = tmp;
+ dregs->cond_reg = esp->prev_hme_dmacsr;
} else {
esp_setcount(eregs, hmuch, 0);
dma_setup(dregs, esp->dma->revision,
@@ -2338,9 +2470,9 @@
}
/* See how successful the data transfer was. */
-static inline int esp_do_data_finale(struct Sparc_ESP *esp,
- struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_data_finale(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
Scsi_Cmnd *SCptr = esp->current_SC;
int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
@@ -2361,7 +2493,7 @@
}
dma_drain(dregs, esp->dma->revision);
}
- dma_invalidate(dregs, esp->dma->revision);
+ dma_invalidate(esp, dregs, esp->dma->revision);
/* This could happen for the above parity error case. */
if(!(esp->ireg == ESP_INTR_BSERV)) {
@@ -2387,26 +2519,43 @@
ecount = esp_getcount(eregs);
bytes_sent = esp->current_transfer_size;
- /* Uhhh, might not want both of these conditionals to run
- * at once on HME due to the fifo problems it has. Consider
- * changing it to:
- *
- * if(!(esp->sreg & ESP_STAT_TCNT)) {
- * bytes_sent -= ecount;
- * } else if(SCptr->SCp.phase == in_dataout) {
- * bytes_sent -= fifocnt;
- * }
- *
- * But only for the HME case, leave the current code alone
- * for all other ESP revisions as we know the existing code
- * works just fine for them.
- */
ESPDATA(("trans_sz=%d, ", bytes_sent));
if(esp->erev == fashme) {
if(!(esp->sreg & ESP_STAT_TCNT)) {
- bytes_sent -= esp_getcount(eregs);
- } else if(SCptr->SCp.phase == in_dataout) {
+ ecount = esp_getcount(eregs);
+ bytes_sent -= ecount;
+ }
+
+ /* Always subtract any cruft remaining in the FIFO. */
+ if(esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
+ fifocnt <<= 1;
+ if(SCptr->SCp.phase == in_dataout)
bytes_sent -= fifocnt;
+
+ /* I have an IBM disk which exhibits the following
+ * behavior during writes to it. It disconnects in
+ * the middle of a partial transfer, the current sglist
+ * buffer is 1024 bytes, the disk stops data transfer
+ * at 512 bytes.
+ *
+ * However the FAS366 reports that 32 more bytes were
+ * transferred than really were. This is precisely
+ * the size of a fully loaded FIFO in wide scsi mode.
+ * The FIFO state recorded indicates that it is empty.
+ *
+ * I have no idea if this is a bug in the FAS366 chip
+ * or a bug in the firmware on this IBM disk. In any
+ * event the following seems to be a good workaround. -DaveM
+ */
+ if (bytes_sent != esp->current_transfer_size &&
+ SCptr->SCp.phase == in_dataout) {
+ int mask = (64 - 1);
+
+ if((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0)
+ mask >>= 1;
+
+ if (bytes_sent & mask)
+ bytes_sent -= (bytes_sent & mask);
}
} else {
if(!(esp->sreg & ESP_STAT_TCNT))
@@ -2442,6 +2591,8 @@
* driver. No idea why it happened, but allowing
* this value to be negative caused things to
* lock up. This allows greater chance of recovery.
+ * In fact every time I've seen this, it has been
+ * a driver bug without question.
*/
ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
@@ -2462,7 +2613,7 @@
SCptr->SCp.this_residual -= bytes_sent;
if(SCptr->SCp.this_residual < 0) {
/* shit */
- printk("esp%d: Data transfer overrun.\n", esp->esp_id);
+ ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
SCptr->SCp.this_residual = 0;
}
@@ -2493,11 +2644,49 @@
return do_intr_end;
}
+/* We received a non-good status return at the end of
+ * running a SCSI command. This is used to decide if
+ * we should clear our synchronous transfer state for
+ * such a device when that happens.
+ *
+ * The idea is that when spinning up a disk or rewinding
+ * a tape, we don't want to go into a loop re-negotiating
+ * synchronous capabilities over and over.
+ */
+static int esp_should_clear_sync(Scsi_Cmnd *sp)
+{
+ unchar cmd1 = sp->cmnd[0];
+ unchar cmd2 = sp->data_cmnd[0];
+
+ /* These cases are for spinning up a disk and
+ * waiting for that spinup to complete.
+ */
+ if(cmd1 == START_STOP ||
+ cmd2 == START_STOP)
+ return 0;
+
+ if(cmd1 == TEST_UNIT_READY ||
+ cmd2 == TEST_UNIT_READY)
+ return 0;
+
+ /* One more special case for SCSI tape drives,
+ * this is what is used to probe the device for
+ * completion of a rewind or tape load operation.
+ */
+ if(sp->device->type == TYPE_TAPE) {
+ if(cmd1 == MODE_SENSE ||
+ cmd2 == MODE_SENSE)
+ return 0;
+ }
+
+ return 1;
+}
+
/* Either a command is completing or a target is dropping off the bus
* to continue the command in the background so we can do other work.
*/
-static inline int esp_do_freebus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_freebus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
Scsi_Cmnd *SCptr = esp->current_SC;
int rval;
@@ -2516,9 +2705,11 @@
if(esp->disconnected_SC || (esp->erev == fashme))
esp_cmd(esp, eregs, ESP_CMD_ESEL);
- if(SCptr->SCp.Status != GOOD && SCptr->SCp.Status != CONDITION_GOOD &&
+ if(SCptr->SCp.Status != GOOD &&
+ SCptr->SCp.Status != CONDITION_GOOD &&
((1<<SCptr->target) & esp->targets_present) &&
- SCptr->device->sync && SCptr->device->sync_max_offset) {
+ SCptr->device->sync &&
+ SCptr->device->sync_max_offset) {
/* SCSI standard says that the synchronous capabilities
* should be renegotiated at this point. Most likely
* we are about to request sense from this target
@@ -2535,15 +2726,7 @@
* can report not ready many times right after
* loading up a tape.
*/
- if(SCptr->cmnd[0] != START_STOP &&
- SCptr->data_cmnd[0] != START_STOP &&
- SCptr->cmnd[0] != TEST_UNIT_READY &&
- SCptr->data_cmnd[0] != TEST_UNIT_READY &&
- !(SCptr->device->type == TYPE_TAPE &&
- (SCptr->cmnd[0] == TEST_UNIT_READY ||
- SCptr->data_cmnd[0] == TEST_UNIT_READY ||
- SCptr->cmnd[0] == MODE_SENSE ||
- SCptr->data_cmnd[0] == MODE_SENSE)))
+ if(esp_should_clear_sync(SCptr) != 0)
SCptr->device->sync = 0;
}
ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
@@ -2570,9 +2753,43 @@
return do_intr_end;
}
+/* When a reselect occurs, and we cannot find the command to
+ * reconnect to in our queues, we do this.
+ */
+static int esp_bad_reconnect(struct Sparc_ESP *esp)
+{
+ Scsi_Cmnd *sp;
+
+ ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+ esp->esp_id));
+ ESPLOG(("QUEUE DUMP\n"));
+ sp = esp->issue_SC;
+ ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ sp = esp->current_SC;
+ ESPLOG(("esp%d: current_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ sp = esp->disconnected_SC;
+ ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+ while(sp) {
+ ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+ sp = (Scsi_Cmnd *) sp->host_scribble;
+ }
+ ESPLOG(("]\n"));
+ return do_reset_bus;
+}
+
/* Do the needy when a target tries to reconnect to us. */
-static inline int esp_do_reconnect(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_reconnect(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
int lun, target;
Scsi_Cmnd *SCptr;
@@ -2592,12 +2809,8 @@
/* Things look ok... */
ESPDISC(("R<%02x,%02x>", target, lun));
- /* Must flush both FIFO and the DVMA on HME. */
- if(esp->erev == fashme) {
- /* XXX this still doesn't fix the problem... */
- esp_cmd(esp, eregs, ESP_CMD_FLUSH);
- dma_invalidate(esp->dregs, dvmahme);
- } else {
+ /* Must not flush FIFO or DVMA on HME. */
+ if(esp->erev != fashme) {
esp_cmd(esp, eregs, ESP_CMD_FLUSH);
if(esp100_reconnect_hwbug(esp, eregs))
return do_reset_bus;
@@ -2605,39 +2818,19 @@
}
SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun);
- if(!SCptr) {
- Scsi_Cmnd *sp;
+ if(!SCptr)
+ return esp_bad_reconnect(esp);
- ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
- esp->esp_id));
- ESPLOG(("QUEUE DUMP\n"));
- sp = esp->issue_SC;
- ESPLOG(("esp%d: issue_SC[", esp->esp_id));
- while(sp) {
- ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
- sp = (Scsi_Cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- sp = esp->current_SC;
- ESPLOG(("esp%d: current_SC[", esp->esp_id));
- while(sp) {
- ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
- sp = (Scsi_Cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- sp = esp->disconnected_SC;
- ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
- while(sp) {
- ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
- sp = (Scsi_Cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- return do_reset_bus;
- }
esp_connect(esp, eregs, SCptr);
esp_cmd(esp, eregs, ESP_CMD_MOK);
- /* No need for explicit restore pointers operation. */
+ if(esp->erev == fashme)
+ eregs->esp_busid = (SCptr->target & 0xf) |
+ (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+
+ /* Reconnect implies a restore pointers operation. */
+ esp_restore_pointers(esp, SCptr);
+
esp->snip = 0;
esp_advance_phase(SCptr, in_the_dark);
return do_intr_end;
@@ -2665,7 +2858,7 @@
esp_cmd(esp, eregs, ESP_CMD_MOK);
if(esp->erev != fashme) {
- dma_flashclear(dregs, esp->dma->revision);
+ dma_flashclear(esp, dregs, esp->dma->revision);
/* Wait till the first bits settle. */
while(esp->esp_command[0] == 0xff)
@@ -2767,112 +2960,135 @@
}
}
-/* The target has control of the bus and we have to see where it has
- * taken us.
- */
-static int esp_do_phase_determine(struct Sparc_ESP *esp,
- struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_enter_status(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
- Scsi_Cmnd *SCptr = esp->current_SC;
+ unchar thecmd = ESP_CMD_ICCSEQ;
- ESPPHASE(("esp_do_phase_determine: "));
- if(!(esp->ireg & ESP_INTR_DC)) {
- switch(esp->sreg & ESP_STAT_PMASK) {
- case ESP_DOP:
- case ESP_DIP:
- ESPPHASE(("to data phase\n"));
- return esp_do_data(esp, eregs, dregs);
+ esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+ if(esp->erev != fashme) {
+ esp->esp_command[0] = esp->esp_command[1] = 0xff;
+ eregs->esp_tclow = 2;
+ eregs->esp_tcmed = 0;
+ dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
+ if(esp->dma->revision == dvmaesc1)
+ dregs->cnt = 0x100;
+ dregs->st_addr = esp->esp_command_dvma;
+ thecmd |= ESP_CMD_DMA;
+ }
+ esp_cmd(esp, eregs, thecmd);
+ esp_advance_phase(esp->current_SC, in_status);
- case ESP_STATP:
- /* Whee, status phase, finish up the command. */
- ESPPHASE(("to status phase\n"));
- esp_cmd(esp, eregs, ESP_CMD_FLUSH);
- if(esp->erev != fashme) {
- esp->esp_command[0] = 0xff;
- esp->esp_command[1] = 0xff;
- eregs->esp_tclow = 2;
- eregs->esp_tcmed = 0;
- dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
- if(esp->dma->revision == dvmaesc1)
- dregs->cnt = 0x1000;
- dregs->st_addr = esp->esp_command_dvma;
- esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
- } else {
- /* Using DVMA for status/message bytes is
- * unreliable on HME, nice job QLogic.
- * Happy Meal indeed....
- */
- esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
- }
- esp_advance_phase(SCptr, in_status);
- return esp_do_status(esp, eregs, dregs);
+ return esp_do_status(esp, eregs, dregs);
+}
- case ESP_MOP:
- ESPPHASE(("to msgout phase\n"));
- esp_advance_phase(SCptr, in_msgout);
- return esp_do_msgout(esp, eregs, dregs);
-
- case ESP_MIP:
- ESPPHASE(("to msgin phase\n"));
- esp_advance_phase(SCptr, in_msgin);
- return esp_do_msgin(esp, eregs, dregs);
-
- case ESP_CMDP:
- /* Ugh, we're running a non-standard command the
- * ESP doesn't understand, one byte at a time.
- */
- ESPPHASE(("to cmd phase\n"));
- esp_advance_phase(SCptr, in_cmdbegin);
- return esp_do_cmdbegin(esp, eregs, dregs);
- };
- } else {
- Scsi_Device *dp = SCptr->device;
+static int esp_disconnect_amidst_phases(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ Scsi_Cmnd *sp = esp->current_SC;
+ Scsi_Device *dp = sp->device;
- /* This means real problems if we see this
- * here. Unless we were actually trying
- * to force the device to abort/reset.
- */
- ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
- ESPLOG(("pphase<%s> cphase<%s>, ",
- phase_string(SCptr->SCp.phase),
- phase_string(SCptr->SCp.sent_command)));
- if(esp->disconnected_SC || (esp->erev == fashme))
- esp_cmd(esp, eregs, ESP_CMD_ESEL);
+ /* This means real problems if we see this
+ * here. Unless we were actually trying
+ * to force the device to abort/reset.
+ */
+ ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
+ ESPLOG(("pphase<%s> cphase<%s>, ",
+ phase_string(sp->SCp.phase),
+ phase_string(sp->SCp.sent_command)));
- switch(esp->cur_msgout[0]) {
- default:
- /* We didn't expect this to happen at all. */
- ESPLOG(("device is bolixed\n"));
- esp_advance_phase(SCptr, in_tgterror);
- esp_done(esp, (DID_ERROR << 16));
- break;
+ if(esp->disconnected_SC || (esp->erev == fashme))
+ esp_cmd(esp, eregs, ESP_CMD_ESEL);
- case BUS_DEVICE_RESET:
- ESPLOG(("device reset successful\n"));
- dp->sync_max_offset = 0;
- dp->sync_min_period = 0;
- dp->sync = 0;
- esp_advance_phase(SCptr, in_resetdev);
- esp_done(esp, (DID_RESET << 16));
- break;
+ switch(esp->cur_msgout[0]) {
+ default:
+ /* We didn't expect this to happen at all. */
+ ESPLOG(("device is bolixed\n"));
+ esp_advance_phase(sp, in_tgterror);
+ esp_done(esp, (DID_ERROR << 16));
+ break;
- case ABORT:
- ESPLOG(("device abort successful\n"));
- esp_advance_phase(SCptr, in_abortone);
- esp_done(esp, (DID_ABORT << 16));
- break;
+ case BUS_DEVICE_RESET:
+ ESPLOG(("device reset successful\n"));
+ dp->sync_max_offset = 0;
+ dp->sync_min_period = 0;
+ dp->sync = 0;
+ esp_advance_phase(sp, in_resetdev);
+ esp_done(esp, (DID_RESET << 16));
+ break;
- };
- return do_intr_end;
- }
+ case ABORT:
+ ESPLOG(("device abort successful\n"));
+ esp_advance_phase(sp, in_abortone);
+ esp_done(esp, (DID_ABORT << 16));
+ break;
+
+ };
+ return do_intr_end;
+}
+
+static int esp_enter_msgout(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ esp_advance_phase(esp->current_SC, in_msgout);
+ return esp_do_msgout(esp, eregs, dregs);
+}
+
+static int esp_enter_msgin(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ esp_advance_phase(esp->current_SC, in_msgin);
+ return esp_do_msgin(esp, eregs, dregs);
+}
- ESPLOG(("esp%d: to unknown phase\n", esp->esp_id));
- printk("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
- esp->sreg & ESP_STAT_PMASK);
+static int esp_enter_cmd(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ esp_advance_phase(esp->current_SC, in_cmdbegin);
+ return esp_do_cmdbegin(esp, eregs, dregs);
+}
+
+static int esp_enter_badphase(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+ esp->sreg & ESP_STAT_PMASK));
return do_reset_bus;
}
+typedef int (*espfunc_t)(struct Sparc_ESP *,
+ struct Sparc_ESP_regs *,
+ struct sparc_dma_registers *);
+
+static espfunc_t phase_vector[] = {
+ esp_do_data, /* ESP_DOP */
+ esp_do_data, /* ESP_DIP */
+ esp_enter_cmd, /* ESP_CMDP */
+ esp_enter_status, /* ESP_STATP */
+ esp_enter_badphase, /* ESP_STAT_PMSG */
+ esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */
+ esp_enter_msgout, /* ESP_MOP */
+ esp_enter_msgin, /* ESP_MIP */
+};
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ if ((esp->ireg & ESP_INTR_DC) != 0)
+ return esp_disconnect_amidst_phases(esp, eregs, dregs);
+ return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs, dregs);
+}
+
/* First interrupt after exec'ing a cmd comes here. */
static int esp_select_complete(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
struct sparc_dma_registers *dregs)
@@ -2888,7 +3104,7 @@
else
fcnt = (eregs->esp_fflags & ESP_FF_FBYTES);
cmd_bytes_sent = esp_bytes_sent(esp, dregs, fcnt);
- dma_invalidate(dregs, esp->dma->revision);
+ dma_invalidate(esp, dregs, esp->dma->revision);
/* Let's check to see if a reselect happened
* while we we're trying to select. This must
@@ -3061,9 +3277,8 @@
SCptr->SCp.phase == in_slct_stop)) {
/* shit */
esp->snip = 0;
- printk("esp%d: Failed synchronous negotiation for target %d "
- "lun %d\n",
- esp->esp_id, SCptr->target, SCptr->lun);
+ ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
+ "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun));
SDptr->sync_max_offset = 0;
SDptr->sync_min_period = 0;
SDptr->sync = 1; /* so we don't negotiate again */
@@ -3090,8 +3305,8 @@
* But first make sure that is really what is happening.
*/
if(((1<<SCptr->target) & esp->targets_present)) {
- printk("esp%d: Warning, live target %d not responding to "
- "selection.\n", esp->esp_id, SCptr->target);
+ ESPLOG(("esp%d: Warning, live target %d not responding to "
+ "selection.\n", esp->esp_id, SCptr->target));
/* This _CAN_ happen. The SCSI standard states that
* the target is to _not_ respond to selection if
@@ -3154,15 +3369,15 @@
* have miscoded something..... so, try to
* recover as best we can.
*/
- printk("esp%d: message in mis-carriage.\n", esp->esp_id);
+ ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
}
esp_advance_phase(esp->current_SC, in_the_dark);
return do_phase_determine;
}
-static inline int check_singlebyte_msg(struct Sparc_ESP *esp,
- struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int check_singlebyte_msg(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
esp->prevmsgin = esp->cur_msgin[0];
if(esp->cur_msgin[0] & 0x80) {
@@ -3191,8 +3406,20 @@
return 0;
case RESTORE_POINTERS:
+ /* In this case we might also have to backup the
+ * "slow command" pointer. It is rare to get such
+ * a save/restore pointer sequence so early in the
+ * bus transition sequences, but cover it.
+ */
+ if(esp->esp_slowcmd) {
+ esp->esp_scmdleft = esp->current_SC->cmd_len;
+ esp->esp_scmdp = &esp->current_SC->cmnd[0];
+ }
+ esp_restore_pointers(esp, esp->current_SC);
+ return 0;
+
case SAVE_POINTERS:
- /* We handle this all automatically. */
+ esp_save_pointers(esp, esp->current_SC);
return 0;
case COMMAND_COMPLETE:
@@ -3227,9 +3454,9 @@
* the SCSI2 standard specifically recommends against targets doing
* this because so many initiators cannot cope with this occuring.
*/
-static inline int target_with_ants_in_pants(struct Sparc_ESP *esp,
- Scsi_Cmnd *SCptr,
- Scsi_Device *SDptr)
+static int target_with_ants_in_pants(struct Sparc_ESP *esp,
+ Scsi_Cmnd *SCptr,
+ Scsi_Device *SDptr)
{
if(SDptr->sync || SDptr->borken) {
/* sorry, no can do */
@@ -3246,7 +3473,7 @@
return 0;
}
-static inline void sync_report(struct Sparc_ESP *esp)
+static void sync_report(struct Sparc_ESP *esp)
{
int msg3, msg4;
char *type;
@@ -3267,21 +3494,27 @@
} else {
type = "synchronous";
}
- printk(KERN_INFO "esp%d: target %d [period %dns offset %d %d.%02dMHz %s SCSI%s]\n",
- esp->esp_id, esp->current_SC->target,
- (int) msg3 * 4,
- (int) msg4,
- integer, fraction, type,
- (((msg3 * 4) < 200) ? "-II" : ""));
+
+ /* Do not transform this back into one big printk
+ * again, it triggers a bug in our sparc64-gcc272
+ * sibling call optimization. -DaveM
+ */
+ ESPLOG((KERN_INFO "esp%d: target %d ",
+ esp->esp_id, esp->current_SC->target));
+ ESPLOG(("[period %dns offset %d %d.%02dMHz ",
+ (int) msg3 * 4, (int) msg4,
+ integer, fraction));
+ ESPLOG(("%s SCSI%s]\n", type,
+ (((msg3 * 4) < 200) ? "-II" : "")));
} else {
- printk(KERN_INFO "esp%d: target %d asynchronous\n",
- esp->esp_id, esp->current_SC->target);
+ ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
+ esp->esp_id, esp->current_SC->target));
}
}
-static inline int check_multibyte_msg(struct Sparc_ESP *esp,
- struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int check_multibyte_msg(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
Scsi_Cmnd *SCptr = esp->current_SC;
Scsi_Device *SDptr = SCptr->device;
@@ -3358,10 +3591,10 @@
esp->config3[SCptr->target] |= bit;
else
esp->config3[SCptr->target] &= ~bit;
- eregs->esp_cfg3 = esp->config3[SCptr->target];
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target];
}
- eregs->esp_soff = SDptr->sync_min_period;
- eregs->esp_stp = SDptr->sync_max_offset;
+ eregs->esp_soff = esp->prev_soff = SDptr->sync_min_period;
+ eregs->esp_stp = esp->prev_stp = SDptr->sync_max_offset;
ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
SDptr->sync_max_offset,
@@ -3376,15 +3609,15 @@
ESPSDTR(("unaccaptable sync nego, forcing async\n"));
SDptr->sync_max_offset = 0;
SDptr->sync_min_period = 0;
- eregs->esp_soff = 0;
- eregs->esp_stp = 0;
+ eregs->esp_soff = esp->prev_soff = 0;
+ eregs->esp_stp = esp->prev_stp = 0;
if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
if((esp->erev == fas100a) || (esp->erev == fashme))
bit = ESP_CONFIG3_FAST;
else
bit = ESP_CONFIG3_FSCSI;
esp->config3[SCptr->target] &= ~bit;
- eregs->esp_cfg3 = esp->config3[SCptr->target];
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target];
}
}
@@ -3409,32 +3642,30 @@
esp->wnip = 0;
if(esp->erev != fashme) {
- printk("esp%d: AIEEE wide msg received and not HME.\n",
- esp->esp_id);
+ ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n",
+ esp->esp_id));
message_out = MESSAGE_REJECT;
} else if(size > 16) {
- printk("esp%d: AIEEE wide transfer for %d size not supported.\n",
- esp->esp_id, size);
+ ESPLOG(("esp%d: AIEEE wide transfer for %d size "
+ "not supported.\n", esp->esp_id, size));
message_out = MESSAGE_REJECT;
} else {
/* Things look good; let's see what we got. */
if(size == 16) {
/* Set config 3 register for this target. */
- printk("esp%d: 16 byte WIDE transfers enabled for target %d.\n",
- esp->esp_id, SCptr->target);
esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
} else {
/* Just make sure it was one byte sized. */
if(size != 8) {
- printk("esp%d: Aieee, wide nego of %d size.\n",
- esp->esp_id, size);
+ ESPLOG(("esp%d: Aieee, wide nego of %d size.\n",
+ esp->esp_id, size));
message_out = MESSAGE_REJECT;
goto finish;
}
/* Pure paranoia. */
esp->config3[SCptr->target] &= ~(ESP_CONFIG3_EWIDE);
}
- eregs->esp_cfg3 = esp->config3[SCptr->target];
+ eregs->esp_cfg3 = esp->prev_cfg3 = esp->config3[SCptr->target];
/* Regardless, next try for sync transfers. */
build_sync_nego_msg(esp, esp->sync_defp, 15);
@@ -3566,11 +3797,11 @@
return do_intr_end;
}
-static inline int esp_do_cmddone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_cmddone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
if(esp->erev == fashme)
- dma_invalidate(dregs, dvmahme);
+ dma_invalidate(esp, dregs, dvmahme);
else
esp_cmd(esp, eregs, ESP_CMD_NULL);
if(esp->ireg & ESP_INTR_BSERV) {
@@ -3583,7 +3814,7 @@
}
static int esp_do_msgout(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+ struct sparc_dma_registers *dregs)
{
esp_cmd(esp, eregs, ESP_CMD_FLUSH);
switch(esp->msgout_len) {
@@ -3661,8 +3892,8 @@
return do_intr_end;
}
-static inline int esp_do_msgoutdone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_do_msgoutdone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
if(esp->msgout_len > 1) {
/* XXX HME/FAS ATN deassert workaround required,
@@ -3673,7 +3904,7 @@
while(dregs->cond_reg & DMA_PEND_READ)
udelay(1);
dregs->cond_reg &= ~(DMA_ENABLE);
- dma_invalidate(dregs, esp->dma->revision);
+ dma_invalidate(esp, dregs, esp->dma->revision);
} else {
esp_cmd(esp, eregs, ESP_CMD_FLUSH);
}
@@ -3722,81 +3953,65 @@
return esp_do_phase_determine(esp, eregs, dregs);
}
+static int esp_bus_unexpected(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
+{
+ ESPLOG(("esp%d: command in weird state %2x\n",
+ esp->esp_id, esp->current_SC->SCp.phase));
+ return do_reset_bus;
+}
+
+static espfunc_t bus_vector[] = {
+ esp_do_data_finale,
+ esp_do_data_finale,
+ esp_bus_unexpected,
+ esp_do_msgin,
+ esp_do_msgincont,
+ esp_do_msgindone,
+ esp_do_msgout,
+ esp_do_msgoutdone,
+ esp_do_cmdbegin,
+ esp_do_cmddone,
+ esp_do_status,
+ esp_do_freebus,
+ esp_do_phase_determine,
+ esp_bus_unexpected,
+ esp_bus_unexpected,
+ esp_bus_unexpected,
+};
+
/* This is the second tier in our dual-level SCSI state machine. */
-static inline int esp_work_bus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
- struct sparc_dma_registers *dregs)
+static int esp_work_bus(struct Sparc_ESP *esp,
+ struct Sparc_ESP_regs *eregs,
+ struct sparc_dma_registers *dregs)
{
Scsi_Cmnd *SCptr = esp->current_SC;
+ unsigned int phase;
ESPBUS(("esp_work_bus: "));
if(!SCptr) {
ESPBUS(("reconnect\n"));
return esp_do_reconnect(esp, eregs, dregs);
}
-
- switch(SCptr->SCp.phase) {
- case in_the_dark:
- ESPBUS(("in the dark\n"));
- return esp_do_phase_determine(esp, eregs, dregs);
-
- case in_slct_norm:
- case in_slct_stop:
- case in_slct_msg:
- case in_slct_tag:
- case in_slct_sneg:
- ESPBUS(("finish selection\n"));
+ phase = SCptr->SCp.phase;
+ if ((phase & 0xf0) == in_phases_mask)
+ return bus_vector[(phase & 0x0f)](esp, eregs, dregs);
+ else if((phase & 0xf0) == in_slct_mask)
return esp_select_complete(esp, eregs, dregs);
-
- case in_datain:
- case in_dataout:
- ESPBUS(("finish data\n"));
- return esp_do_data_finale(esp, eregs, dregs);
-
- case in_msgout:
- ESPBUS(("message out "));
- return esp_do_msgout(esp, eregs, dregs);
-
- case in_msgoutdone:
- ESPBUS(("finish message out "));
- return esp_do_msgoutdone(esp, eregs, dregs);
-
- case in_msgin:
- ESPBUS(("message in "));
- return esp_do_msgin(esp, eregs, dregs);
-
- case in_msgincont:
- ESPBUS(("continue message in "));
- return esp_do_msgincont(esp, eregs, dregs);
-
- case in_msgindone:
- ESPBUS(("finish message in "));
- return esp_do_msgindone(esp, eregs, dregs);
-
- case in_status:
- ESPBUS(("status phase "));
- return esp_do_status(esp, eregs, dregs);
-
- case in_freeing:
- ESPBUS(("freeing the bus "));
- return esp_do_freebus(esp, eregs, dregs);
-
- case in_cmdbegin:
- ESPBUS(("begin slow cmd "));
- return esp_do_cmdbegin(esp, eregs, dregs);
-
- case in_cmdend:
- ESPBUS(("end slow cmd "));
- return esp_do_cmddone(esp, eregs, dregs);
-
- default:
- printk("esp%d: command in weird state %2x\n",
- esp->esp_id, esp->current_SC->SCp.phase);
- return do_reset_bus;
- };
+ else
+ return esp_bus_unexpected(esp, eregs, dregs);
}
+static espfunc_t isvc_vector[] = {
+ 0,
+ esp_do_phase_determine,
+ esp_do_resetbus,
+ esp_finish_reset,
+ esp_work_bus
+};
+
/* Main interrupt handler for an esp adapter. */
-static inline void esp_handle(struct Sparc_ESP *esp)
+static void esp_handle(struct Sparc_ESP *esp)
{
struct sparc_dma_registers *dregs;
struct Sparc_ESP_regs *eregs;
@@ -3841,7 +4056,7 @@
ESPLOG(("esp%d: No current cmd during gross error, "
"resetting bus\n", esp->esp_id));
what_next = do_reset_bus;
- goto again;
+ goto state_machine;
}
}
@@ -3862,9 +4077,11 @@
esp_reset_dma(esp);
what_next = do_reset_bus;
- goto again;
+ goto state_machine;
}
+ esp->ireg = eregs->esp_intrpt; /* Unlatch intr and stat regs */
+
if(esp->erev == fashme) {
/* This chip is really losing. */
ESPHME(("HME["));
@@ -3877,17 +4094,12 @@
if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
(esp->sreg2 & ESP_STAT2_F1BYTE)) {
ESPHME(("fifo_workaround]"));
- hme_fifo_hwbug_workaround(esp, eregs);
+ hme_fifo_read(esp, eregs);
} else {
ESPHME(("no_fifo_workaround]"));
}
}
- esp->ireg = eregs->esp_intrpt; /* Unlatch intr and stat regs */
-
- /* This cannot be done until this very moment. -DaveM */
- synchronize_irq();
-
/* No current cmd is only valid at this point when there are
* commands off the bus or we are trying a reset.
*/
@@ -3926,10 +4138,7 @@
}
what_next = do_reset_bus;
- goto again;
- }
-
- if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+ } else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
int phase;
if(SCptr) {
@@ -3941,13 +4150,12 @@
} else {
ESPLOG(("esp%d: interrupt for no good reason...\n",
esp->esp_id));
- goto esp_handle_done;
+ what_next = do_intr_end;
}
} else {
ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
esp->esp_id));
what_next = do_reset_bus;
- goto again;
}
} else if(esp->ireg & ESP_INTR_SR) {
ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
@@ -3956,7 +4164,6 @@
ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
esp->esp_id));
what_next = do_reset_bus;
- goto again;
} else if(esp->ireg & ESP_INTR_RSEL) {
if(!SCptr) {
/* This is ok. */
@@ -3971,95 +4178,22 @@
ESPLOG(("esp%d: Reselected while bus is busy\n",
esp->esp_id));
what_next = do_reset_bus;
- goto again;
}
}
- /* We're trying to fight stack problems, and inline as much as
- * possible without making this driver a mess. hate hate hate
- * This is tier-one in our dual level SCSI state machine.
- */
-again:
- switch(what_next) {
- case do_intr_end:
- goto esp_handle_done;
-
- case do_work_bus:
- what_next = esp_work_bus(esp, eregs, dregs);
- break;
-
- case do_phase_determine:
- what_next = esp_do_phase_determine(esp, eregs, dregs);
- break;
-
- case do_reset_bus:
- ESPLOG(("esp%d: resetting bus...\n", esp->esp_id));
- esp->resetting_bus = 1;
- esp_cmd(esp, eregs, ESP_CMD_RS);
- goto esp_handle_done;
-
- case do_reset_complete:
- /* Tricky, we don't want to cause any more commands to
- * go out until we clear all the live cmds by hand.
- */
- if(esp->current_SC) {
- Scsi_Cmnd *SCptr = esp->current_SC;
- if(!SCptr->use_sg)
- mmu_release_scsi_one(SCptr->SCp.have_data_in,
- SCptr->request_bufflen,
- esp->edev->my_bus);
- else
- mmu_release_scsi_sgl((struct mmu_sglist *)
- SCptr->buffer,
- SCptr->use_sg - 1,
- esp->edev->my_bus);
- SCptr->result = (DID_RESET << 16);
-
- SCptr->scsi_done(SCptr);
- }
- esp->current_SC = NULL;
- if(esp->disconnected_SC) {
- Scsi_Cmnd *SCptr;
- while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
- if(!SCptr->use_sg)
- mmu_release_scsi_one(SCptr->SCp.have_data_in,
- SCptr->request_bufflen,
- esp->edev->my_bus);
- else
- mmu_release_scsi_sgl((struct mmu_sglist *)
- SCptr->buffer,
- SCptr->use_sg - 1,
- esp->edev->my_bus);
- SCptr->result = (DID_RESET << 16);
-
- SCptr->scsi_done(SCptr);
- }
- }
- esp->resetting_bus = 0;
-
- if(esp->current_SC) {
- printk("esp%d: weird weird weird, current_SC not NULL after "
- "SCSI bus reset.\n", esp->esp_id);
- goto esp_handle_done;
+ /* This is tier-one in our dual level SCSI state machine. */
+state_machine:
+ while(what_next != do_intr_end) {
+ if (what_next >= do_phase_determine &&
+ what_next < do_intr_end)
+ what_next = isvc_vector[what_next](esp, eregs, dregs);
+ else {
+ /* state is completely lost ;-( */
+ ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+ esp->esp_id));
+ what_next = do_reset_bus;
}
-
- /* Now it is safe to execute more things. */
- if(esp->issue_SC)
- esp_exec_cmd(esp);
- goto esp_handle_done;
-
- default:
- /* state is completely lost ;-( */
- ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
- esp->esp_id));
- what_next = do_reset_bus;
- break;
-
- };
- goto again;
-
-esp_handle_done:
- return;
+ }
}
#ifndef __sparc_v9__
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)