patch-2.0.28 linux/drivers/scsi/u14-34f.c
Next file: linux/drivers/scsi/u14-34f.h
Previous file: linux/drivers/scsi/scsi_ioctl.c
Back to the patch index
Back to the overall index
- Lines: 445
- Date:
Tue Jan 14 12:47:28 1997
- Orig file:
v2.0.27/linux/drivers/scsi/u14-34f.c
- Orig date:
Mon Dec 30 16:01:47 1996
diff -u --recursive --new-file v2.0.27/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
@@ -1,7 +1,13 @@
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
- * 21 Nov 1996 rev. 2.30 for linux 2.1.11 and 2.0.25
+ * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27
+ * Added linked command support.
+ *
+ * 3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27
+ * Added queue depth adjustment.
+ *
+ * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
* The list of i/o ports to be probed can be overwritten by the
* "u14-34f=port0, port1,...." boot command line option.
* Scatter/gather lists are now allocated by a number of kmalloc
@@ -78,7 +84,7 @@
*
* Multiple U14F and/or U34F host adapters are supported.
*
- * Copyright (C) 1994, 1995, 1996 Dario Ballabio (dario@milano.europe.dg.com)
+ * Copyright (C) 1994-1997 Dario Ballabio (dario@milano.europe.dg.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that redistributions of source
@@ -112,8 +118,8 @@
*
* Here a sample configuration using two U14F boards:
*
- U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, Mbox 16, CmdLun 2, C1.
- U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, Mbox 16, CmdLun 2, C1.
+ U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, UC 1, LC 1, MQ 8.
+ U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, UC 1, LC 1, MQ 8.
*
* The boot controller must have its BIOS enabled, while other boards can
* have their BIOS disabled, or enabled to an higher address.
@@ -194,6 +200,7 @@
#include <asm/irq.h>
#include "u14-34f.h"
#include<linux/stat.h>
+#include<linux/config.h>
struct proc_dir_entry proc_scsi_u14_34f = {
PROC_SCSI_U14_34F, 6, "u14_34f",
@@ -220,6 +227,7 @@
#define HA_CMD_READ_BUFF 0x3
#define HA_CMD_WRITE_BUFF 0x4
+#undef DEBUG_LINKED_COMMANDS
#undef DEBUG_DETECT
#undef DEBUG_INTERRUPT
#undef DEBUG_STATISTICS
@@ -239,6 +247,7 @@
#define MAX_SAFE_SGLIST 16
#define MAX_INTERNAL_RETRIES 64
#define MAX_CMD_PER_LUN 2
+#define MAX_TAGGED_CMD_PER_LUN 8
#define FALSE 0
#define TRUE 1
@@ -247,6 +256,8 @@
#define LOCKED 2
#define IN_RESET 3
#define IGNORE 4
+#define READY 5
+#define ABORTING 6
#define NO_DMA 0xff
#define MAXLOOP 200000
@@ -291,8 +302,8 @@
unsigned char lun: 3; /* SCSI logical unit number */
unsigned int data_address PACKED; /* transfer data pointer */
unsigned int data_len PACKED; /* length in bytes */
- unsigned int command_link PACKED; /* for linking command chains */
- unsigned char scsi_command_link_id; /* identifies command in chain */
+ unsigned int link_address PACKED; /* for linking command chains */
+ unsigned char clink_id; /* identifies command in chain */
unsigned char use_sg; /* (if sg is set) 8 bytes per list */
unsigned char sense_len;
unsigned char scsi_cdbs_len; /* 6, 10, or 12 */
@@ -302,6 +313,7 @@
unsigned int sense_addr PACKED;
Scsi_Cmnd *SCpnt;
unsigned int index; /* cp index */
+ unsigned int link_id; /* reference cp for linked commands */
struct sg_list *sglist;
};
@@ -341,12 +353,14 @@
#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
#define BN(board) (HD(board)->board_name)
-#if defined(__BIG_ENDIAN)
-#define H2DEV(x) ((unsigned long)( \
+#define SWAP_BYTE(x) ((unsigned long)( \
(((unsigned long)(x) & 0x000000ffU) << 24) | \
(((unsigned long)(x) & 0x0000ff00U) << 8) | \
(((unsigned long)(x) & 0x00ff0000U) >> 8) | \
(((unsigned long)(x) & 0xff000000U) >> 24)))
+
+#if defined(__BIG_ENDIAN)
+#define H2DEV(x) SWAP_BYTE(x)
#else
#define H2DEV(x) (x)
#endif
@@ -359,6 +373,64 @@
static int do_trace = FALSE;
static int setup_done = FALSE;
+#if defined (CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
+static int linked_commands = TRUE;
+#else
+static int linked_commands = FALSE;
+#endif
+
+#if defined CONFIG_SCSI_U14_34F_MAX_TAGS
+static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;
+#else
+static int max_queue_depth = MAX_CMD_PER_LUN;
+#endif
+
+static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
+ Scsi_Device *dev;
+ int j, ntag = 0, nuntag = 0, tqd, utqd;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ j = ((struct hostdata *) host->hostdata)->board_number;
+
+ for(dev = devlist; dev; dev = dev->next) {
+
+ if (dev->host != host) continue;
+
+ if (dev->tagged_supported) ntag++;
+ else nuntag++;
+ }
+
+ utqd = MAX_CMD_PER_LUN;
+
+ tqd = (host->can_queue - utqd * nuntag) / (ntag + 1);
+
+ if (tqd > max_queue_depth) tqd = max_queue_depth;
+
+ if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN;
+
+ for(dev = devlist; dev; dev = dev->next) {
+ char *tag_suffix = "";
+
+ if (dev->host != host) continue;
+
+ if (dev->tagged_supported) dev->queue_depth = tqd;
+ else dev->queue_depth = utqd;
+
+ if (dev->tagged_supported && dev->tagged_queue) tag_suffix = ", tagged";
+ else if (dev->tagged_supported) tag_suffix = ", untagged";
+
+ printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n",
+ BN(j), host->host_no, dev->channel, dev->id, dev->lun,
+ dev->queue_depth, tag_suffix);
+ }
+
+ restore_flags(flags);
+ return;
+}
+
static inline int wait_on_busy(unsigned int iobase) {
unsigned int loop = MAXLOOP;
@@ -415,6 +487,7 @@
Scsi_Host_Template *tpnt) {
unsigned char irq, dma_channel, subversion, i;
unsigned char in_byte;
+ char *bus_type, dma_name[16];
/* Allowed BIOS base addresses (NULL indicates reserved) */
void *bios_segment_table[8] = {
@@ -508,6 +581,7 @@
sh[j]->this_id = config_2.ha_scsi_id;
sh[j]->can_queue = MAX_MAILBOXES;
sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
+ sh[j]->select_queue_depths = select_queue_depths;
#if defined(DEBUG_DETECT)
{
@@ -541,6 +615,7 @@
sh[j]->dma_channel = NO_DMA;
sh[j]->unchecked_isa_dma = FALSE;
sprintf(BN(j), "U34F%d", j);
+ bus_type = "VESA";
}
else {
sh[j]->wish_block = TRUE;
@@ -557,6 +632,7 @@
clear_dma_ff(dma_channel);
set_dma_mode(dma_channel, DMA_MODE_CASCADE);
enable_dma(dma_channel);
+ bus_type = "ISA";
}
sh[j]->max_channel = MAX_CHANNEL - 1;
@@ -575,6 +651,9 @@
}
}
+ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "NO DMA");
+ else sprintf(dma_name, "DMA %u", dma_channel);
+
for (i = 0; i < sh[j]->can_queue; i++)
if (! ((&HD(j)->cp[i])->sglist = kmalloc(
sh[j]->sg_tablesize * sizeof(struct sg_list),
@@ -584,11 +663,15 @@
return FALSE;
}
- printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
- "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port,
- (int)sh[j]->base, sh[j]->irq, sh[j]->dma_channel,
- sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun,
- sh[j]->hostt->use_clustering);
+ if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
+ max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
+
+ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
+
+ printk("%s: %s 0x%03x, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d, UC %d, "\
+ "LC %d, MQ %d.\n", BN(j), bus_type, sh[j]->io_port, (int)sh[j]->base,
+ sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue,
+ sh[j]->hostt->use_clustering, linked_commands, max_queue_depth);
if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
@@ -635,7 +718,7 @@
if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
if (j > 0)
- printk("UltraStor 14F/34F: Copyright (C) 1994, 1995, 1996 Dario Ballabio.\n");
+ printk("UltraStor 14F/34F: Copyright (C) 1994-1997 Dario Ballabio.\n");
restore_flags(flags);
return j;
@@ -747,6 +830,28 @@
cpp->scsi_cdbs_len = SCpnt->cmd_len;
memcpy(cpp->scsi_cdbs, SCpnt->cmnd, cpp->scsi_cdbs_len);
+ if (linked_commands && SCpnt->device->tagged_supported
+ && !HD(j)->target_to[SCpnt->target][SCpnt->channel]
+ && !HD(j)->target_redo[SCpnt->target][SCpnt->channel])
+
+ for (k = 0; k < sh[j]->can_queue; k++) {
+
+ if (HD(j)->cp_stat[k] != IN_USE) continue;
+
+ if ((&HD(j)->cp[k])->SCpnt->device != SCpnt->device) continue;
+
+ cpp->link_id = k;
+ HD(j)->cp_stat[i] = READY;
+
+#if defined (DEBUG_LINKED_COMMANDS)
+ printk("%s: qcomm, target %d.%d:%d, pid %ld, Mbox %d ready.\n",
+ BN(j), SCpnt->channel, SCpnt->target, SCpnt->lun,
+ SCpnt->pid, i);
+#endif
+ restore_flags(flags);
+ return 0;
+ }
+
if (wait_on_busy(sh[j]->io_port)) {
SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
@@ -828,6 +933,18 @@
restore_flags(flags);
return SCSI_ABORT_NOT_RUNNING;
}
+
+ if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+ SCarg->result = DID_ABORT << 16;
+ SCarg->host_scribble = NULL;
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+ BN(j), i, SCarg->pid);
+ SCarg->scsi_done(SCarg);
+ restore_flags(flags);
+ return SCSI_ABORT_SUCCESS;
+ }
+
restore_flags(flags);
panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
}
@@ -878,14 +995,21 @@
continue;
}
- SCpnt = HD(j)->cp[i].SCpnt;
- HD(j)->cp_stat[i] = IN_RESET;
- printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
-
- if (SCpnt == NULL)
+ if (!(SCpnt = HD(j)->cp[i].SCpnt))
panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+ HD(j)->cp_stat[i] = ABORTING;
+ printk("%s: reset, mbox %d aborting, pid %ld.\n",
+ BN(j), i, SCpnt->pid);
+ }
+
+ else {
+ HD(j)->cp_stat[i] = IN_RESET;
+ printk("%s: reset, mbox %d in reset, pid %ld.\n",
+ BN(j), i, SCpnt->pid);
+ }
+
if (SCpnt->host_scribble == NULL)
panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
@@ -920,18 +1044,35 @@
for (i = 0; i < sh[j]->can_queue; i++) {
- /* Skip mailboxes already set free by interrupt */
- if (HD(j)->cp_stat[i] != IN_RESET) continue;
+ if (HD(j)->cp_stat[i] == IN_RESET) {
+ SCpnt = HD(j)->cp[i].SCpnt;
+ SCpnt->result = DID_RESET << 16;
+ SCpnt->host_scribble = NULL;
- SCpnt = HD(j)->cp[i].SCpnt;
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
+ /* This mailbox is still waiting for its interrupt */
+ HD(j)->cp_stat[i] = LOCKED;
- /* This mailbox is still waiting for its interrupt */
- HD(j)->cp_stat[i] = LOCKED;
+ printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+ BN(j), i, SCpnt->pid);
+ }
+
+ else if (HD(j)->cp_stat[i] == ABORTING) {
+ SCpnt = HD(j)->cp[i].SCpnt;
+ SCpnt->result = DID_RESET << 16;
+ SCpnt->host_scribble = NULL;
+
+ /* This mailbox was never queued to the adapter */
+ HD(j)->cp_stat[i] = FREE;
+
+ printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+ BN(j), i, SCpnt->pid);
+ }
+
+ else
+
+ /* Any other mailbox has already been set free by interrupt */
+ continue;
- printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
restore_flags(flags);
SCpnt->scsi_done(SCpnt);
cli();
@@ -961,11 +1102,49 @@
return FALSE;
}
+static inline void process_ready_list(unsigned int i, unsigned int j) {
+ Scsi_Cmnd *SCpnt;
+ unsigned int k, n_ready = 0;
+ struct mscp *cpp;
+
+ for (k = 0; k < sh[j]->can_queue; k++) {
+
+ if (HD(j)->cp_stat[k] != READY) continue;
+
+ cpp = &HD(j)->cp[k];
+
+ if (cpp->link_id != i) continue;
+
+ SCpnt = cpp->SCpnt;
+ n_ready++;
+
+ if (wait_on_busy(sh[j]->io_port)) {
+ printk("%s: ihdlr, target %d.%d:%d, pid %ld, Mbox %d, link_id %d, "\
+ "n_ready %d, adapter busy, will abort.\n", BN(j),
+ SCpnt->channel, SCpnt->target, SCpnt->lun, SCpnt->pid,
+ k, i, n_ready);
+ HD(j)->cp_stat[k] = ABORTING;
+ continue;
+ }
+
+ outl(V2DEV(cpp), sh[j]->io_port + REG_OGM);
+ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
+ HD(j)->cp_stat[k] = IN_USE;
+
+#if defined (DEBUG_LINKED_COMMANDS)
+ printk("%s: ihdlr, target %d.%d:%d, pid %ld, Mbox %d in use, link_id %d,"
+ " n_ready %d.\n", BN(j), SCpnt->channel, SCpnt->target,
+ SCpnt->lun, SCpnt->pid, k, i, n_ready);
+#endif
+ }
+
+}
+
static void u14_34f_interrupt_handler(int irq, void *dev_id,
struct pt_regs *regs) {
Scsi_Cmnd *SCpnt;
unsigned long flags;
- unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0;
+ unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0, ret;
struct mscp *spp;
save_flags(flags);
@@ -995,15 +1174,19 @@
if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
BN(j), HD(j)->iocount);
- spp = (struct mscp *)DEV2V(inl(sh[j]->io_port + REG_ICM));
+ spp = (struct mscp *)DEV2V(ret = inl(sh[j]->io_port + REG_ICM));
/* Clear interrupt pending flag */
outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
i = spp - HD(j)->cp;
- if (i >= sh[j]->can_queue)
- panic("%s: ihdlr, invalid mscp address.\n", BN(j));
+ if (spp < HD(j)->cp || spp >= HD(j)->cp + sh[j]->can_queue
+ || i >= sh[j]->can_queue)
+ panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n",
+ BN(j), (void *)ret, HD(j)->cp);
+
+ if (linked_commands) process_ready_list(i, j);
if (HD(j)->cp_stat[i] == IGNORE) {
HD(j)->cp_stat[i] = FREE;
@@ -1135,7 +1318,7 @@
if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
(spp->adapter_status != ASOK &&
spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
- do_trace)
+ do_trace || msg_byte(spp->target_status))
#endif
printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
" target %d.%d:%d, pid %ld, count %d.\n",
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov