diff options
Diffstat (limited to 'i386/i386at/gpl/linux/scsi/eata_dma.c')
-rw-r--r-- | i386/i386at/gpl/linux/scsi/eata_dma.c | 1375 |
1 files changed, 1375 insertions, 0 deletions
diff --git a/i386/i386at/gpl/linux/scsi/eata_dma.c b/i386/i386at/gpl/linux/scsi/eata_dma.c new file mode 100644 index 00000000..da9e3daa --- /dev/null +++ b/i386/i386at/gpl/linux/scsi/eata_dma.c @@ -0,0 +1,1375 @@ +/************************************************************ + * * + * 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 * + * -supports all EISA based EATA-DMA boards * + * -supports all PCI based EATA-DMA boards * + * -supports multiple HBAs with & without IRQ sharing * + * -supports all SCSI channels on multi channel boards * + * -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,94,95 Michael Neuffer * + * neuffer@goofy.zdv.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 Greg Hosler who did a lot of testing and * + * found quite a number of bugs during the development. * + ************************************************************ + * last change: 95/11/29 OS: Linux 1.3.45 * + ************************************************************/ + +/* Look in eata_dma.h for configuration and revision information */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/in.h> +#include <linux/bios32.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <asm/byteorder.h> +#include <asm/types.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <linux/blk.h> +#include "scsi.h" +#include "sd.h" +#include "hosts.h" +#include <linux/scsicam.h> +#include "eata_dma.h" +#include "eata_dma_proc.h" + +#include <linux/stat.h> +#include <linux/config.h> /* for CONFIG_PCI */ + +struct proc_dir_entry proc_scsi_eata_dma = { + PROC_SCSI_EATA, 8, "eata_dma", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +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_scsi_done (Scsi_Cmnd * scmd) +{ + scmd->request.rq_status = RQ_SCSI_DONE; + + if (scmd->request.sem != NULL) + up(scmd->request.sem); + + return; +} + +void eata_fake_int_handler(s32 irq, 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; +} + +#ifdef MACH +#include "eata_dma_proc.src" +#else +#include "eata_dma_proc.c" +#endif + +#ifdef MODULE +int eata_release(struct Scsi_Host *sh) +{ + uint i; + if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq); + else reg_IRQ[sh->irq]--; + + scsi_init_free((void *)status, 512); + scsi_init_free((void *)dma_scratch, 512); + for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */ + if(SD(sh)->ccb[i].sg_list != NULL) + scsi_init_free((void *) SD(sh)->ccb[i].sg_list, + sh->sg_tablesize * sizeof(struct eata_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 + + +void eata_int_handler(int irq, struct pt_regs * regs) +{ + uint i, result = 0; + uint hba_stat, scsi_stat, eata_stat; + Scsi_Cmnd *cmd; + struct eata_ccb *cp; + struct eata_sp *sp; + uint base; + ulong flags; + uint x; + struct Scsi_Host *sh; + + save_flags(flags); + cli(); + + 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; + cp = sp->ccb; + + if(cp == 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 = cp->cmd; + base = (uint) cmd->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("eata_dma: int_handler, board: %x cmd %lx returned " + "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx " + "spadrirq %lx, irq%d\n", base, (long)cp, eata_stat, + hba_stat, scsi_stat,(long)&status, (long)&status[irq], + irq); + DBG(DBG_DELAY, DEL2(800)); + break; + } + + if (cp->status == LOCKED) { + cp->status = FREE; + eata_stat = inb(base + HA_RSTATUS); + printk("eata_dma: int_handler, freeing locked queueslot\n"); + DBG(DBG_INTR && DBG_DELAY, DEL2(800)); + break; + } + + 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->target, + cmd->lun, eata_stat, hba_stat)); + + switch (hba_stat) { + case HA_NO_ERROR: /* NO Error */ + if (scsi_stat == CONDITION_GOOD + && cmd->device->type == TYPE_DISK + && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET)) + result = DID_BUS_BUSY << 16; + else if (scsi_stat == GOOD) { + HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK; + if(HD(cmd)->do_latency == TRUE && cp->timestamp) { + uint time; + time = jiffies - cp->timestamp; + if((cp->rw_latency) == TRUE) { /* was WRITE */ + if(HD(cmd)->writes_lat[cp->sizeindex][1] > time) + HD(cmd)->writes_lat[cp->sizeindex][1] = time; + if(HD(cmd)->writes_lat[cp->sizeindex][2] < time) + HD(cmd)->writes_lat[cp->sizeindex][2] = time; + HD(cmd)->writes_lat[cp->sizeindex][3] += time; + HD(cmd)->writes_lat[cp->sizeindex][0]++; + } else { + if(HD(cmd)->reads_lat[cp->sizeindex][1] > time) + HD(cmd)->reads_lat[cp->sizeindex][1] = time; + if(HD(cmd)->reads_lat[cp->sizeindex][2] < time) + HD(cmd)->reads_lat[cp->sizeindex][2] = time; + HD(cmd)->reads_lat[cp->sizeindex][3] += time; + HD(cmd)->reads_lat[cp->sizeindex][0]++; + } + } + } + else if (scsi_stat == CHECK_CONDITION + && cmd->device->type == TYPE_DISK + && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR) + result = DID_BUS_BUSY << 16; + else + result = DID_OK << 16; + HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK; + break; + case HA_ERR_SEL_TO: /* Selection Timeout */ + result = DID_BAD_TARGET << 16; + break; + case HA_ERR_CMD_TO: /* Command Timeout */ + if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1) + result = DID_ERROR << 16; + else { + result = DID_TIME_OUT << 16; + HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++; + } + break; + case HA_ERR_RESET: /* SCSI Bus Reset Received */ + 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++) + HD(cmd)->t_state[cp->cp_channel][i] = RESET; + 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_SCSI_HUNG: /* SCSI Hung */ + case HA_UNX_MSGRJCT: /* Unexpected Message Reject */ + case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */ + case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */ + 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,DEL2(800)); +#endif + + cp->status = FREE; /* now we can release the slot */ + cmd->scsi_done(cmd); + } + } + restore_flags(flags); + + 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); + + /* And now the address in nice little byte chunks */ + outb( addr & 0x000000ff, base + HA_WDMAADDR); + outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); + outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); + outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); + outb(command, base + HA_WCOMMAND); + return(TRUE); +} + +#if 0 +inline int eata_send_immediate(u32 addr, u32 base, u8 cmnd, u8 cmnd2, u8 id, + u8 lun) +{ + if(addr){ + outb( addr & 0x000000ff, base + HA_WDMAADDR); + outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); + outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); + outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); + } else { + outb(id, base + HA_WSUBCODE); + outb(lun, base + HA_WSUBLUN); + } + + outb(cmnd2, base + HA_WCOMMAND2); + outb(cmnd, base + HA_WCOMMAND); + return(TRUE); +} +#endif + +int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *)) +{ + unsigned int i, x, y; + u32 flags; + hostdata *hd; + struct Scsi_Host *sh; + struct eata_ccb *cp; + struct scatterlist *sl; + + save_flags(flags); + cli(); + + queue_counter++; + + hd = HD(cmd); + sh = cmd->host; + + /* 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) { + uint z; + + printk(KERN_EMERG "eata_dma: run out of queue slots cmdno:%ld" + " intrno: %ld, can_queue: %d, x: %d, y: %d\n", + queue_counter, int_counter, sh->can_queue, x, y); + printk(KERN_EMERG "Status of queueslots:"); + for(z = 0; z < sh->can_queue; z +=2) { + switch(hd->ccb[z].status) { + case FREE: + printk(KERN_EMERG "Slot %2d is FREE \t", z); + break; + case USED: + printk(KERN_EMERG "Slot %2d is USED \t", z); + break; + case LOCKED: + printk(KERN_EMERG "Slot %2d is LOCKED\t", z); + break; + default: + printk(KERN_EMERG "Slot %2d is UNKNOWN\t", z); + } + panic("\nSystem halted.\n"); + } + } + cp = &hd->ccb[y]; + + memset(cp, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *)); + + cp->status = USED; /* claim free slot */ + + DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n", + cmd->pid, cmd->target, cmd->lun, y)); + DBG(DBG_QUEUE && DBG_DELAY, DEL2(250)); + + if(hd->do_latency == TRUE) { + int x, z; + short *sho; + long *lon; + x = 0; /* just to keep GCC quiet */ + 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) { + + cp->timestamp = jiffies; /* For latency measurements */ + switch(cmd->cmnd[0]) { + case WRITE_6: + case READ_6: + x = cmd->cmnd[4]/2; + break; + case WRITE_10: + case READ_10: + sho = (short *) &cmd->cmnd[7]; + x = ntohs(*sho)/2; + break; + case WRITE_12: + case READ_12: + lon = (long *) &cmd->cmnd[6]; + x = ntohl(*lon)/2; + break; + } + + for(z = 0; (x > (1 << z)) && (z <= 11); z++) + /* nothing */; + cp->sizeindex = z; + if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 || + cmd->cmnd[0] == WRITE_12){ + cp->rw_latency = TRUE; + } + } + } + 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 */ + cp->DataOut = TRUE; /* Output mode */ + break; + case TEST_UNIT_READY: + default: + cp->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->target == sh->this_id) + cp->Interpret = TRUE; /* Interpret command */ + + if (cmd->use_sg) { + cp->scatter = TRUE; /* SG mode */ + if (cp->sg_list == NULL) { + cp->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list), + GFP_ATOMIC | GFP_DMA); + } + if (cp->sg_list == NULL) + panic("eata_dma: Run out of DMA memory for SG lists !\n"); + cp->cp_dataDMA = htonl(virt_to_bus(cp->sg_list)); + + cp->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++){ + cp->sg_list[i].data = htonl(virt_to_bus(sl->address)); + cp->sg_list[i].len = htonl((u32) sl->length); + } + } else { + cp->scatter = FALSE; + cp->cp_datalen = htonl(cmd->request_bufflen); + cp->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer)); + } + + cp->Auto_Req_Sen = TRUE; + cp->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer)); + cp->reqlen = sizeof(cmd->sense_buffer); + + cp->cp_id = cmd->target; + cp->cp_channel = cmd->channel; + cp->cp_lun = cmd->lun; + cp->cp_dispri = TRUE; + cp->cp_identify = TRUE; + memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len); + + cp->cp_statDMA = htonl(virt_to_bus(&(hd->sp))); + + cp->cp_viraddr = cp; /* This will be passed thru, so we don't need to + * convert it */ + cp->cmd = cmd; + cmd->host_scribble = (char *)&hd->ccb[y]; + + if(eata_send_command((u32) cp, (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->target, cmd->pid)); + done(cmd); + cp->status = FREE; + restore_flags(flags); + 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->target, cmd->lun, y, sh->irq)); + DBG(DBG_QUEUE && DBG_DELAY, DEL2(200)); + restore_flags(flags); + return(0); +} + + +int eata_abort(Scsi_Cmnd * cmd) +{ + ulong loop = R_LIMIT; + ulong flags; + + save_flags(flags); + cli(); + + DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x" + " reason %x\n", cmd->pid, cmd->target, cmd->lun, + cmd->abort_reason)); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + + while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) { + if (--loop == 0) { + printk("eata_dma: abort, timeout error.\n"); + restore_flags(flags); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + return (SCSI_ABORT_ERROR); + } + } + if (CD(cmd)->status == RESET) { + restore_flags(flags); + printk("eata_dma: abort, command reset error.\n"); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + return (SCSI_ABORT_ERROR); + } + if (CD(cmd)->status == LOCKED) { + restore_flags(flags); + DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n")); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + 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) +{ + ushort x, z; + ulong time, limit = 0; + ulong loop = R_LIMIT; + ulong flags; + unchar success = FALSE; + Scsi_Cmnd *sp; + + save_flags(flags); + cli(); + + DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x" + " reason %x\n", cmd->pid, cmd->target, cmd->lun, + cmd->abort_reason)); + + if (HD(cmd)->state == RESET) { + printk("eata_reset: exit, already in reset.\n"); + restore_flags(flags); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + return (SCSI_RESET_ERROR); + } + + while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) + if (--loop == 0) { + printk("eata_reset: exit, timeout error.\n"); + restore_flags(flags); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + return (SCSI_RESET_ERROR); + } + + for (x = 0; x < MAXCHANNEL; x++) { + for (z = 0; z < MAXTARGET; z++) { + HD(cmd)->t_state[x][z] = RESET; + HD(cmd)->t_timeout[x][z] = NO_TIMEOUT; + } + } + + for (x = 0; x < cmd->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, DEL2(500)); + continue; + } + sp = HD(cmd)->ccb[x].cmd; + HD(cmd)->ccb[x].status = RESET; + printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + + if (sp == NULL) + panic("eata_reset: slot %d, sp==NULL.\n", x); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + + if (sp == cmd) + success = TRUE; + } + + /* hard reset the HBA */ + inb((u32) (cmd->host->base) + HA_RSTATUS); /* This might cause trouble */ + eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET); + + DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n")); + HD(cmd)->state = RESET; + + restore_flags(flags); + + time = jiffies; + while (jiffies < (time + (3 * HZ)) || limit++ < 10000000) + /* As time goes by... */; + + save_flags(flags); + cli(); + + DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n", + limit)); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + + for (x = 0; x < cmd->host->can_queue; x++) { + + /* Skip slots already set free by interrupt */ + 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, DEL2(500)); + restore_flags(flags); + sp->scsi_done(sp); + cli(); + } + + HD(cmd)->state = FALSE; + restore_flags(flags); + + if (success) { + DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n")); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + return (SCSI_RESET_SUCCESS); + } else { + DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n")); + DBG(DBG_ABNORM && DBG_DELAY, DEL2(500)); + return (SCSI_RESET_PUNT); + } +} + +char * get_board_data(u32 base, u32 irq, u32 id) +{ + struct eata_ccb *cp; + struct eata_sp *sp; + static char *buff; + ulong i; + ulong limit = 0; + + cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb), + GFP_ATOMIC | GFP_DMA); + sp = (struct eata_sp *) scsi_init_malloc(sizeof(struct eata_sp), + GFP_ATOMIC | GFP_DMA); + + 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 && jiffies <= i) + barrier(); + + DBG(DBG_INTR3, printk("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)); + + scsi_init_free((void *)cp, sizeof(struct eata_ccb)); + scsi_init_free((void *)sp, sizeof(struct eata_sp)); + + if ((fake_int_result & HA_SERROR) || jiffies > i){ + /* hard reset the HBA */ + inb((u32) (base) + HA_RSTATUS); + eata_send_command(0, base, EATA_CMD_RESET); + i = jiffies; + while (jiffies < (i + (3 * HZ)) && limit++ < 10000000) + barrier(); + return (NULL); + } else + return (buff); +} + +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); +} + +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); + + 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")){ + 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 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("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); + if (gc->IRQ_TR == FALSE) + reg_IRQL[gc->IRQ] = FALSE; + return (FALSE); + } + } + +#if !(NEWSTUFF) + if (bustype != IS_EISA && bustype != IS_ISA) +#endif + buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]); + + if (buff == NULL) { +#if !(NEWSTUFF) + if (bustype == IS_EISA || bustype == IS_ISA) { + bugs = bugs || BROKEN_INQUIRY; + } else { +#endif + if (gc->DMA_support == FALSE) + printk("HBA at %#.4x doesn't support DMA. Sorry\n", base); + else + printk("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); + if (gc->IRQ_TR == FALSE) + reg_IRQL[gc->IRQ] = FALSE; + return (FALSE); +#if !(NEWSTUFF) + } +#endif + } + + if (gc->DMA_support == FALSE && buff != NULL) + printk("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("Warning: Queue size has to be corrected. Assuming 64 queueslots\n" + " This might be a PM2012B with a defective Firmware\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) { + if (gc->DMA_valid) + free_dma(dma_channel); + + reg_IRQ[gc->IRQ]--; + if (reg_IRQ[gc->IRQ] == 0) + free_irq(gc->IRQ); + if (gc->IRQ_TR == FALSE) + reg_IRQL[gc->IRQ] = FALSE; + return (FALSE); + } + + hd = SD(sh); + + memset(hd->ccb, 0, sizeof(struct eata_ccb) * ntohs(gc->queuesiz)); + memset(hd->reads, 0, sizeof(u32) * 26); + + hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY); + + if(hd->broken_INQUIRY == TRUE) { + strcpy(SD(sh)->vendor, "DPT"); + strcpy(SD(sh)->name, "??????????"); + strcpy(SD(sh)->revision, "???.?"); + } else { + strncpy(SD(sh)->vendor, &buff[8], 8); + SD(sh)->vendor[8] = 0; + strncpy(SD(sh)->name, &buff[16], 17); + SD(sh)->name[17] = 0; + SD(sh)->revision[0] = buff[32]; + SD(sh)->revision[1] = buff[33]; + SD(sh)->revision[2] = buff[34]; + SD(sh)->revision[3] = '.'; + SD(sh)->revision[4] = buff[35]; + SD(sh)->revision[5] = 0; + } + + switch (ntohl(gc->len)) { + case 0x1c: + SD(sh)->EATA_revision = 'a'; + break; + case 0x1e: + SD(sh)->EATA_revision = 'b'; + break; + case 0x22: + SD(sh)->EATA_revision = 'c'; + break; + case 0x24: + SD(sh)->EATA_revision = 'z'; + default: + SD(sh)->EATA_revision = '?'; + } + + if(ntohl(gc->len) >= 0x22) { + if (gc->is_PCI == TRUE) + hd->bustype = IS_PCI; + else if (gc->is_EISA == TRUE) + hd->bustype = IS_EISA; + else + hd->bustype = IS_ISA; + } else if(hd->broken_INQUIRY == FALSE) { + if (buff[21] == '4') + hd->bustype = IS_PCI; + else if (buff[21] == '2') + hd->bustype = IS_EISA; + else + hd->bustype = IS_ISA; + } else + hd->bustype = bustype; + + 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->channel = gc->MAX_CHAN; + sh->max_channel = gc->MAX_CHAN; + sh->unique_id = base; + sh->base = (char *) 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]; + sh->can_queue = ntohs(gc->queuesiz); + + if (gc->OCS_enabled == TRUE) { + if(hd->bustype != IS_ISA) + sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; + else + sh->cmd_per_lun = 8; /* We artificially limit this to conserve + * memory, which would be needed for ISA + * bounce buffers */ + } else + sh->cmd_per_lun = 1; + + /* FIXME: + * SG should be allocated more dynamically + */ + /* + * If we are using a ISA board, we can't use extended SG, + * because we would need exessive 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; + sh->use_clustering = FALSE; + } else { + sh->sg_tablesize = ntohs(gc->SGsiz); + sh->use_clustering = TRUE; + if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) { + sh->sg_tablesize = SG_SIZE; + if (ntohs(gc->SGsiz) == 0) + printk("Warning: SG size had to be corrected.\n" + "This might be a PM2012 with a defective Firmware\n"); + } + } + + if (gc->SECOND) + hd->primary = FALSE; + else + hd->primary = TRUE; + + sh->wish_block = FALSE; + + 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->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"); + } else { + if (check_blink_state(base)) + printk("HBA is in BLINK state. Consult your HBAs " + "Manual to correct this.\n"); + } + /* 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); + } else { + if (check_blink_state(ISAbases[i])) + printk("HBA is in BLINK state. Consult your HBAs " + "Manual to correct this.\n"); + } + 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 + + u8 pci_bus, pci_device_fn; + static s16 pci_index = 0; /* Device index to PCI BIOS calls */ + u32 base = 0; + u16 com_adr; + u16 rev_device; + u32 error, i, x; + u8 pal1, pal2, pal3; + + if (pcibios_present()) { + for (i = 0; i <= MAXPCI; ++i, ++pci_index) { + if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, + pci_index, &pci_bus, &pci_device_fn)) + break; + DBG(DBG_PROBE && DBG_PCI, + printk("eata_dma: find_PCI, HBA at bus %d, device %d," + " function %d, index %d\n", (s32)pci_bus, + (s32)((pci_device_fn & 0xf8) >> 3), + (s32)(pci_device_fn & 7), pci_index)); + + if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_CLASS_DEVICE, &rev_device))) { + if (rev_device == PCI_CLASS_STORAGE_SCSI) { + if (!(error = pcibios_read_config_word(pci_bus, + pci_device_fn, PCI_COMMAND, + (u16 *) & com_adr))) { + if (!((com_adr & PCI_COMMAND_IO) && + (com_adr & PCI_COMMAND_MASTER))) { + printk("eata_dma: find_PCI, HBA has IO or BUSMASTER mode disabled\n"); + continue; + } + } else + printk("eata_dma: find_PCI, error %x while reading " + "PCI_COMMAND\n", error); + } else + printk("eata_dma: find_PCI, DEVICECLASSID %x didn't match\n", + rev_device); + } else { + printk("eata_dma: find_PCI, error %x while reading PCI_CLASS_BASE\n", + error); + continue; + } + + if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, (int *) &base))){ + + /* Check if the address is valid */ + if (base & 0x01) { + base &= 0xfffffffe; + /* 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; + continue; /* break; */ + } else if (check_blink_state(base) == TRUE) { + printk("eata_dma: HBA is in BLINK state.\n" + "Consult your HBAs Manual to correct this.\n"); + } + } + } + } else { + printk("eata_dma: error %x while reading " + "PCI_BASE_ADDRESS_0\n", error); + } + } + } else { + printk("eata_dma: No BIOS32 extensions present. This driver release " + "still depends on it.\n" + " Skipping scan for PCI HBAs. \n"); + } +#endif /* #ifndef CONFIG_PCI */ + return; +} + +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_dir = &proc_scsi_eata_dma; + + status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA); + + if(status == NULL || dma_scratch == NULL) { + printk("eata_dma: can't allocate enough memory to probe for hosts !\n"); + return(0); + } + + 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]){ /* exchange the interrupt handler which */ + free_irq(i); /* we used for probing with the real one */ + request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, "eata_dma"); + } + } + HBA_ptr = first_HBA; + + if (registered_HBAs != 0) { + printk("EATA (Extended Attachment) driver version: %d.%d%s\n" + "developed in co-operation with DPT\n" + "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n", + VER_MAJOR, VER_MINOR, VER_SUB); + printk("Registered HBAs:"); + printk("\nHBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: " + "ID: Pr: QS: SG: CPL:\n"); + for (i = 1; i <= registered_HBAs; i++) { + printk("scsi%-2d: %.10s 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 %2d %2d %2d\n", SD(HBA_ptr)->channel, + HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', + HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun); + HBA_ptr = SD(HBA_ptr)->next; + } + } else { + scsi_init_free((void *)status, 512); + } + + scsi_init_free((void *)dma_scratch, 512); + + DBG(DPT_DEBUG, DELAY(12)); + + return(registered_HBAs); +} + +#ifdef MODULE +/* Eventually this will go into an include file, but this will be later */ +Scsi_Host_Template driver_template = EATA_DMA; +#include "scsi_module.c" +#endif + +/* + * 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: + */ |