Commit cd9be7d7 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Christoph Hellwig

[PATCH] remove eata_dma driver

Last changelog entry is from 1996 and it had no changes ecept global
search and replace since start of the bitkeeper history.

The alternate driver eata is maintained and the Kconfig file contains
a stong advice on using it.
parent e23a6bdf
......@@ -471,10 +471,6 @@ config SCSI_EATA
SCSI-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>.
Note that there is also another driver for the same hardware
available: "EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti,
Alphatronix) support". You should say Y to only one of them.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
......@@ -512,24 +508,6 @@ config SCSI_EATA_MAX_TAGS
by the driver for each probed SCSI device is reported at boot time.
This is equivalent to the "eata=mq:8" boot option.
config SCSI_EATA_DMA
tristate "EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support"
depends on SCSI
---help---
This is support for the EATA-DMA protocol compliant SCSI Host
Adapters like the SmartCache III/IV, SmartRAID controller families
and the DPT PM2011B and PM2012B controllers.
Note that this driver is obsolete; if you have one of the above
SCSI Host Adapters, you should normally say N here and Y to "EATA
ISA/EISA/PCI support", below. Please read the SCSI-HOWTO, available
from <http://www.linuxdoc.org/docs.html#howto>.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called eata_dma. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
config SCSI_EATA_PIO
tristate "EATA-PIO (old DPT PM2001, PM2012A) support"
depends on SCSI
......
......@@ -82,7 +82,6 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/
obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
obj-$(CONFIG_SCSI_NCR53C8XX) += ncr53c8xx.o
obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
obj-$(CONFIG_SCSI_EATA_DMA) += eata_dma.o
obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o
obj-$(CONFIG_SCSI_7000FASST) += wd7000.o
obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o
......
/************************************************************
* *
* Linux EATA SCSI driver *
* *
* based on the CAM document CAM/89-004 rev. 2.0c, *
* DPT's driver kit, some internal documents and source, *
* and several other Linux scsi drivers and kernel docs. *
* *
* The driver currently: *
* -supports all ISA based EATA-DMA boards *
* like PM2011, PM2021, PM2041, PM3021 *
* -supports all EISA based EATA-DMA boards *
* like PM2012B, PM2022, PM2122, PM2322, PM2042, *
* PM3122, PM3222, PM3332 *
* -supports all PCI based EATA-DMA boards *
* like PM2024, PM2124, PM2044, PM2144, PM3224, *
* PM3334 *
* -supports the Wide, Ultra Wide and Differential *
* versions of the boards *
* -supports multiple HBAs with & without IRQ sharing *
* -supports all SCSI channels on multi channel boards *
* -supports ix86 and MIPS, untested on ALPHA *
* -needs identical IDs on all channels of a HBA *
* -can be loaded as module *
* -displays statistical and hardware information *
* in /proc/scsi/eata_dma *
* -provides rudimentary latency measurement *
* possibilities via /proc/scsi/eata_dma/<hostnum> *
* *
* (c)1993-96 Michael Neuffer *
* mike@i-Connect.Net *
* neuffer@mail.uni-mainz.de *
* *
* This program is free software; you can redistribute it *
* and/or modify it under the terms of the GNU General *
* Public License as published by the Free Software *
* Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be *
* useful, but WITHOUT ANY WARRANTY; without even the *
* implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License *
* for more details. *
* *
* You should have received a copy of the GNU General *
* Public License along with this kernel; if not, write to *
* the Free Software Foundation, Inc., 675 Mass Ave, *
* Cambridge, MA 02139, USA. *
* *
* I have to thank DPT for their excellent support. I took *
* me almost a year and a stopover at their HQ, on my first *
* trip to the USA, to get it, but since then they've been *
* very helpful and tried to give me all the infos and *
* support I need. *
* *
* Thanks also to Simon Shapiro, Greg Hosler and Mike *
* Jagdis who did a lot of testing and found quite a number *
* of bugs during the development. *
************************************************************
* last change: 96/10/21 OS: Linux 2.0.23 *
************************************************************/
/* Look in eata_dma.h for configuration and revision information */
#error Please convert me to Documentation/DMA-mapping.txt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/in.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/types.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
#ifdef __mips__
#include <asm/cachectl.h>
#include <linux/spinlock.h>
#endif
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
#include "eata_dma.h"
#include "eata_dma_proc.h"
#include <linux/stat.h>
#include <linux/config.h> /* for CONFIG_PCI */
static u32 ISAbases[] =
{0x1F0, 0x170, 0x330, 0x230};
static unchar EISAbases[] =
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
static uint registered_HBAs = 0;
static struct Scsi_Host *last_HBA = NULL;
static struct Scsi_Host *first_HBA = NULL;
static unchar reg_IRQ[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static unchar reg_IRQL[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static struct eata_sp *status = 0; /* Statuspacket array */
static void *dma_scratch = 0;
static struct eata_register *fake_int_base;
static int fake_int_result;
static int fake_int_happened;
static ulong int_counter = 0;
static ulong queue_counter = 0;
void eata_fake_int_handler(s32 irq, void *dev_id, struct pt_regs * regs)
{
fake_int_result = inb((ulong)fake_int_base + HA_RSTATUS);
fake_int_happened = TRUE;
DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%d base %p"
" res %#x\n", irq, fake_int_base, fake_int_result));
return;
}
#include "eata_dma_proc.c"
#ifdef MODULE
int eata_release(struct Scsi_Host *sh)
{
uint i;
if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq, NULL);
else reg_IRQ[sh->irq]--;
kfree((void *)status);
kfree((void *)dma_scratch - 4);
for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */
if(SD(sh)->ccb[i].sg_list != NULL)
kfree((void *) SD(sh)->ccb[i].sg_list);
}
if (SD(sh)->channel == 0) {
if (sh->dma_channel != BUSMASTER) free_dma(sh->dma_channel);
if (sh->io_port && sh->n_io_port)
release_region(sh->io_port, sh->n_io_port);
}
return(TRUE);
}
#endif
inline void eata_latency_in(struct eata_ccb *cp, hostdata *hd)
{
uint time;
time = jiffies - cp->timestamp;
if(hd->all_lat[1] > time)
hd->all_lat[1] = time;
if(hd->all_lat[2] < time)
hd->all_lat[2] = time;
hd->all_lat[3] += time;
hd->all_lat[0]++;
if((cp->rw_latency) == WRITE) { /* was WRITE */
if(hd->writes_lat[cp->sizeindex][1] > time)
hd->writes_lat[cp->sizeindex][1] = time;
if(hd->writes_lat[cp->sizeindex][2] < time)
hd->writes_lat[cp->sizeindex][2] = time;
hd->writes_lat[cp->sizeindex][3] += time;
hd->writes_lat[cp->sizeindex][0]++;
} else if((cp->rw_latency) == READ) {
if(hd->reads_lat[cp->sizeindex][1] > time)
hd->reads_lat[cp->sizeindex][1] = time;
if(hd->reads_lat[cp->sizeindex][2] < time)
hd->reads_lat[cp->sizeindex][2] = time;
hd->reads_lat[cp->sizeindex][3] += time;
hd->reads_lat[cp->sizeindex][0]++;
}
}
inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd)
{
int x, z;
short *sho;
long *lon;
x = 0; /* just to keep GCC quiet */
cp->timestamp = jiffies; /* For latency measurements */
switch(cmd->cmnd[0]) {
case WRITE_6:
x = cmd->cmnd[4]/2;
cp->rw_latency = WRITE;
break;
case READ_6:
x = cmd->cmnd[4]/2;
cp->rw_latency = READ;
break;
case WRITE_10:
sho = (short *) &cmd->cmnd[7];
x = ntohs(*sho)/2;
cp->rw_latency = WRITE;
break;
case READ_10:
sho = (short *) &cmd->cmnd[7];
x = ntohs(*sho)/2;
cp->rw_latency = READ;
break;
case WRITE_12:
lon = (long *) &cmd->cmnd[6];
x = ntohl(*lon)/2;
cp->rw_latency = WRITE;
break;
case READ_12:
lon = (long *) &cmd->cmnd[6];
x = ntohl(*lon)/2;
cp->rw_latency = READ;
break;
default:
cp->rw_latency = OTHER;
break;
}
if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 ||
cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 ||
cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) {
for(z = 0; (x > (1 << z)) && (z <= 11); z++)
/* nothing */;
cp->sizeindex = z;
}
}
void eata_int_handler(int, void *, struct pt_regs *);
void do_eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
eata_int_handler(irq, dev_id, regs);
spin_unlock_irqrestore(dev->host_lock, flags);
}
void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
{
uint i, result = 0;
uint hba_stat, scsi_stat, eata_stat;
Scsi_Cmnd *cmd;
struct eata_ccb *ccb;
struct eata_sp *sp;
uint base;
uint x;
struct Scsi_Host *sh;
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if (sh->irq != irq)
continue;
while(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
int_counter++;
sp = &SD(sh)->sp;
#ifdef __mips__
sys_cacheflush(sp, sizeof(struct eata_sp), 2);
#endif
ccb = sp->ccb;
if(ccb == NULL) {
eata_stat = inb((uint)sh->base + HA_RSTATUS);
printk("eata_dma: int_handler, Spurious IRQ %d "
"received. CCB pointer not set.\n", irq);
break;
}
cmd = ccb->cmd;
base = (uint) cmd->device->host->base;
hba_stat = sp->hba_stat;
scsi_stat = (sp->scsi_stat >> 1) & 0x1f;
if (sp->EOC == FALSE) {
eata_stat = inb(base + HA_RSTATUS);
printk(KERN_WARNING "eata_dma: int_handler, board: %x cmd %lx "
"returned unfinished.\n"
"EATA: %x HBA: %x SCSI: %x spadr %lx spadrirq %lx, "
"irq%d\n", base, (long)ccb, eata_stat, hba_stat,
scsi_stat,(long)&status, (long)&status[irq], irq);
cmd->result = DID_ERROR << 16;
ccb->status = FREE;
cmd->scsi_done(cmd);
break;
}
sp->EOC = FALSE; /* Clean out this flag */
if (ccb->status == LOCKED || ccb->status == RESET) {
printk("eata_dma: int_handler, reseted command pid %ld returned"
"\n", cmd->pid);
DBG(DBG_INTR && DBG_DELAY, DELAY(1));
}
eata_stat = inb(base + HA_RSTATUS);
DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, "
"target: %x, lun: %x, ea_s: %#.2x, hba_s: "
"%#.2x \n", irq, base, cmd->pid, cmd->device->id,
cmd->device->lun, eata_stat, hba_stat));
switch (hba_stat) {
case HA_NO_ERROR: /* NO Error */
if(HD(cmd)->do_latency == TRUE && ccb->timestamp)
eata_latency_in(ccb, HD(cmd));
result = DID_OK << 16;
break;
case HA_ERR_SEL_TO: /* Selection Timeout */
case HA_ERR_CMD_TO: /* Command Timeout */
result = DID_TIME_OUT << 16;
break;
case HA_BUS_RESET: /* SCSI Bus Reset Received */
result = DID_RESET << 16;
DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: BUS RESET "
"received on cmd %ld\n",
HD(cmd)->HBA_number, cmd->pid));
break;
case HA_INIT_POWERUP: /* Initial Controller Power-up */
if (cmd->device->type != TYPE_TAPE)
result = DID_BUS_BUSY << 16;
else
result = DID_ERROR << 16;
for (i = 0; i < MAXTARGET; i++)
DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld "
"returned with INIT_POWERUP\n",
HD(cmd)->HBA_number, cmd->pid));
break;
case HA_CP_ABORT_NA:
case HA_CP_ABORTED:
result = DID_ABORT << 16;
DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: aborted cmd "
"returned\n", HD(cmd)->HBA_number));
break;
case HA_CP_RESET_NA:
case HA_CP_RESET:
HD(cmd)->resetlevel[cmd->device->channel] = 0;
result = DID_RESET << 16;
DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd "
"pid %ldreturned\n",
HD(cmd)->HBA_number, cmd->pid));
case HA_SCSI_HUNG: /* SCSI Hung */
printk(KERN_ERR "scsi%d: SCSI hung\n", HD(cmd)->HBA_number);
result = DID_ERROR << 16;
break;
case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */
DBG(DBG_STATUS, printk(KERN_ERR "scsi%d: Auto Request Sense "
"Failed\n", HD(cmd)->HBA_number));
result = DID_ERROR << 16;
break;
case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */
case HA_UNX_BUS_FREE: /* Unexpected Bus Free */
case HA_BUS_PARITY: /* Bus Parity Error */
case HA_UNX_MSGRJCT: /* Unexpected Message Reject */
case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */
case HA_PARITY_ERR: /* Controller Ram Parity */
default:
result = DID_ERROR << 16;
break;
}
cmd->result = result | (scsi_stat << 1);
#if DBG_INTR2
if (scsi_stat || result || hba_stat || eata_stat != 0x50
|| cmd->scsi_done == NULL || cmd->device->id == 7)
printk("HBA: %d, channel %d, id: %d, lun %d, pid %ld:\n"
"eata_stat %#x, hba_stat %#.2x, scsi_stat %#.2x, "
"sense_key: %#x, result: %#.8x\n", x,
cmd->device->channel, cmd->device->id, cmd->device->lun,
cmd->pid, eata_stat, hba_stat, scsi_stat,
cmd->sense_buffer[2] & 0xf, cmd->result);
DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
#endif
ccb->status = FREE; /* now we can release the slot */
cmd->scsi_done(cmd);
}
}
return;
}
inline int eata_send_command(u32 addr, u32 base, u8 command)
{
long loop = R_LIMIT;
while (inb(base + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0)
return(FALSE);
if(addr != (u32) NULL)
addr = virt_to_bus((void *)addr);
/*
* This is overkill.....but the MIPSen seem to need this
* and it will be optimized away for i86 and ALPHA machines.
*/
flush_cache_all();
/* And now the address in nice little byte chunks */
#ifdef __LITTLE_ENDIAN
outb(addr, base + HA_WDMAADDR);
outb(addr >> 8, base + HA_WDMAADDR + 1);
outb(addr >> 16, base + HA_WDMAADDR + 2);
outb(addr >> 24, base + HA_WDMAADDR + 3);
#else
outb(addr >> 24, base + HA_WDMAADDR);
outb(addr >> 16, base + HA_WDMAADDR + 1);
outb(addr >> 8, base + HA_WDMAADDR + 2);
outb(addr, base + HA_WDMAADDR + 3);
#endif
outb(command, base + HA_WCOMMAND);
return(TRUE);
}
inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2)
{
if(addr != (u32) NULL)
addr = virt_to_bus((void *)addr);
/*
* This is overkill.....but the MIPSen seem to need this
* and it will be optimized away for i86 and ALPHA machines.
*/
flush_cache_all();
outb(0x0, base + HA_WDMAADDR - 1);
if(addr){
#ifdef __LITTLE_ENDIAN
outb(addr, base + HA_WDMAADDR);
outb(addr >> 8, base + HA_WDMAADDR + 1);
outb(addr >> 16, base + HA_WDMAADDR + 2);
outb(addr >> 24, base + HA_WDMAADDR + 3);
#else
outb(addr >> 24, base + HA_WDMAADDR);
outb(addr >> 16, base + HA_WDMAADDR + 1);
outb(addr >> 8, base + HA_WDMAADDR + 2);
outb(addr, base + HA_WDMAADDR + 3);
#endif
} else {
outb(0x0, base + HA_WDMAADDR);
outb(0x0, base + HA_WDMAADDR + 1);
outb(code2, base + HA_WCODE2);
outb(code, base + HA_WCODE);
}
outb(ifc, base + HA_WIFC);
outb(EATA_CMD_IMMEDIATE, base + HA_WCOMMAND);
return(TRUE);
}
int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
{
unsigned int i, x, y;
ulong flags;
hostdata *hd;
struct Scsi_Host *sh;
struct eata_ccb *ccb;
struct scatterlist *sl;
save_flags(flags);
cli();
#if 0
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
printk("eata_dma: scsi%d interrupt pending in eata_queue.\n"
" Calling interrupt handler.\n", sh->host_no);
eata_int_handler(sh->irq, 0, 0);
}
}
#endif
queue_counter++;
hd = HD(cmd);
sh = cmd->device->host;
if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
cmd->result = DID_OK << 16;
done(cmd);
restore_flags(flags);
return(0);
}
/* check for free slot */
for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
if (y >= sh->can_queue)
y = 0;
if (hd->ccb[y].status == FREE)
break;
}
hd->last_ccb = y;
if (x >= sh->can_queue) {
cmd->result = DID_BUS_BUSY << 16;
DBG(DBG_QUEUE && DBG_ABNORM,
printk(KERN_CRIT "eata_queue pid %ld, HBA QUEUE FULL..., "
"returning DID_BUS_BUSY\n", cmd->pid));
done(cmd);
restore_flags(flags);
return(0);
}
ccb = &hd->ccb[y];
memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
ccb->status = USED; /* claim free slot */
restore_flags(flags);
DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
cmd->pid, cmd->device->id, cmd->device->lun, y));
DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
if(hd->do_latency == TRUE)
eata_latency_out(ccb, cmd);
cmd->scsi_done = (void *)done;
switch (cmd->cmnd[0]) {
case CHANGE_DEFINITION: case COMPARE: case COPY:
case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT:
case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER:
case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
case WRITE_6: case WRITE_10: case WRITE_VERIFY:
case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME:
case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12:
case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW:
case MEDIUM_SCAN: case SEND_VOLUME_TAG:
case 0xea: /* alternate number for WRITE LONG */
ccb->DataOut = TRUE; /* Output mode */
break;
case TEST_UNIT_READY:
default:
ccb->DataIn = TRUE; /* Input mode */
}
/* FIXME: This will will have to be changed once the midlevel driver
* allows different HBA IDs on every channel.
*/
if (cmd->device->id == sh->this_id)
ccb->Interpret = TRUE; /* Interpret command */
if (cmd->use_sg) {
ccb->scatter = TRUE; /* SG mode */
if (ccb->sg_list == NULL) {
ccb->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),
GFP_ATOMIC | GFP_DMA);
}
if (ccb->sg_list == NULL)
{
/*
* Claim the bus was busy. Actually we are the problem but this
* will do a deferred retry for us ;)
*/
printk(KERN_ERR "eata_dma: Run out of DMA memory for SG lists !\n");
cmd->result = DID_BUS_BUSY << 16;
ccb->status = FREE;
done(cmd);
return(0);
}
ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list));
ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
sl=(struct scatterlist *)cmd->request_buffer;
for(i = 0; i < cmd->use_sg; i++, sl++){
ccb->sg_list[i].data = htonl(virt_to_bus(sl->address));
ccb->sg_list[i].len = htonl((u32) sl->length);
}
} else {
ccb->scatter = FALSE;
ccb->cp_datalen = htonl(cmd->request_bufflen);
ccb->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));
}
ccb->Auto_Req_Sen = TRUE;
ccb->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));
ccb->reqlen = sizeof(cmd->sense_buffer);
ccb->cp_id = cmd->device->id;
ccb->cp_channel = cmd->device->channel;
ccb->cp_lun = cmd->device->lun;
ccb->cp_dispri = TRUE;
ccb->cp_identify = TRUE;
memcpy(ccb->cp_cdb, cmd->cmnd, cmd->cmd_len);
ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to
* convert it */
ccb->cmd = cmd;
cmd->host_scribble = (char *)&hd->ccb[y];
if(eata_send_command((u32) ccb, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
cmd->result = DID_BUS_BUSY << 16;
DBG(DBG_QUEUE && DBG_ABNORM,
printk("eata_queue target %d, pid %ld, HBA busy, "
"returning DID_BUS_BUSY\n",cmd->device->id, cmd->pid));
ccb->status = FREE;
done(cmd);
return(0);
}
DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "
"slot %d irq %d\n", (s32)sh->base, cmd->pid,
cmd->device->id, cmd->device->lun, y, sh->irq));
DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
return(0);
}
int eata_abort(Scsi_Cmnd * cmd)
{
ulong loop = HZ / 2;
ulong flags;
int x;
struct Scsi_Host *sh;
save_flags(flags);
cli();
DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x"
" reason %x\n", cmd->pid, cmd->device->id, cmd->device->lun,
cmd->abort_reason));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
/* Some interrupt controllers seem to loose interrupts */
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
printk("eata_dma: scsi%d interrupt pending in eata_abort.\n"
" Calling interrupt handler.\n", sh->host_no);
eata_int_handler(sh->irq, 0, 0);
}
}
while (inb((u32)(cmd->device->host->base) + HA_RAUXSTAT) & HA_ABUSY) {
if (--loop == 0) {
printk("eata_dma: abort, timeout error.\n");
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
restore_flags(flags);
return (SCSI_ABORT_ERROR);
}
}
if (CD(cmd)->status == RESET) {
printk("eata_dma: abort, command reset error.\n");
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
restore_flags(flags);
return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == LOCKED) {
DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
restore_flags(flags);
return (SCSI_ABORT_NOT_RUNNING);
}
if (CD(cmd)->status == USED) {
DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
restore_flags(flags);
return (SCSI_ABORT_BUSY); /* SNOOZE */
}
if (CD(cmd)->status == FREE) {
DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n"));
restore_flags(flags);
return (SCSI_ABORT_NOT_RUNNING);
}
restore_flags(flags);
panic("eata_dma: abort: invalid slot status\n");
}
int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags)
{
uint x;
/* 10 million PCI reads take at least one third of a second */
ulong loop = 10 * 1000 * 1000;
ulong flags;
unchar success = FALSE;
Scsi_Cmnd *sp;
struct Scsi_Host *sh;
save_flags(flags);
cli();
DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x"
" reason %x\n", cmd->pid, cmd->device->id, cmd->device->lun,
cmd->abort_reason));
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) {
printk("eata_dma: scsi%d interrupt pending in eata_reset.\n"
" Calling interrupt handler.\n", sh->host_no);
eata_int_handler(sh->irq, 0, 0);
}
}
if (HD(cmd)->state == RESET) {
printk("eata_reset: exit, already in reset.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_ERROR);
}
while (inb((u32)(cmd->device->host->base) + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
printk("eata_reset: exit, timeout error.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_ERROR);
}
for (x = 0; x < cmd->device->host->can_queue; x++) {
if (HD(cmd)->ccb[x].status == FREE)
continue;
if (HD(cmd)->ccb[x].status == LOCKED) {
HD(cmd)->ccb[x].status = FREE;
printk("eata_reset: locked slot %d forced free.\n", x);
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
continue;
}
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
if (sp == NULL)
panic("eata_reset: slot %d, sp==NULL.\n", x);
printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
if (sp == cmd)
success = TRUE;
}
/* hard reset the HBA */
inb((u32) (cmd->device->host->base) + HA_RSTATUS); /* This might cause trouble */
eata_send_command(0, (u32) cmd->device->host->base, EATA_CMD_RESET);
HD(cmd)->state = RESET;
DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling "
"interrupts.\n"));
DELAY(2); /* In theorie we should get interrupts and set free all
* used queueslots */
DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled again.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
for (x = 0; x < cmd->device->host->can_queue; x++) {
/* Skip slots already set free by interrupt and those that
* are still LOCKED from the last reset */
if (HD(cmd)->ccb[x].status != RESET)
continue;
sp = HD(cmd)->ccb[x].cmd;
sp->result = DID_RESET << 16;
/* This mailbox is still waiting for its interrupt */
HD(cmd)->ccb[x].status = LOCKED;
printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",
x, sp->pid);
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
sp->scsi_done(sp);
}
HD(cmd)->state = FALSE;
restore_flags(flags);
if (success) {
DBG(DBG_ABNORM, printk("eata_reset: exit, pending.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_PENDING);
} else {
DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_PUNT);
}
}
/* Here we try to determine the optimum queue depth for
* each attached device.
*
* At the moment the algorithm is rather simple
*/
static void eata_select_queue_depths(struct Scsi_Host *host,
Scsi_Device *devicelist)
{
Scsi_Device *device;
int devcount = 0;
int factor = 0;
#if CRIPPLE_QUEUE
for(device = devicelist; device != NULL; device = device->next) {
if(device->host == host)
device->queue_depth = 2;
}
#else
/* First we do a sample run go find out what we have */
for(device = devicelist; device != NULL; device = device->next) {
if (device->host == host) {
devcount++;
switch(device->type) {
case TYPE_DISK:
case TYPE_MOD:
factor += TYPE_DISK_QUEUE;
break;
case TYPE_TAPE:
factor += TYPE_TAPE_QUEUE;
break;
case TYPE_WORM:
case TYPE_ROM:
factor += TYPE_ROM_QUEUE;
break;
case TYPE_PROCESSOR:
case TYPE_SCANNER:
default:
factor += TYPE_OTHER_QUEUE;
break;
}
}
}
DBG(DBG_REGISTER, printk(KERN_DEBUG "scsi%d: needed queueslots %d\n",
host->host_no, factor));
if(factor == 0) /* We don't want to get a DIV BY ZERO error */
factor = 1;
factor = (SD(host)->queuesize * 10) / factor;
DBG(DBG_REGISTER, printk(KERN_DEBUG "scsi%d: using factor %dE-1\n",
host->host_no, factor));
/* Now that have the factor we can set the individual queuesizes */
for(device = devicelist; device != NULL; device = device->next) {
if(device->host == host) {
if(SD(device->host)->bustype != IS_ISA){
switch(device->type) {
case TYPE_DISK:
case TYPE_MOD:
device->queue_depth = (TYPE_DISK_QUEUE * factor) / 10;
break;
case TYPE_TAPE:
device->queue_depth = (TYPE_TAPE_QUEUE * factor) / 10;
break;
case TYPE_WORM:
case TYPE_ROM:
device->queue_depth = (TYPE_ROM_QUEUE * factor) / 10;
break;
case TYPE_PROCESSOR:
case TYPE_SCANNER:
default:
device->queue_depth = (TYPE_OTHER_QUEUE * factor) / 10;
break;
}
} else /* ISA forces us to limit the queue depth because of the
* bounce buffer memory overhead. I know this is cruel */
device->queue_depth = 2;
/*
* It showed that we need to set an upper limit of commands
* we can allow to queue for a single device on the bus.
* If we get above that limit, the broken midlevel SCSI code
* will produce bogus timeouts and aborts en masse. :-(
*/
if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT)
device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT;
if(device->queue_depth == 0)
device->queue_depth = 1;
printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
"set to %d\n", host->host_no, device->id, device->channel,
device->queue_depth);
}
}
#endif
}
#if CHECK_BLINK
int check_blink_state(long base)
{
ushort loops = 10;
u32 blinkindicator;
u32 state = 0x12345678;
u32 oldstate = 0;
blinkindicator = htonl(0x54504442);
while ((loops--) && (state != oldstate)) {
oldstate = state;
state = inl((uint) base + 1);
}
DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
(state == oldstate) && (state == blinkindicator)));
if ((state == oldstate) && (state == blinkindicator))
return(TRUE);
else
return (FALSE);
}
#endif
char * get_board_data(u32 base, u32 irq, u32 id)
{
struct eata_ccb *cp;
struct eata_sp *sp;
static char *buff;
ulong i;
cp = (struct eata_ccb *) kmalloc(sizeof(struct eata_ccb),
GFP_ATOMIC | GFP_DMA);
if(cp==NULL)
return NULL;
sp = (struct eata_sp *) kmalloc(sizeof(struct eata_sp),
GFP_ATOMIC | GFP_DMA);
if(sp==NULL)
{
kfree(cp);
return NULL;
}
buff = dma_scratch;
memset(cp, 0, sizeof(struct eata_ccb));
memset(sp, 0, sizeof(struct eata_sp));
memset(buff, 0, 256);
cp->DataIn = TRUE;
cp->Interpret = TRUE; /* Interpret command */
cp->cp_dispri = TRUE;
cp->cp_identify = TRUE;
cp->cp_datalen = htonl(56);
cp->cp_dataDMA = htonl(virt_to_bus(buff));
cp->cp_statDMA = htonl(virt_to_bus(sp));
cp->cp_viraddr = cp;
cp->cp_id = id;
cp->cp_lun = 0;
cp->cp_cdb[0] = INQUIRY;
cp->cp_cdb[1] = 0;
cp->cp_cdb[2] = 0;
cp->cp_cdb[3] = 0;
cp->cp_cdb[4] = 56;
cp->cp_cdb[5] = 0;
fake_int_base = (struct eata_register *) base;
fake_int_result = FALSE;
fake_int_happened = FALSE;
eata_send_command((u32) cp, (u32) base, EATA_CMD_DMA_SEND_CP);
i = jiffies + (3 * HZ);
while (fake_int_happened == FALSE && time_before_eq(jiffies, i))
barrier();
DBG(DBG_INTR3, printk(KERN_DEBUG "fake_int_result: %#x hbastat %#x "
"scsistat %#x, buff %p sp %p\n",
fake_int_result, (u32) (sp->hba_stat /*& 0x7f*/),
(u32) sp->scsi_stat, buff, sp));
kfree((void *)cp);
kfree((void *)sp);
if ((fake_int_result & HA_SERROR) || time_after(jiffies, i)){
printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear "
"possible blink state\n", base);
/* hard reset the HBA */
inb((u32) (base) + HA_RSTATUS);
eata_send_command(0, base, EATA_CMD_RESET);
DELAY(1);
return (NULL);
} else
return (buff);
}
int get_conf_PIO(u32 base, struct get_conf *buf)
{
ulong loop = R_LIMIT;
u16 *p;
if(check_region(base, 9))
return (FALSE);
memset(buf, 0, sizeof(struct get_conf));
while (inb(base + HA_RSTATUS) & HA_SBUSY)
if (--loop == 0)
return (FALSE);
fake_int_base = (struct eata_register *) base;
fake_int_result = FALSE;
fake_int_happened = FALSE;
DBG(DBG_PIO && DBG_PROBE,
printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
eata_send_command(0, base, EATA_CMD_PIO_READ_CONFIG);
loop = R_LIMIT;
for (p = (u16 *) buf;
(long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
if (--loop == 0)
return (FALSE);
loop = R_LIMIT;
*p = inw(base + HA_RDATA);
}
if (!(inb(base + HA_RSTATUS) & HA_SERROR)) { /* Error ? */
if (htonl(EATA_SIGNATURE) == buf->signature) {
DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %x "
"EATA Level: %x\n", (uint) base,
(uint) (buf->version)));
while (inb(base + HA_RSTATUS) & HA_SDRQ)
inw(base + HA_RDATA);
return (TRUE);
}
} else {
DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
"for HBA at %lx\n", (long)base));
}
return (FALSE);
}
void print_config(struct get_conf *gc)
{
printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
(u32) ntohl(gc->len), gc->version,
gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
gc->DMA_support);
printk("DMAV:%d HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d SG_64K:%d SG_UAE:%d MID:%d "
"MCH:%d MLUN:%d\n",
gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR,
gc->SG_64K, gc->SG_UAE, gc->MAX_ID, gc->MAX_CHAN, gc->MAX_LUN);
printk("RIDQ:%d PCI:%d EISA:%d\n",
gc->ID_qest, gc->is_PCI, gc->is_EISA);
DBG(DPT_DEBUG, DELAY(14));
}
short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
u8 bustype)
{
ulong size = 0;
unchar dma_channel = 0;
char *buff = 0;
unchar bugs = 0;
struct Scsi_Host *sh;
hostdata *hd;
int x;
DBG(DBG_REGISTER, print_config(gc));
if (gc->DMA_support == FALSE) {
printk("The EATA HBA at %#.4x does not support DMA.\n"
"Please use the EATA-PIO driver.\n", base);
return (FALSE);
}
if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22)
gc->MAX_CHAN = 0;
if (reg_IRQ[gc->IRQ] == FALSE) { /* Interrupt already registered ? */
if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT,
"eata_dma", NULL)){
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */
} else {
printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
return (FALSE);
}
} else { /* More than one HBA on this IRQ */
if (reg_IRQL[gc->IRQ] == TRUE) {
printk("Can't support more than one HBA on this IRQ,\n"
" if the IRQ is edge triggered. Sorry.\n");
return (FALSE);
} else
reg_IRQ[gc->IRQ]++;
}
/* If DMA is supported but DMA_valid isn't set to indicate that
* the channel number is given we must have pre 2.0 firmware (1.7?)
* which leaves us to guess since the "newer ones" also don't set the
* DMA_valid bit.
*/
if (gc->DMA_support && !gc->DMA_valid && gc->DMA_channel) {
printk(KERN_WARNING "eata_dma: If you are using a pre 2.0 firmware "
"please update it !\n"
" You can get new firmware releases from ftp.dpt.com\n");
gc->DMA_channel = (base == 0x1f0 ? 3 /* DMA=5 */ : 2 /* DMA=6 */);
gc->DMA_valid = TRUE;
}
/* if gc->DMA_valid it must be an ISA HBA and we have to register it */
dma_channel = BUSMASTER;
if (gc->DMA_valid) {
if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
printk(KERN_WARNING "Unable to allocate DMA channel %d for ISA HBA"
" at %#.4x.\n", dma_channel, base);
reg_IRQ[gc->IRQ]--;
if (reg_IRQ[gc->IRQ] == 0)
free_irq(gc->IRQ, NULL);
if (gc->IRQ_TR == FALSE)
reg_IRQL[gc->IRQ] = FALSE;
return (FALSE);
}
}
if (dma_channel != BUSMASTER) {
disable_dma(dma_channel);
clear_dma_ff(dma_channel);
set_dma_mode(dma_channel, DMA_MODE_CASCADE);
enable_dma(dma_channel);
}
if (bustype != IS_EISA && bustype != IS_ISA)
buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
if (buff == NULL) {
if (bustype == IS_EISA || bustype == IS_ISA) {
bugs = bugs || BROKEN_INQUIRY;
} else {
if (gc->DMA_support == FALSE)
printk(KERN_WARNING "HBA at %#.4x doesn't support DMA. "
"Sorry\n", base);
else
printk(KERN_WARNING "HBA at %#.4x does not react on INQUIRY. "
"Sorry.\n", base);
if (gc->DMA_valid)
free_dma(dma_channel);
reg_IRQ[gc->IRQ]--;
if (reg_IRQ[gc->IRQ] == 0)
free_irq(gc->IRQ, NULL);
if (gc->IRQ_TR == FALSE)
reg_IRQL[gc->IRQ] = FALSE;
return (FALSE);
}
}
if (gc->DMA_support == FALSE && buff != NULL)
printk(KERN_WARNING "HBA %.12sat %#.4x doesn't set the DMA_support "
"flag correctly.\n", &buff[16], base);
request_region(base, 9, "eata_dma"); /* We already checked the
* availability, so this
* should not fail.
*/
if(ntohs(gc->queuesiz) == 0) {
gc->queuesiz = ntohs(64);
printk(KERN_WARNING "Warning: Queue size has to be corrected. Assuming"
" 64 queueslots\n"
" This might be a PM2012B with a defective Firmware\n"
" Contact DPT support@dpt.com for an upgrade\n");
}
size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long))
* ntohs(gc->queuesiz));
DBG(DBG_REGISTER, printk("scsi_register size: %ld\n", size));
sh = scsi_register(tpnt, size);
if(sh != NULL) {
hd = SD(sh);
memset(hd->reads, 0, sizeof(u32) * 26);
sh->select_queue_depths = eata_select_queue_depths;
hd->bustype = bustype;
/*
* If we are using a ISA board, we can't use extended SG,
* because we would need excessive amounts of memory for
* bounce buffers.
*/
if (gc->SG_64K==TRUE && ntohs(gc->SGsiz)==64 && hd->bustype!=IS_ISA){
sh->sg_tablesize = SG_SIZE_BIG;
} else {
sh->sg_tablesize = ntohs(gc->SGsiz);
if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
if (sh->sg_tablesize == 0)
printk(KERN_WARNING "Warning: SG size had to be fixed.\n"
"This might be a PM2012 with a defective Firmware"
"\nContact DPT support@dpt.com for an upgrade\n");
sh->sg_tablesize = SG_SIZE;
}
}
hd->sgsize = sh->sg_tablesize;
}
if(sh != NULL) {
sh->can_queue = hd->queuesize = ntohs(gc->queuesiz);
sh->cmd_per_lun = 0;
}
if(sh == NULL) {
DBG(DBG_REGISTER, printk(KERN_NOTICE "eata_dma: couldn't register HBA"
" at%x \n", base));
scsi_unregister(sh);
if (gc->DMA_valid)
free_dma(dma_channel);
reg_IRQ[gc->IRQ]--;
if (reg_IRQ[gc->IRQ] == 0)
free_irq(gc->IRQ, NULL);
if (gc->IRQ_TR == FALSE)
reg_IRQL[gc->IRQ] = FALSE;
return (FALSE);
}
hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY);
if(hd->broken_INQUIRY == TRUE) {
strcpy(hd->vendor, "DPT");
strcpy(hd->name, "??????????");
strcpy(hd->revision, "???.?");
hd->firmware_revision = 0;
} else {
strncpy(hd->vendor, &buff[8], 8);
hd->vendor[8] = 0;
strncpy(hd->name, &buff[16], 17);
hd->name[17] = 0;
hd->revision[0] = buff[32];
hd->revision[1] = buff[33];
hd->revision[2] = buff[34];
hd->revision[3] = '.';
hd->revision[4] = buff[35];
hd->revision[5] = 0;
hd->firmware_revision = (buff[32] << 24) + (buff[33] << 16)
+ (buff[34] << 8) + buff[35];
}
if (hd->firmware_revision >= (('0'<<24) + ('7'<<16) + ('G'<< 8) + '0'))
hd->immediate_support = 1;
else
hd->immediate_support = 0;
switch (ntohl(gc->len)) {
case 0x1c:
hd->EATA_revision = 'a';
break;
case 0x1e:
hd->EATA_revision = 'b';
break;
case 0x22:
hd->EATA_revision = 'c';
break;
case 0x24:
hd->EATA_revision = 'z';
default:
hd->EATA_revision = '?';
}
if(ntohl(gc->len) >= 0x22) {
sh->max_id = gc->MAX_ID + 1;
sh->max_lun = gc->MAX_LUN + 1;
} else {
sh->max_id = 8;
sh->max_lun = 8;
}
hd->HBA_number = sh->host_no;
hd->channel = gc->MAX_CHAN;
sh->max_channel = gc->MAX_CHAN;
sh->unique_id = base;
sh->base = base;
sh->io_port = base;
sh->n_io_port = 9;
sh->irq = gc->IRQ;
sh->dma_channel = dma_channel;
/* FIXME:
* SCSI midlevel code should support different HBA ids on every channel
*/
sh->this_id = gc->scsi_id[3];
if (gc->SECOND)
hd->primary = FALSE;
else
hd->primary = TRUE;
if (hd->bustype != IS_ISA) {
sh->unchecked_isa_dma = FALSE;
} else {
sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */
}
for(x = 0; x <= 11; x++){ /* Initialize min. latency */
hd->writes_lat[x][1] = 0xffffffff;
hd->reads_lat[x][1] = 0xffffffff;
}
hd->all_lat[1] = 0xffffffff;
hd->next = NULL; /* build a linked list of all HBAs */
hd->prev = last_HBA;
if(hd->prev != NULL)
SD(hd->prev)->next = sh;
last_HBA = sh;
if (first_HBA == NULL)
first_HBA = sh;
registered_HBAs++;
return (TRUE);
}
void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
u32 base;
int i;
#if CHECKPAL
u8 pal1, pal2, pal3;
#endif
for (i = 0; i < MAXEISA; i++) {
if (EISAbases[i] == TRUE) { /* Still a possibility ? */
base = 0x1c88 + (i * 0x1000);
#if CHECKPAL
pal1 = inb((u16)base - 8);
pal2 = inb((u16)base - 7);
pal3 = inb((u16)base - 6);
if (((pal1 == DPT_ID1) && (pal2 == DPT_ID2)) ||
((pal1 == NEC_ID1) && (pal2 == NEC_ID2) && (pal3 == NEC_ID3))||
((pal1 == ATT_ID1) && (pal2 == ATT_ID2) && (pal3 == ATT_ID3))){
DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
(int)pal1, (int)pal2, (int)pal3));
#endif
if (get_conf_PIO(base, buf) == TRUE) {
if (buf->IRQ) {
DBG(DBG_EISA, printk("Registering EISA HBA\n"));
register_HBA(base, buf, tpnt, IS_EISA);
} else
printk("eata_dma: No valid IRQ. HBA removed from list\n");
}
#if CHECK_BLINK
else {
if (check_blink_state(base))
printk("HBA is in BLINK state. Consult your HBAs "
"Manual to correct this.\n");
}
#endif
/* Nothing found here so we take it from the list */
EISAbases[i] = 0;
#if CHECKPAL
}
#endif
}
}
return;
}
void find_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
int i;
for (i = 0; i < MAXISA; i++) {
if (ISAbases[i]) {
if (get_conf_PIO(ISAbases[i],buf) == TRUE){
DBG(DBG_ISA, printk("Registering ISA HBA\n"));
register_HBA(ISAbases[i], buf, tpnt, IS_ISA);
}
#if CHECK_BLINK
else {
if (check_blink_state(ISAbases[i]))
printk("HBA is in BLINK state. Consult your HBAs "
"Manual to correct this.\n");
}
#endif
ISAbases[i] = 0;
}
}
return;
}
void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
#ifndef CONFIG_PCI
printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
#else
struct pci_dev *dev = NULL;
u32 base, x;
u8 pal1, pal2, pal3;
while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
DBG(DBG_PROBE && DBG_PCI,
printk("eata_dma: find_PCI, HBA at %s\n", dev->name));
if (pci_enable_device(dev))
continue;
pci_set_master(dev);
base = pci_resource_flags(dev, 0);
if (base & IORESOURCE_MEM) {
printk("eata_dma: invalid base address of device %s\n", dev->name);
continue;
}
base = pci_resource_start(dev, 0);
/* EISA tag there ? */
pal1 = inb(base);
pal2 = inb(base + 1);
pal3 = inb(base + 2);
if (((pal1 == DPT_ID1) && (pal2 == DPT_ID2)) ||
((pal1 == NEC_ID1) && (pal2 == NEC_ID2) &&
(pal3 == NEC_ID3)) ||
((pal1 == ATT_ID1) && (pal2 == ATT_ID2) &&
(pal3 == ATT_ID3)))
base += 0x08;
else
base += 0x10; /* Now, THIS is the real address */
if (base != 0x1f8) {
/* We didn't find it in the primary search */
if (get_conf_PIO(base, buf) == TRUE) {
/* OK. We made it till here, so we can go now
* and register it. We only have to check and
* eventually remove it from the EISA and ISA list
*/
DBG(DBG_PCI, printk("Registering PCI HBA\n"));
register_HBA(base, buf, tpnt, IS_PCI);
if (base < 0x1000) {
for (x = 0; x < MAXISA; ++x) {
if (ISAbases[x] == base) {
ISAbases[x] = 0;
break;
}
}
} else if ((base & 0x0fff) == 0x0c88)
EISAbases[(base >> 12) & 0x0f] = 0;
}
#if CHECK_BLINK
else if (check_blink_state(base) == TRUE) {
printk("eata_dma: HBA is in BLINK state.\n"
"Consult your HBAs manual to correct this.\n");
}
#endif
}
}
#endif /* #ifndef CONFIG_PCI */
}
int eata_detect(Scsi_Host_Template * tpnt)
{
struct Scsi_Host *HBA_ptr;
struct get_conf gc;
int i;
DBG((DBG_PROBE && DBG_DELAY) || DPT_DEBUG,
printk("Using lots of delays to let you read the debugging output\n"));
tpnt->proc_name = "eata_dma";
status = kmalloc(512, GFP_ATOMIC | GFP_DMA);
dma_scratch = kmalloc(1024, GFP_ATOMIC | GFP_DMA);
if(status == NULL || dma_scratch == NULL) {
printk("eata_dma: can't allocate enough memory to probe for hosts !\n");
if(status)
kfree(status);
if(dma_scratch)
kfree(dma_scratch);
return(0);
}
dma_scratch += 4;
find_PCI(&gc, tpnt);
find_EISA(&gc, tpnt);
find_ISA(&gc, tpnt);
for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we */
if (reg_IRQ[i] >= 1){ /* exchange the interrupt handler which */
free_irq(i, NULL); /* we used for probing with the real one */
request_irq(i, (void *)(do_eata_int_handler), SA_INTERRUPT|SA_SHIRQ,
"eata_dma", first_HBA); /* Check it */
}
}
HBA_ptr = first_HBA;
if (registered_HBAs != 0) {
printk("EATA (Extended Attachment) driver version: %d.%d%s"
"\ndeveloped in co-operation with DPT\n"
"(c) 1993-96 Michael Neuffer, mike@i-Connect.Net\n",
VER_MAJOR, VER_MINOR, VER_SUB);
printk("Registered HBAs:");
printk("\nHBA no. Boardtype Revis EATA Bus BaseIO IRQ"
" DMA Ch ID Pr QS S/G IS\n");
for (i = 1; i <= registered_HBAs; i++) {
printk("scsi%-2d: %.12s v%s 2.0%c %s %#.4x %2d",
HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
"PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
(u32) HBA_ptr->base, HBA_ptr->irq);
if(HBA_ptr->dma_channel != BUSMASTER)
printk(" %2x ", HBA_ptr->dma_channel);
else
printk(" %s", "BMST");
printk(" %d %d %c %3d %3d %c\n",
SD(HBA_ptr)->channel+1, HBA_ptr->this_id,
(SD(HBA_ptr)->primary == TRUE)?'Y':'N',
HBA_ptr->can_queue, HBA_ptr->sg_tablesize,
(SD(HBA_ptr)->immediate_support == TRUE)?'Y':'N');
HBA_ptr = SD(HBA_ptr)->next;
}
} else {
kfree((void *)status);
}
kfree((void *)dma_scratch - 4);
DBG(DPT_DEBUG, DELAY(12));
return(registered_HBAs);
}
MODULE_LICENSE("GPL");
/* Eventually this will go into an include file, but this will be later */
static Scsi_Host_Template driver_template = EATA_DMA;
#include "scsi_module.c"
/*
* Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* tab-width: 8
* End:
*/
/********************************************************
* Header file for eata_dma.c Linux EATA-DMA SCSI driver *
* (c) 1993-96 Michael Neuffer *
* mike@i-Connect.Net *
* neuffer@mail.uni-mainz.de *
*********************************************************
* last change: 96/10/14 *
********************************************************/
#ifndef _EATA_DMA_H
#define _EATA_DMA_H
#include "eata_generic.h"
#define VER_MAJOR 2
#define VER_MINOR 5
#define VER_SUB "9b"
/************************************************************************
* Here you can switch parts of the code on and of *
************************************************************************/
#define CHECKPAL 0 /* EISA pal checking on/off */
#define CHECK_BLINK 1 /* Switch Blink state check off, might *
* be nessessary for some MIPS machines*/
#define CRIPPLE_QUEUE 0 /* Only enable this if the interrupt
* controller on your motherboard is
* broken and you are experiencing
* massive interrupt losses */
/************************************************************************
* Debug options. *
* Enable DEBUG and whichever options you require. *
************************************************************************/
#define DEBUG_EATA 1 /* Enable debug code. */
#define DPT_DEBUG 0 /* Bobs special */
#define DBG_DELAY 0 /* Build in delays so debug messages can be
* be read before they vanish of the top of
* the screen! */
#define DBG_PROBE 0 /* Debug probe routines. */
#define DBG_PCI 0 /* Trace PCI routines */
#define DBG_EISA 0 /* Trace EISA routines */
#define DBG_ISA 0 /* Trace ISA routines */
#define DBG_BLINK 0 /* Trace Blink check */
#define DBG_PIO 0 /* Trace get_config_PIO */
#define DBG_COM 0 /* Trace command call */
#define DBG_QUEUE 0 /* Trace command queueing. */
#define DBG_QUEUE2 0 /* Trace command queueing SG. */
#define DBG_INTR 0 /* Trace interrupt service routine. */
#define DBG_INTR2 0 /* Trace interrupt service routine. */
#define DBG_INTR3 0 /* Trace get_board_data interrupts. */
#define DBG_REQSENSE 0 /* Trace request sense commands */
#define DBG_RESET 0 /* Trace reset calls */
#define DBG_STATUS 0 /* Trace status generation */
#define DBG_PROC 0 /* Debug proc-fs related statistics */
#define DBG_PROC_WRITE 0
#define DBG_REGISTER 0 /* */
#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort)*/
#if DEBUG_EATA
#define DBG(x, y) if ((x)) {y;}
#else
#define DBG(x, y)
#endif
int eata_detect(Scsi_Host_Template *);
const char *eata_info(struct Scsi_Host *);
int eata_command(Scsi_Cmnd *);
int eata_queue(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int eata_abort(Scsi_Cmnd *);
int eata_reset(Scsi_Cmnd *, unsigned int);
int eata_proc_info(char *, char **, off_t, int, int, int);
#ifdef MODULE
int eata_release(struct Scsi_Host *);
#else
#define eata_release NULL
#endif
#include <scsi/scsicam.h>
#define EATA_DMA { \
.proc_info = eata_proc_info, /* procinfo */ \
.name = "EATA (Extended Attachment) HBA driver", \
.detect = eata_detect, \
.release = eata_release, \
.queuecommand = eata_queue, \
.abort = eata_abort, \
.reset = eata_reset, \
.unchecked_isa_dma = 1, /* True if ISA */ \
.use_clustering = ENABLE_CLUSTERING }
#endif /* _EATA_DMA_H */
/*
* Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
void swap_statistics(u8 *p)
{
u32 y;
u32 *lp, h_lp;
u16 *sp, h_sp;
u8 *bp;
lp = (u32 *)p;
sp = ((short *)lp) + 1; /* Convert Header */
h_sp = *sp = ntohs(*sp);
lp++;
do {
sp = (u16 *)lp; /* Convert SubHeader */
*sp = ntohs(*sp);
bp = (u8 *) lp;
y = *(bp + 3);
lp++;
for (h_lp = (u32)lp; (u32)lp < h_lp + ((u32)*(bp + 3)); lp++)
*lp = ntohl(*lp);
}while ((u32)lp < ((u32)p) + 4 + h_sp);
}
/*
* eata_set_info
* buffer : pointer to the data that has been written to the hostfile
* length : number of bytes written to the hostfile
* HBA_ptr: pointer to the Scsi_Host struct
*/
int eata_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
{
int orig_length = length;
if (length >= 8 && strncmp(buffer, "eata_dma", 8) == 0) {
buffer += 9;
length -= 9;
if(length >= 8 && strncmp(buffer, "latency", 7) == 0) {
SD(HBA_ptr)->do_latency = TRUE;
return(orig_length);
}
if(length >=10 && strncmp(buffer, "nolatency", 9) == 0) {
SD(HBA_ptr)->do_latency = FALSE;
return(orig_length);
}
printk("Unknown command:%s length: %d\n", buffer, length);
} else
printk("Wrong Signature:%10s\n", buffer);
return(-EINVAL);
}
/*
* eata_proc_info
* inout : decides on the direction of the dataflow and the meaning of the
* variables
* buffer: If inout==FALSE data is being written to it else read from it
* *start: If inout==FALSE start of the valid data in the buffer
* offset: If inout==FALSE offset from the beginning of the imaginary file
* from which we start writing into the buffer
* length: If inout==FALSE max number of bytes to be written into the buffer
* else number of bytes in the buffer
*/
int eata_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
{
Scsi_Device *scd, *SDev;
struct Scsi_Host *HBA_ptr;
Scsi_Request * scmd;
char cmnd[MAX_COMMAND_SIZE];
static u8 buff[512];
static u8 buff2[512];
hst_cmd_stat *rhcs, *whcs;
coco *cc;
scsitrans *st;
scsimod *sm;
hobu *hb;
scbu *sb;
boty *bt;
memco *mc;
firm *fm;
subinf *si;
pcinf *pi;
arrlim *al;
int i, x;
int size, len = 0;
off_t begin = 0;
off_t pos = 0;
scd = NULL;
HBA_ptr = first_HBA;
for (i = 1; i <= registered_HBAs; i++) {
if (HBA_ptr->host_no == hostno)
break;
HBA_ptr = SD(HBA_ptr)->next;
}
if(inout == TRUE) /* Has data been written to the file ? */
return(eata_set_info(buffer, length, HBA_ptr));
if (offset == 0)
memset(buff, 0, sizeof(buff));
cc = (coco *) (buff + 0x148);
st = (scsitrans *)(buff + 0x164);
sm = (scsimod *) (buff + 0x16c);
hb = (hobu *) (buff + 0x172);
sb = (scbu *) (buff + 0x178);
bt = (boty *) (buff + 0x17e);
mc = (memco *) (buff + 0x186);
fm = (firm *) (buff + 0x18e);
si = (subinf *) (buff + 0x196);
pi = (pcinf *) (buff + 0x19c);
al = (arrlim *) (buff + 0x1a2);
size = sprintf(buffer+len, "EATA (Extended Attachment) driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
len += size; pos = begin + len;
size = sprintf(buffer + len, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
len += size; pos = begin + len;
size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
HBA_ptr->host_no, SD(HBA_ptr)->name);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Firmware revision: v%s\n",
SD(HBA_ptr)->revision);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Hardware Configuration:\n");
len += size;
pos = begin + len;
if(SD(HBA_ptr)->broken_INQUIRY == TRUE) {
if (HBA_ptr->dma_channel == BUSMASTER)
size = sprintf(buffer + len, "DMA: BUSMASTER\n");
else
size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Host Bus: EISA\n");
len += size;
pos = begin + len;
} else {
SDev = scsi_get_host_dev(HBA_ptr);
if(SDev == NULL)
return -ENOMEM;
scmd = scsi_allocate_request(SDev);
if(scmd == NULL)
{
scsi_free_host_dev(SDev);
return -ENOMEM;
}
cmnd[0] = LOG_SENSE;
cmnd[1] = 0;
cmnd[2] = 0x33 + (3<<6);
cmnd[3] = 0;
cmnd[4] = 0;
cmnd[5] = 0;
cmnd[6] = 0;
cmnd[7] = 0x00;
cmnd[8] = 0x66;
cmnd[9] = 0;
scmd->sr_cmd_len = 10;
scmd->sr_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
*/
scsi_wait_req (scmd, cmnd, buff + 0x144, 0x66,
1 * HZ, 1);
size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
(cc->intt == TRUE)?"level":"edge");
len += size;
pos = begin + len;
if (HBA_ptr->dma_channel == 0xff)
size = sprintf(buffer + len, "DMA: BUSMASTER\n");
else
size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type,
bt->cpu_speed);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Host Bus: %s\n",
(SD(HBA_ptr)->bustype == IS_PCI)?"PCI ":
(SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA ");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n",
(sb->wide == TRUE)?" WIDE":"",
(sb->dif == TRUE)?" DIFFERENTIAL":"",
(sb->speed == 0)?"5":(sb->speed == 1)?"10":"20",
(sb->ext == TRUE)?"With external cable detection":"");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "SCSI channel expansion Module: %s present\n",
(bt->sx1 == TRUE)?"SX1 (one channel)":
((bt->sx2 == TRUE)?"SX2 (two channels)":"not"));
len += size;
pos = begin + len;
size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n",
(cc->srs == TRUE)?"":"not ");
len += size;
pos = begin + len;
size = sprintf(buffer + len, " Type: %s\n",
((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated"
:((bt->dm4 == TRUE)?"DM401X"
:(bt->dm4k == TRUE)?"DM4000"
:"-"))
:"-"));
len += size;
pos = begin + len;
size = sprintf(buffer + len, " Max array groups: %d\n",
(al->code == 0x0e)?al->max_groups:7);
len += size;
pos = begin + len;
size = sprintf(buffer + len, " Max drives per RAID 0 array: %d\n",
(al->code == 0x0e)?al->raid0_drv:7);
len += size;
pos = begin + len;
size = sprintf(buffer + len, " Max drives per RAID 3/5 array: %d\n",
(al->code == 0x0e)?al->raid35_drv:7);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Cache Module: %spresent.\n",
(cc->csh)?"":"not ");
len += size;
pos = begin + len;
size = sprintf(buffer + len, " Type: %s\n",
((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated"
:((bt->cm4 == TRUE)?"CM401X"
:((bt->cm4k == TRUE)?"CM4000"
:"-")))
:"-"));
len += size;
pos = begin + len;
for (x = 0; x <= 3; x++) {
size = sprintf(buffer + len, " Bank%d: %dMB with%s ECC\n",x,
mc->banksize[x] & 0x7f,
(mc->banksize[x] & 0x80)?"":"out");
len += size;
pos = begin + len;
}
size = sprintf(buffer + len, "Timer Mod.: %spresent\n",
(cc->tmr == TRUE)?"":"not ");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "NVRAM : %spresent\n",
(cc->nvr == TRUE)?"":"not ");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "SmartROM : %sabled\n",
(bt->srom == TRUE)?"dis":"en");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Alarm : %s\n",
(bt->alrm == TRUE)?"on":"off");
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
if(SD(HBA_ptr)->do_latency == FALSE) {
cmnd[0] = LOG_SENSE;
cmnd[1] = 0;
cmnd[2] = 0x32 + (3<<6);
cmnd[3] = 0;
cmnd[4] = 0;
cmnd[5] = 0;
cmnd[6] = 0;
cmnd[7] = 0x01;
cmnd[8] = 0x44;
cmnd[9] = 0;
scmd->sr_cmd_len = 10;
scmd->sr_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
*/
scsi_wait_req (scmd, cmnd, buff2, 0x144,
1 * HZ, 1);
swap_statistics(buff2);
rhcs = (hst_cmd_stat *)(buff2 + 0x2c);
whcs = (hst_cmd_stat *)(buff2 + 0x8c);
for (x = 0; x <= 11; x++) {
SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
SD(HBA_ptr)->writes[x] += whcs->sizes[x];
SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
SD(HBA_ptr)->writes[12] += whcs->sizes[x];
}
size = sprintf(buffer + len, "Host<->Disk command statistics:\n"
" Reads: Writes:\n");
len += size;
pos = begin + len;
for (x = 0; x <= 10; x++) {
size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
SD(HBA_ptr)->reads[x],
SD(HBA_ptr)->writes[x]);
len += size;
pos = begin + len;
}
size = sprintf(buffer+len,">1024k:%12u %12u\n",
SD(HBA_ptr)->reads[11],
SD(HBA_ptr)->writes[11]);
len += size;
pos = begin + len;
size = sprintf(buffer+len,"Sum :%12u %12u\n",
SD(HBA_ptr)->reads[12],
SD(HBA_ptr)->writes[12]);
len += size;
pos = begin + len;
}
scsi_release_request(scmd);
scsi_free_host_dev(SDev);
}
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
if(SD(HBA_ptr)->do_latency == TRUE) {
int factor = 1024/HZ;
size = sprintf(buffer + len, "Host Latency Command Statistics:\n"
"Current timer resolution: %2dms\n"
" Reads: Min:(ms) Max:(ms) Ave:(ms)\n",
factor);
len += size;
pos = begin + len;
for (x = 0; x <= 10; x++) {
size = sprintf(buffer+len,"%5dk:%12u %12u %12u %12u\n",
1 << x,
SD(HBA_ptr)->reads_lat[x][0],
(SD(HBA_ptr)->reads_lat[x][1] == 0xffffffff)
? 0:(SD(HBA_ptr)->reads_lat[x][1] * factor),
SD(HBA_ptr)->reads_lat[x][2] * factor,
SD(HBA_ptr)->reads_lat[x][3] * factor /
((SD(HBA_ptr)->reads_lat[x][0])
? SD(HBA_ptr)->reads_lat[x][0]:1));
len += size;
pos = begin + len;
}
size = sprintf(buffer+len,">1024k:%12u %12u %12u %12u\n",
SD(HBA_ptr)->reads_lat[11][0],
(SD(HBA_ptr)->reads_lat[11][1] == 0xffffffff)
? 0:(SD(HBA_ptr)->reads_lat[11][1] * factor),
SD(HBA_ptr)->reads_lat[11][2] * factor,
SD(HBA_ptr)->reads_lat[11][3] * factor /
((SD(HBA_ptr)->reads_lat[x][0])
? SD(HBA_ptr)->reads_lat[x][0]:1));
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
size = sprintf(buffer + len,
" Writes: Min:(ms) Max:(ms) Ave:(ms)\n");
len += size;
pos = begin + len;
for (x = 0; x <= 10; x++) {
size = sprintf(buffer+len,"%5dk:%12u %12u %12u %12u\n",
1 << x,
SD(HBA_ptr)->writes_lat[x][0],
(SD(HBA_ptr)->writes_lat[x][1] == 0xffffffff)
? 0:(SD(HBA_ptr)->writes_lat[x][1] * factor),
SD(HBA_ptr)->writes_lat[x][2] * factor,
SD(HBA_ptr)->writes_lat[x][3] * factor /
((SD(HBA_ptr)->writes_lat[x][0])
? SD(HBA_ptr)->writes_lat[x][0]:1));
len += size;
pos = begin + len;
}
size = sprintf(buffer+len,">1024k:%12u %12u %12u %12u\n",
SD(HBA_ptr)->writes_lat[11][0],
(SD(HBA_ptr)->writes_lat[11][1] == 0xffffffff)
? 0:(SD(HBA_ptr)->writes_lat[x][1] * factor),
SD(HBA_ptr)->writes_lat[11][2] * factor,
SD(HBA_ptr)->writes_lat[11][3] * factor /
((SD(HBA_ptr)->writes_lat[x][0])
? SD(HBA_ptr)->writes_lat[x][0]:1));
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
}
size = sprintf(buffer+len,"Attached devices: %s\n",
(!list_empty(&HBA_ptr->my_devices))?"":"none");
len += size;
pos = begin + len;
list_for_each_entry(scd, &HBA_ptr->my_devices, siblings) {
proc_print_scsidevice(scd, buffer, &size, len);
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
}
stop_output:
DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
*start=buffer+(offset-begin); /* Start of wanted data */
len-=(offset-begin); /* Start slop */
if(len>length)
len = length; /* Ending slop */
DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
return (len);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* tab-width: 8
* End:
*/
struct lun_map {
__u8 id:5,
chan:3;
__u8 lun;
};
typedef struct emul_pp {
__u8 p_code:6,
null:1,
p_save:1;
__u8 p_length;
__u16 cylinder;
__u8 heads;
__u8 sectors;
__u8 null2;
__u8 s_lunmap:4,
ems:1;
__u16 drive_type; /* In Little Endian ! */
struct lun_map lunmap[4];
}emulpp;
/* Log Sense pages */
typedef struct log_sheader {
__u8 page_code,
reserved;
__u16 length;
}logsh;
/* Log Sense Statistics */
typedef struct read_command_statistics {
__u16 code; /* 0x01 */
__u8 flags;
__u8 length; /* 0x24 */
__u32 h_commands,
uncached,
la_cmds,
la_blks,
la_hits,
missed,
hits,
seq_la_blks,
seq_la_hits;
}r_cmd_stat;
typedef struct write_command_statistics {
__u16 code; /* 0x03 */
__u8 flags;
__u8 length; /* 0x28 */
__u32 h_commands,
uncached,
thru,
bypass,
soft_err,
hits,
b_idle,
b_activ,
b_blks,
b_blks_clean;
}w_cmd_stat;
typedef struct host_command_statistics {
__u16 code; /* 0x02, 0x04 */
__u8 flags;
__u8 length; /* 0x30 */
__u32 sizes[12];
}hst_cmd_stat;
typedef struct physical_command_statistics {
__u16 code; /* 0x06, 0x07 */
__u8 flags;
__u8 length; /* 0x34 */
__u32 sizes[13];
}phy_cmd_stat;
typedef struct misc_device_statistics {
__u16 code; /* 0x05 */
__u8 flags;
__u8 length; /* 0x10 */
__u32 disconnect,
pass_thru,
sg_commands,
stripe_boundary_crosses;
}msc_stats;
/* Configuration Pages */
typedef struct controller_configuration {
__u16 code; /* 0x01 */
__u8 flags;
__u8 length; /* 0x02 */
__u8 intt:1,
sec:1,
csh:1,
key:1,
tmr:1,
srs:1,
nvr:1;
__u8 interrupt;
}coco;
typedef struct controller_hardware_errors {
__u16 code; /* 0x02 */
__u8 flags;
__u8 length; /* 0x02 */
__u8 unused:1,
per:1;
__u8 interrupt;
}coher;
typedef struct memory_map {
__u16 code; /* 0x03, 0x04 */
__u8 flags;
__u8 length; /* 0x04 */
__u32 memory_map;
}mema;
typedef struct scsi_transfer {
__u16 code; /* 0x05 */
__u8 flags;
__u8 length; /* 0x04 */
__u8 offset,
period;
__u16 speed;
}scsitrans;
typedef struct scsi_modes {
__u16 code; /* 0x06 */
__u8 flags;
__u8 length; /* 0x02 */
__u8 que:1,
cdis:1,
wtru:1,
dasd:1,
ncr:1,
awre:1;
__u8 reserved;
}scsimod;
typedef struct host_bus {
__u16 code; /* 0x07 */
__u8 flags;
__u8 length; /* 0x02 */
__u8 speed:6,
pci:1,
eisa:1;
__u8 reserved;
}hobu;
typedef struct scsi_bus {
__u16 code; /* 0x08 */
__u8 flags;
__u8 length; /* 0x02 */
__u8 speed:4,
res:1,
ext:1,
wide:1,
dif:1;
__u8 busnum;
}scbu;
typedef struct board_type {
__u16 code; /* 0x09 */
__u8 flags;
__u8 length; /* 0x04 */
__u8 unused:1,
cmi:1,
dmi:1,
cm4k:1,
cm4:1,
dm4k:1,
dm4:1,
hba:1;
__u8 cpu_type,
cpu_speed;
__u8 sx1:1,
sx2:1,
unused2:4,
alrm:1,
srom:1;
}boty;
typedef struct memory_config {
__u16 code; /* 0x0a */
__u8 flags;
__u8 length; /* 0x04 */
__u8 banksize[4];
}memco;
typedef struct firmware_info {
__u16 code; /* 0x0b */
__u8 flags;
__u8 length; /* 0x04 */
__u8 dnld:1,
bs528:1,
fmt:1,
fw528:1;
__u8 unused1,
fw_type,
unused;
}firm;
typedef struct subsystem_info {
__u16 code; /* 0x0c */
__u8 flags;
__u8 length; /* 0x02 */
__u8 shlf:1,
swap:1,
noss:1;
__u8 reserved;
}subinf;
typedef struct per_channel_info {
__u16 code; /* 0x0d */
__u8 flags;
__u8 length; /* 0x02 */
__u8 channel;
__u8 shlf:1,
swap:1,
noss:1,
srs:1,
que:1,
ext:1,
wide:1,
diff:1;
}pcinf;
typedef struct array_limits {
__u16 code; /* 0x0e */
__u8 flags;
__u8 length; /* 0x04 */
__u8 max_groups,
raid0_drv,
raid35_drv,
unused;
}arrlim;
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment