/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $ * linux/kernel/aha1542.c * * Copyright (C) 1992 Tommy Thorn * Copyright (C) 1993, 1994, 1995 Eric Youngdale * Copyright (C) 1998, 1999 Andries Brouwer * * Modified by Eric Youngdale * Use request_irq and request_dma to help prevent unexpected conflicts * Set up on-board DMA controller, such that we do not have to * have the bios enabled to use the aha1542. * Modified by David Gentzel * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus * controller). * Modified by Matti Aarnio * Accept parameters from LILO cmd-line. -- 1-Oct-94 * Modified by Mike McLagan * Recognise extended mode on AHA1542CP, different bit than 1542CF * 1-Jan-97 * This patch is buggy - it causes the driver to assume unconditionally that * extended translation is required when a disk larger than 1 GB is present. - if(mbenable_result[1] & 1) retval = BIOS_TRANSLATION_25563; + if(mbenable_result[1] & 0x03) retval = BIOS_TRANSLATION_25563; * Modified by Bjorn L. Thordarson and Einar Thor Einarsson * Recognize that DMA0 is valid DMA channel -- 13-Jul-98 * Modified by Andries Brouwer * Make abort and reset work -- 25-Aug-98 and 29-Dec-98 * Modified by Richard Fish * Suppress reset/retry error handling at EOM/EOF conditions * 11-Nov-98 * Modified by Chris Faulhaber * Added module command-line options * 19-Jul-99 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "scsi.h" #include "hosts.h" #include "aha1542.h" #define STAY_ALIVE #define SCSI_PA(address) virt_to_bus(address) /* convert ADDRESS as used by driver to address as used by host adapter */ /* and store in big_endian order at PTR */ static inline void addr_to_scsi(unsigned char *ptr, void *address) { any2scsi(ptr, SCSI_PA(address)); } /* determine index in CCB array that ADDRESS as stored by host adapter points to */ static inline int get_ccb_index(unchar *address, struct ccb *ccb) { return (scsi2int(address) - SCSI_PA(&ccb[0])) / sizeof(struct ccb); } static inline int check_past_dma_threshold(char *address, int len, char *msg) { if (SCSI_PA(address+len-1) > ISA_DMA_THRESHOLD) { if (!msg) return 1; /* not fatal */ printk(KERN_CRIT "aha1542: %s address %p length %d\n", msg, address, len); panic("Buffer at physical address > 16Mb used for aha1542"); } return 0; } #undef SCSI_PA #include struct proc_dir_entry proc_scsi_aha1542 = { PROC_SCSI_AHA1542, 7, "aha1542", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; /* The adaptec can be configured for quite a number of addresses, but I generally do not want the card poking around at random. We allow two addresses - this allows people to use the Adaptec with a Midi card, which also used 0x330 -- can be overridden with LILO! */ #define MAXBOARDS 2 /* Increase this and the sizes of the arrays below, if you need more.. */ static unsigned int bases[MAXBOARDS]={0x330, 0x334}; /* set by aha1542_setup according to the command line */ static int setup_called[MAXBOARDS] = {0,0}; static int setup_buson[MAXBOARDS] = {0,0}; static int setup_busoff[MAXBOARDS] = {0,0}; static int setup_dmaspeed[MAXBOARDS] = {-1,-1}; static char *setup_str[MAXBOARDS] = {(char *)NULL,(char *)NULL}; /* * LILO/Module params: aha1542=[,,[,]] * * Where: is any of the valid AHA addresses: * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 * is the time (in microsecs) that AHA spends on the AT-bus * when transferring data. 1542A power-on default is 11us, * valid values are in range: 2..15 (decimal) * is the time that AHA spends OFF THE BUS after while * it is transferring data (not to monopolize the bus). * Power-on default is 4us, valid range: 1..64 microseconds. * Default is jumper selected (1542A: on the J1), * but experimenter can alter it with this. * Valid values: 5, 6, 7, 8, 10 (MB/s) * Factory default is 5 MB/s. * (The 1542CF also has a lower choice, 3.3 MB/s, I think) */ #if defined(MODULE) int aha1542[] = { 0x330, 11, 4, -1 }; MODULE_PARM(aha1542, "1-4i"); #endif #define BIOS_TRANSLATION_UNKN 0 #define BIOS_TRANSLATION_1632 1 /* Used by some old 1542A boards */ #define BIOS_TRANSLATION_6432 2 /* Default case these days */ #define BIOS_TRANSLATION_25563 3 /* Big disk case */ struct aha1542_hostdata { int bios_translation; /* Mapping bios uses - for compatibility */ int aha1542_last_mbi_used; int aha1542_last_mbo_used; Scsi_Cmnd * SCint[AHA1542_MAILBOXES]; struct mailbox mb[2*AHA1542_MAILBOXES]; struct ccb ccb[AHA1542_MAILBOXES]; }; #define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata) /* One for each IRQ level (9-15) */ static struct Scsi_Host * aha_host[7] = {NULL,}; #define WAITnexttimeout 3000000 static int aha1542_restart(struct Scsi_Host * shost); #define aha1542_intr_reset(base) outb(IRST, CONTROL(base)) #define WAIT(port, mask, allof, noneof) \ { register int WAITbits; \ register int WAITtimeout = WAITnexttimeout; \ while (1) { \ WAITbits = inb(port) & (mask); \ if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ break; \ if (--WAITtimeout == 0) goto fail; \ } \ } static inline int get_next_unused_mbo(Scsi_Cmnd * SCpnt) { struct aha1542_hostdata *hostdata = HOSTDATA(SCpnt->host); struct mailbox * mb = hostdata->mb; unsigned long flags; int mbo; save_flags(flags); cli(); mbo = hostdata->aha1542_last_mbo_used; do { mbo++; if (mbo >= AHA1542_MAILBOXES) mbo = 0; } while (mbo != hostdata->aha1542_last_mbo_used && (mb[mbo].status || hostdata->SCint[mbo])); hostdata->aha1542_last_mbo_used = mbo; /* A panic may be too drastic if this isnt our root device */ /* No doubt this means that we are leaking mailboxes by forgetting to remove entries hostdata->SCint[mbo]. */ if(mb[mbo].status || hostdata->SCint[mbo]) panic("Unable to find empty mailbox for aha1542.\n"); /* Prevent someone else from screwing with this cdb. */ hostdata->SCint[mbo] = SCpnt; restore_flags(flags); return mbo; } static void aha1542_stat(unsigned int base) { unchar s = inb(STATUS(base)); unchar i = inb(INTRFLAGS(base)); printk("status=%x intrflags=%x\n", s, i); } /* This is a bit complicated, but we need to make sure that an interrupt routine does not send something out while we are in the middle of this. Fortunately, it is only at boot time that multi-byte messages are ever sent. */ static int aha1542_out(unsigned int base, unchar *cmdp, int len) { unsigned long flags = 0; save_flags(flags); if(len == 1) { while(1) { WAIT(STATUS(base), CDF, 0, CDF); cli(); if(inb(STATUS(base)) & CDF) { restore_flags(flags); continue; } outb(*cmdp, DATA(base)); restore_flags(flags); return 0; } } else { cli(); while (len--) { WAIT(STATUS(base), CDF, 0, CDF); outb(*cmdp++, DATA(base)); } restore_flags(flags); } return 0; fail: restore_flags(flags); printk("aha1542_out failed(%d): ", len+1); aha1542_stat(base); return 1; } /* Translate HASTAT (host adapter status) into an error code understood by upper layers */ static int makecode(unsigned hosterr, unsigned scsierr) { switch (hosterr) { /* HASTAT */ case 0x0: /* No host adapter detected error - The CCB was completed normally. */ case 0xa: /* Linked command complete without error - The SCSI command completed and linked normally. */ case 0xb: /* Linked command complete without error, interrupt generated. - The SCSI command completed and linked with a LINKED COMMAND COMPLETE WITH FLAG message. */ hosterr = 0; break; /* cases 0x11-0x14 are problems with the target device */ case 0x11: /* Selection time out - The initiator selection or target reselection was not complete within the Set SCSI Selection Time-out period. */ hosterr = DID_TIME_OUT; break; case 0x14: /* Target bus phase sequence failure - An invalid bus phase or bus phase sequence was requested by the target. The host adapter will generate a SCSI Reset Condition, notifying the host with a SCRD interrupt. */ hosterr = DID_RESET; break; case 0x12: /* Data overrun/underrun - The target attempted to transfer more data than was allocated by the Data Length field or the sum of the Scatter / Gather Data Length fields. */ case 0x13: /* Unexpected bus free - The target dropped the SCSI BSY at an unexpected time. */ hosterr = DID_ERROR; break; /* cases 0x15-0x1a are software bugs */ case 0x15: /* MBO command was not 00, 01, or 02 - The first byte of the MBO command was invalid. This usually indicates a software failure. */ case 0x16: /* Invalid CCB Operation Code - The first byte of the CCB was invalid. This usually indicates a software failure. */ case 0x17: /* Linked CCB does not have the same LUN - A subsequent CCB of a set of linked CCB's does not specify the same logical unit number as the first. */ case 0x18: /* Invalid Target Direction received from Host - The direction of a Target Mode CCB was invalid. */ case 0x19: /* Duplicate CCB Received in Target Mode - More than once CCB was received to service data transfer between the same target LUN and initiator SCSI ID in the same direction. */ case 0x1a: /* Invalid CCB or Segment List Parameter - A segment list with a zero length segment or invalid segment list boundaries was received. A CCB parameter was invalid. */ printk("aha1542: driver bug: %x %x\n", hosterr, scsierr); hosterr = DID_ERROR; break; default: printk("aha1542: makecode: unknown hoststatus %x\n", hosterr); hosterr = DID_ERROR; break; } return scsierr | (hosterr << 16); } static int aha1542_test_port(int base, struct Scsi_Host * shpnt) { unchar inquiry_cmd[] = { CMD_INQUIRY }; unchar inquiry_result[4]; unchar *cmdp; int len; /* Quick and dirty test for presence of the card. */ if(inb(STATUS(base)) == 0xff) return 0; /* Clear interrupts */ /* Soft reset - no reason to reset SCSI bus */ outb(IRST|SRST, CONTROL(base)); mdelay(20); /* Wait a little bit for things to settle down. */ /* Expect INIT and IDLE, any of the others are bad */ WAIT(STATUS(base), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF); /* Shouldn't have generated any interrupts during reset */ if (inb(INTRFLAGS(base)) & INTRMASK) goto fail; /* Perform a host adapter inquiry instead so we do not need to set up the mailboxes ahead of time */ aha1542_out(base, inquiry_cmd, 1); len = 4; cmdp = &inquiry_result[0]; while (len--) { WAIT(STATUS(base), DF, DF, 0); *cmdp++ = inb(DATA(base)); } /* Reading port should reset DF */ if (inb(STATUS(base)) & DF) goto fail; /* When HACC, command is completed, and we're though testing */ WAIT(INTRFLAGS(base), HACC, HACC, 0); /* now initialize adapter */ /* Clear interrupts */ outb(IRST, CONTROL(base)); return 1; /* ok */ fail: return 0; /* nok */ } /* A "high" level interrupt handler */ static void aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { int first = 1; int errstatus, mbo, mbistatus; unsigned int flags; struct Scsi_Host * shost; Scsi_Cmnd * SCtmp; int flag; struct mailbox * mb; struct ccb *ccb; shost = aha_host[irq - 9]; if(!shost) panic("Splunge!"); mb = HOSTDATA(shost)->mb; ccb = HOSTDATA(shost)->ccb; while (1){ flag = inb(INTRFLAGS(shost->io_port)); if (first || flag) { aha1542_intr_reset(shost->io_port); /* Check for unusual interrupts. */ /* We expect MBIF+ANYINTR the first time around, and 0 or MBIF+ANYINTR on later iterations of this loop. */ if ((flag & INTRMASK) != MBIF+ANYINTR) { char errmsg[100]; sprintf(errmsg, "aha1542_intr_handle:"); if (!(flag & ANYINTR)) strcat(errmsg, " no interrupt?"); if (flag & MBOA) strcat(errmsg, " MBOA"); if (flag & HACC) strcat(errmsg, " HACC"); if (flag & SCRD) strcat(errmsg, " SCSI reset detected."); if (!(flag & MBIF)) strcat(errmsg, " no mail."); printk("%s\n", errmsg); } } if (flag & SCRD) { /* We detected a reset. Restart all pending commands for devices that use the hard reset option */ aha1542_restart(shost); } if (first && !(flag & MBIF)) return; first = 0; /* Either we got a MBIF or we already found sth on a previous loop around. Check for mail. */ /* In fact it is not necessary to check all mailboxes: The host adapter guarantees that the next letter will be in the next mailbox. But just to be sure... */ { int mbi; save_flags(flags); cli(); mbi = HOSTDATA(shost)->aha1542_last_mbi_used; do { mbi++; if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES; } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used && mb[mbi].status == 0); mbistatus = mb[mbi].status; mb[mbi].status = 0; if(mbistatus == 0){ restore_flags(flags); if (flag & MBIF) printk("aha1542.c: interrupt received, but no mail.\n"); return; } HOSTDATA(shost)->aha1542_last_mbi_used = mbi; mbo = get_ccb_index(mb[mbi].ccbptr, ccb); restore_flags(flags); } if (mbo < 0 || mbo >= AHA1542_MAILBOXES) { printk("aha1542.c: bad mbo (%d)??\n", mbo); return; } errstatus = 0; switch(mbistatus) { case 3: /* Aborted command not found */ printk("aha1542.c: cannot find command to abort\n"); /* maybe it just completed */ return; case 2: /* ccb aborted by host */ printk("abort succeeded - ccb[%d].op=%x idlun=%x\n", mbo, ccb[mbo].op, ccb[mbo].idlun); break; case 0: /* impossible */ case 0x10: /* Adaptec was addressed as target */ default: errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); printk("aha1542.c: unexpected mbistatus %x? errstatus=%x\n", mbistatus, errstatus); return; case 4: /* ccb completed with error */ errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); #ifdef DEBUG printk("aha1542.c: I/O error mbo=%d tarstat=%x hastat=%x" " idlun=%x\n", mbo, ccb[mbo].tarstat, ccb[mbo].hastat, ccb[mbo].idlun); #endif break; case 1: /* ccb completed without error */ break; } SCtmp = HOSTDATA(shost)->SCint[mbo]; if (!SCtmp || !SCtmp->scsi_done) { printk("aha1542_intr_handle: Unexpected interrupt\n"); printk("tarstat=%x, hastat=%x idlun=%x mbo=%d mbistatus=%d\n", ccb[mbo].tarstat, ccb[mbo].hastat, ccb[mbo].idlun, mbo, mbistatus); return; } if (SCtmp->host_scribble) { scsi_free(SCtmp->host_scribble, 512); SCtmp->host_scribble = 0; } switch (ccb[mbo].tarstat) { case 0: /* good status */ break; case 8: /* LUN busy */ printk("aha1542.c: surprising: LUN is busy, " "but got interrupt nevertheless\n"); break; default: printk("aha1542.c: undocumented tarstat %x\n", ccb[mbo].tarstat); break; case 2: /* check status */ /* Fetch the sense data, and tuck it away, in the required slot. The Adaptec automatically fetches it, and there is no guarantee that we will still have it in the cdb when we come back */ memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], sizeof(SCtmp->sense_buffer)); /* #ifdef DEBUG */ #if 1 /* Skip messages on Logical Unit not Supported */ if (!(SCtmp->sense_buffer[12] == 0x25 && SCtmp->sense_buffer[13] == 0)) { int i; printk("aha1542_intr_handle: sense:"); for (i = 0; i < sizeof(SCtmp->sense_buffer); i++) printk(" %02x", SCtmp->sense_buffer[i]); printk("\n"); print_sense("xx", SCtmp); } #endif } /* RJF - catch for EOM/EOF -- not really an error so we don't want the error handler to run */ /* bit 0x80: Filemark (or setmark) */ /* bit 0x40: End of Medium */ if ((SCtmp->sense_buffer[2] & 0x40) || (SCtmp->sense_buffer[2] & 0x80)) errstatus = (DID_PASSTHROUGH << 16) | ccb[mbo].tarstat; SCtmp->result = errstatus; HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as far as queuecommand is concerned */ if (SCtmp->scsi_done) (SCtmp->scsi_done)(SCtmp); else printk("aha1542_intr_handle: scsi_done NULL?\n"); } } /* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */ static void do_aha1542_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); aha1542_intr_handle(irq, dev_id, regs); spin_unlock_irqrestore(&io_request_lock, flags); } int /* used in hosts.c */ aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) { unchar ahacmd = CMD_START_SCSI; unchar direction; unchar *cmd = (unchar *) SCpnt->cmnd; unchar target = SCpnt->target; unchar lun = SCpnt->lun; void *buff = SCpnt->request_buffer; int bufflen = SCpnt->request_bufflen; int mbo; struct mailbox * mb; struct ccb *ccb; mb = HOSTDATA(SCpnt->host)->mb; ccb = HOSTDATA(SCpnt->host)->ccb; if(*cmd == REQUEST_SENSE){ /* Don't do the command - we have the sense data already */ #if 0 /* scsi_request_sense() provides a buffer of size 256, so there is no reason to expect equality */ if (bufflen != sizeof(SCpnt->sense_buffer)) printk("aha1542: Wrong buffer length supplied " "for request sense (%d)\n", bufflen); #endif SCpnt->result = 0; done(SCpnt); return 0; } /* Use the outgoing mailboxes in a round-robin fashion, because this is how the host adapter will scan for them */ mbo = get_next_unused_mbo(SCpnt); memset(&ccb[mbo], 0, sizeof(struct ccb)); ccb[mbo].cdblen = SCpnt->cmd_len; direction = 0; if (*cmd == READ_10 || *cmd == READ_6) direction = 8; else if (*cmd == WRITE_10 || *cmd == WRITE_6) direction = 16; memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); if (SCpnt->use_sg) { struct scatterlist * sgpnt; struct chain * cptr; int i; ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather*/ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); sgpnt = (struct scatterlist *) SCpnt->request_buffer; cptr = (struct chain *) SCpnt->host_scribble; if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n"); for(i=0; iuse_sg; i++) { if(sgpnt[i].length == 0 || SCpnt->use_sg > 16 || (((int)sgpnt[i].address) & 1) || (sgpnt[i].length & 1)){ unsigned char * ptr; printk("Bad segment list supplied to aha1542.c" " (%d, %d)\n", SCpnt->use_sg, i); for(i=0;iuse_sg;i++){ printk("%d: %x %x %d\n", i, (unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address, sgpnt[i].length); } printk("cptr %x: ",(unsigned int) cptr); ptr = (unsigned char *) &cptr[i]; for(i=0;i<18;i++) printk("%02x ", ptr[i]); panic("Foooooooood fight!"); } addr_to_scsi(cptr[i].dataptr, sgpnt[i].address); check_past_dma_threshold(sgpnt[i].address, sgpnt[i].length, "sgpnt"); any2scsi(cptr[i].datalen, sgpnt[i].length); } any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); addr_to_scsi(ccb[mbo].dataptr, cptr); #ifdef DEBUG { unsigned char *ptr; printk("cptr %x: ",cptr); ptr = (unsigned char *) cptr; for(i=0;i<18;i++) printk("%02x ", ptr[i]); } #endif } else { ccb[mbo].op = 0; /* SCSI Initiator Command */ SCpnt->host_scribble = NULL; any2scsi(ccb[mbo].datalen, bufflen); if(buff) check_past_dma_threshold(buff, bufflen, "buff"); addr_to_scsi(ccb[mbo].dataptr, buff); } ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); ccb[mbo].rsalen = 16; ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; ccb[mbo].commlinkid = 0; #ifdef DEBUG { int i; printk("aha1542_queuecommand: sending.. "); for (i = 0; i < sizeof(ccb[mbo])-10; i++) printk("%02x ", ((unchar *)&ccb[mbo])[i]); } #endif if (done) { #ifdef DEBUG printk("aha1542_queuecommand: now waiting for interrupt "); #endif SCpnt->scsi_done = done; mb[mbo].status = 1; aha1542_out(SCpnt->host->io_port, &ahacmd, 1); } else printk("aha1542_queuecommand: done can't be NULL\n"); return 0; } static void internal_done(Scsi_Cmnd * SCpnt) { SCpnt->SCp.Status++; } int aha1542_command(Scsi_Cmnd * SCpnt) { SCpnt->SCp.Status = 0; aha1542_queuecommand(SCpnt, internal_done); while (!SCpnt->SCp.Status) barrier(); return SCpnt->result; } /* Only used at boot time, before interrupts have been set up */ #define AHA1542_IO_SILENT 1 #define AHA1542_IO_FLUSHCT 1000 #define AHA1542_IO_DEF_TIMEOUT 1000 /* 1000 ms = 1 s */ #define AHA1542_IO_DELAY 50 /* us to wait between status reads */ /* often we need 200 us or so */ #define A AHA1542_IO_DELAY /* We need a NOP to clear an earlier invalid command */ static int aha1542_doNOP(int base) { int t = (1000/A)*AHA1542_IO_DEF_TIMEOUT; aha1542_intr_reset(base); while (inb(STATUS(base)) & CDF) { if (!t--) goto fail; udelay(A); } outb (CMD_NOP, DATA(base)); while ((inb(INTRFLAGS(base)) & HACC) == 0) { if (!t--) goto fail; udelay(A); } return 0; fail: return 1; } /* the INVDCMD bit is valid only while HACC is raised */ static int aha1542_is_invalid(int base) { if (inb(INTRFLAGS(base)) & HACC) { if (inb(STATUS(base)) & INVDCMD) aha1542_doNOP(base); aha1542_intr_reset(base); return 1; } return 0; } static int aha1542_io(int base, unchar *cmd, int cmdlth, unchar *res, int reslth, int flags) { int i; int t = (1000/A)*AHA1542_IO_DEF_TIMEOUT; /* total allowed */ /* Wait until idle, except for commands 02 and 05 */ if (*cmd != CMD_START_SCSI && *cmd != CMD_EMBOI) { while ((inb(STATUS(base)) & IDLE) == 0) { if (!t--) goto fail; /* status bit stuck at 0 */ udelay(A); } } /* flush any bytes waiting, just to be sure */ if (inb(STATUS(base)) & DF) { int ct = AHA1542_IO_FLUSHCT; printk("aha1542_io: unexpected bytes waiting?\n"); do { if (!ct--) goto fail; /* status bit stuck at 1 */ i = inb(DATA(base)); mdelay(1); /* long enough */ } while (inb(STATUS(base)) & DF); } /* now see whether the previous command left garbage behind */ /* (maybe it had too many command bytes) */ if (aha1542_is_invalid(base)) printk("aha1542_io: previous command left garbage.\n"); /* write command */ while (cmdlth--) { while (inb(STATUS(base)) & CDF) { if (!t--) goto fail; udelay(A); } if (aha1542_is_invalid(base)) goto invalid; /* previous byte invalid */ outb (*cmd++, DATA(base)); } /* read any required result */ while (reslth--) { while (1) { if (aha1542_is_invalid(base)) goto invalid; /* last cmd byte was invalid */ if (inb(STATUS(base)) & DF) break; if (!t--) goto fail; udelay(A); } *res++ = inb(DATA(base)); } /* wait for completion */ while ((inb(INTRFLAGS(base)) & HACC) == 0) { if (inb(STATUS(base)) & DF) { printk("aha1542_io: Unexpected additional output\n"); inb(DATA(base)); } if (!t--) goto fail; udelay(A); } aha1542_intr_reset(base); #if 0 /* In case of too many command bytes, the first stat shows intr=0, the second HACC */ aha1542_stat(base); aha1542_stat(base); #endif return 0; invalid: /* command like CMD_EXTBIOS not recognized by present board */ if (!(flags & AHA1542_IO_SILENT)) printk("aha1542_io: invalid command\n"); if (aha1542_doNOP(base)) goto fail; aha1542_intr_reset(base); return 1; fail: /* got a timeout - not expected ever to happen */ printk("aha1542_io timed out\n"); aha1542_stat(base); aha1542_intr_reset(base); return 1; } #undef A /* Initialize mailboxes */ static int setup_mailboxes(int base, struct Scsi_Host * shpnt) { int i; struct mailbox * mb; struct ccb *ccb; unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; mb = HOSTDATA(shpnt)->mb; ccb = HOSTDATA(shpnt)->ccb; for(i=0; i= 0) { unchar dmacmd[] = {CMD_DMASPEED, 0}; dmacmd[1] = setup_dmaspeed[indx]; if (aha1542_io(base, dmacmd, sizeof(dmacmd), NULL, 0, 0)) printk("aha1542: setting DMA speed failed\n"); } } #if 0 static void aha1542_getsetup(int base) { unchar cmd[] = { CMD_RETSETUP, 16 }; unchar result[16]; int i; if (aha1542_io(base, cmd, sizeof(cmd), result, sizeof(result), 0)) return; /* failed */ printk("parity %x speed %x buson %x busoff %x", result[0], result[1], result[2], result[3]); printk(" #mb %x addr %lx\n", result[4], scsi2int(result+5)); printk("syncs:"); for (i=0; i<8; i++) printk(" id %d:%x", i, result[8+i]); printk("\n"); } /* * Probing for devices is really unnecessary - the Host Adapter * is willing to give us precise information. Unfortunately, there * is no facility in the higher SCSI layers yet to make use cof this. */ static void aha1542_getdevs(int base) { unchar cmd[] = { CMD_RETDEVS }; unchar result[8]; int i, j; if (aha1542_io(base, cmd, sizeof(cmd), result, sizeof(result), 0)) return; /* failed */ for(i=0; i<8; i++) for(j=0; j<8; j++) if(result[i] & (1< 1 GByte" is enabled. extbios_result[1] is either 0 or 1 or 2 - the precise conditions are unclear. Nick Andrew (nick@zeta.org.au) reports that it is 2 for the 1542-CP with a big disk, is 1 for the 1542-CF with a big disk and extended translation, and is 0 otherwise. I (aeb@cwi.nl) find 2 when at least one of "Dynamically Scan SCSI Bus" and "BIOS support for more than 2 drives" is enabled, 1 if not, but extended translation is enabled, and 0 when all three are disabled. I also find 0 when "BIOS" is disabled. This is on a 1542-CF with BIOS v2.11. */ if ((extbios_result[0] & 0x08) || extbios_result[1]) { /* Earlier we tested with 0x01, but need 0x03 for AHA1542CP */ if(extbios_result[0] & 0x08) retval = BIOS_TRANSLATION_25563; mbenable_cmd[2] = extbios_result[1]; if (aha1542_io(base, mbenable_cmd, sizeof(mbenable_cmd), NULL, 0, 0)) printk("aha1542_mbenable: Mailbox init failed\n"); } return retval; } /* return x if in 0-9A-Z, a hex form if not */ static void unchar_to_asc(unchar x, char *res) { if (('0' <= x && x <= '9') || ('A' <= x && x <= 'Z')) { res[0] = x; res[1] = 0; } else { sprintf(res, "0x%x", x); } } /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ static int aha1542_query(int base, int * transl) { unchar cmd[] = { CMD_INQUIRY }; unchar result[4]; char *type; int tl; /* BusLogic 545 gets this wrong and returns only one byte, 0x20=' ' [says bsd driver] */ if (aha1542_io(base, cmd, sizeof(cmd), result, sizeof(result), 0)) return 1; /* failed */ *transl = BIOS_TRANSLATION_6432; /* Default case */ switch (result[0]) { case 0: type="AHA-1540 with 16 Head BIOS"; *transl = BIOS_TRANSLATION_1632; break; case 0x30: case 0x31: type="AHA-1540"; break; case 0x41: type="AHA-1540A/1542A/1542B"; break; case 0x42: type="AHA-1640"; break; case 0x43: type="AHA-1740A/1742A/1744"; break; /* also 1542C ? */ case 0x44: type="AHA-1542C"; break; /* or old AHA-1542CF ? */ case 0x45: type="AHA-1542CF"; break; /* only BIOS v2.01 or later ? */ case 0x46: type="AHA-1542CP, PnP"; break; default: type="unknown"; } /* For the options field, 0x41='A' is documented to be the standard. I find fields A005 - aeb. */ { char res[4][5]; int i; for (i=0; i<4; i++) unchar_to_asc(result[i], res[i]); printk("aha1542: board %s (%s) options %s firmware %s.%s\n", res[0], type, res[1], res[2], res[3]); } /* For an AHA1740 series board, we ignore the board since there is a hardware bug which can lead to wrong blocks being returned if the board is operating in the 1542 emulation mode. Since there is an extended mode driver, we simply ignore the board and let the 1740 driver pick it up. */ if (result[0] == 0x43) { printk("aha1542.c: Emulation mode not supported " "for AHA 174N hardware.\n"); return 1; } /* Always call this - boards that do not support extended bios translation will ignore the command, and we will set the proper default */ tl = aha1542_mbenable(base); if (tl != BIOS_TRANSLATION_UNKN) *transl = tl; return 0; } int to_dmaspeed(int a) { int atbt = -1; switch (a) { case 5: atbt = 0x00; break; case 6: atbt = 0x04; break; case 7: atbt = 0x01; break; case 8: atbt = 0x02; break; case 10: atbt = 0x03; break; } return atbt; } /* called from init/main.c */ __initfunc(void aha1542_setup( char *str, int *ints)) { const char *ahausage = "aha1542: usage: aha1542=[,,[,]]\n"; static int setup_idx = 0; int setup_portbase; if(setup_idx >= MAXBOARDS) { printk("aha1542: aha1542_setup called too many times! Bad LILO params ?\n"); printk(" Entryline 1: %s\n",setup_str[0]); printk(" Entryline 2: %s\n",setup_str[1]); printk(" This line: %s\n",str); return; } if (ints[0] < 1 || ints[0] > 4) { printk("aha1542: %s\n", str ); printk(ahausage); printk("aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n"); } setup_called[setup_idx]=ints[0]; setup_str[setup_idx]=str; setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */ setup_buson [setup_idx] = ints[0] >= 2 ? ints[2] : 7; setup_busoff [setup_idx] = ints[0] >= 3 ? ints[3] : 5; if (ints[0] >= 4) { int atbt = to_dmaspeed(ints[4]); if (atbt == -1) { printk("aha1542: %s\n", str ); printk(ahausage); printk("aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. " "Using jumper defaults.\n"); } setup_dmaspeed[setup_idx] = atbt; } if (setup_portbase != 0) bases[setup_idx] = setup_portbase; ++setup_idx; } /* return non-zero on detection */ static int aha1542_detect_one(Scsi_Host_Template * tpnt, int indx) { unsigned char dma_chan; unsigned char irq_level; unsigned char scsi_id; unsigned long flags; unsigned int base; int trans; struct Scsi_Host * shpnt = NULL; shpnt = scsi_register(tpnt, sizeof(struct aha1542_hostdata)); /* For now we do this - until kmalloc is more intelligent we are resigned to stupid hacks like this */ if (check_past_dma_threshold((char *)(HOSTDATA(shpnt)), sizeof(struct aha1542_hostdata), NULL)) { printk("Invalid address for shpnt with 1542.\n"); goto unregister; } if (!aha1542_test_port(bases[indx], shpnt)) goto unregister; base = bases[indx]; set_bus_onoff_times(base, indx); if (aha1542_query(base, &trans)) goto unregister; if (aha1542_getconfig(base, &irq_level, &dma_chan, &scsi_id) == -1) goto unregister; printk("Configuring Adaptec (SCSI-ID %d) at IO:%x, " "IRQ %d", scsi_id, base, irq_level); if (dma_chan != 0xFF) printk(", DMA priority %d", dma_chan); printk("\n"); #if 0 aha1542_getdevs(base); aha1542_getsetup(base); #endif if (setup_mailboxes(base, shpnt)) { printk("aha1542: failed setting up mailboxes\n"); goto unregister; } save_flags(flags); cli(); if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) { printk("Unable to allocate IRQ for Adaptec controller.\n"); restore_flags(flags); goto unregister; } if (dma_chan != 0xFF) { if (request_dma(dma_chan,"aha1542")) { printk("Unable to allocate DMA channel" " for Adaptec controller.\n"); free_irq(irq_level, NULL); restore_flags(flags); goto unregister; } if (dma_chan == 0 || dma_chan >= 5) { set_dma_mode(dma_chan, DMA_MODE_CASCADE); enable_dma(dma_chan); } } aha_host[irq_level - 9] = shpnt; shpnt->this_id = scsi_id; shpnt->unique_id = base; shpnt->io_port = base; shpnt->n_io_port = 4; /* Number of bytes of I/O space used */ shpnt->dma_channel = dma_chan; shpnt->irq = irq_level; HOSTDATA(shpnt)->bios_translation = trans; if(trans == BIOS_TRANSLATION_25563) printk("aha1542.c: Using extended bios translation\n"); HOSTDATA(shpnt)->aha1542_last_mbi_used = (2*AHA1542_MAILBOXES - 1); HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1); memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint)); restore_flags(flags); #if 0 #ifdef DEBUG printk(" *** READ CAPACITY ***\n"); #endif { unchar buf[8]; static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int i; for (i = 0; i < sizeof(buf); ++i) buf[i] = 0x87; for (i = 0; i < 2; ++i) if (!aha1542_command(i, cmd, buf, sizeof(buf))) { printk("aha_detect: LU %d sector_size %d device_size %d\n", i, xscsi2int(buf+4), xscsi2int(buf)); } } #ifdef DEBUG printk(" *** NOW RUNNING MY OWN TEST *** \n"); #endif for (i = 0; i < 4; ++i) { unsigned char cmd[10]; static buffer[512]; cmd[0] = READ_10; cmd[1] = 0; xany2scsi(cmd+2, i); cmd[6] = 0; cmd[7] = 0; cmd[8] = 1; cmd[9] = 0; aha1542_command(0, cmd, buffer, 512); } #endif /* Register the IO ports that we use */ request_region(bases[indx], 4, "aha1542"); return 1; unregister: scsi_unregister(shpnt); return 0; } int aha1542_detect(Scsi_Host_Template * tpnt) { int indx; int count = 0; #ifdef DEBUG printk("aha1542_detect: \n"); #endif tpnt->proc_dir = &proc_scsi_aha1542; #ifdef MODULE bases[0] = aha1542[0]; setup_buson[0] = aha1542[1]; setup_busoff[0] = aha1542[2]; setup_dmaspeed[0] = to_dmaspeed(aha1542[3]); #endif for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++) if(bases[indx] != 0 && !check_region(bases[indx], 4)) if (aha1542_detect_one(tpnt, indx)) count++; return count; } static int aha1542_restart(struct Scsi_Host * shost) { int i; int count = 0; #if 0 unchar ahacmd = CMD_START_SCSI; #endif for(i=0; i< AHA1542_MAILBOXES; i++) if(HOSTDATA(shost)->SCint[i] && !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) { #if 0 /* Indicate ready to restart... */ HOSTDATA(shost)->mb[i].status = 1; #endif count++; } printk("Potential to restart %d stalled commands...\n", count); #if 0 /* start scsi command */ if (count) aha1542_out(shost->io_port, &ahacmd, 1); #endif return 0; } /* Called from scsi_error with io_request_lock held */ #define AHA1542_ABORT_TIMEOUT 1000000 /* 1000000 us = 1 s */ int aha1542_abort(Scsi_Cmnd * SCpnt) { struct aha1542_hostdata *hostdata = HOSTDATA(SCpnt->host); struct mailbox *mb = hostdata->mb; int mbo, rtn; static void (*donefn)(Scsi_Cmnd *); int timeout; unchar ahacmd = CMD_START_SCSI; /* Which mailbox did we use? Didnt we write this someplace? */ /* We do not need the mailbox, just the ccb that is still there */ for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) if (hostdata->SCint[mbo] == SCpnt) goto gotit; printk("aha1542_abort: cannot find job to abort\n"); return FAILED; gotit: printk("Trying to abort mbo %d for target %d\n", mbo, SCpnt->target); /* We must wait for actual completion of the abort */ /* For the time being, let us use somewhat busy waiting */ /* Experience so far: needed 267-542 us aborting a CDROM read */ donefn = SCpnt->scsi_done; /* save old fn */ SCpnt->scsi_done = internal_done; SCpnt->SCp.Status = 0; mb[mbo].status = 2; /* abort */ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); timeout = AHA1542_ABORT_TIMEOUT; while (!SCpnt->SCp.Status && timeout--) { spin_unlock_irq(&io_request_lock); udelay(1L); /* scsi_sleep() causes kernel panic */ spin_lock_irq(&io_request_lock); } if (timeout < 0) { printk("aha1542_abort timed out\n"); return FAILED; } if (SCpnt->result) { printk("aha1542_abort: FAILED, result 0x%x, " "microsecs used %d\n", SCpnt->result, AHA1542_ABORT_TIMEOUT - timeout); rtn = FAILED; } else { SCpnt->result = (DID_ABORT << 16); printk("aha1542_abort: SUCCESS, microsecs used %d\n", AHA1542_ABORT_TIMEOUT - timeout); rtn = SUCCESS; } SCpnt->scsi_done = donefn; if (donefn) donefn(SCpnt); else printk("aha1542_abort: no donefn?\n"); return rtn; } int aha1542_dev_reset(Scsi_Cmnd * SCpnt) { Scsi_Cmnd BDR; unchar target = SCpnt->target; unchar lun = SCpnt->lun; struct mailbox * mb; int mbo; struct ccb *ccb; unchar ahacmd = CMD_START_SCSI; int timeout; /* Set up a private SCSI command, to avoid races */ /* No fields other than those mentioned here, will be touched */ BDR.host = SCpnt->host; BDR.target = target; BDR.lun = lun; BDR.scsi_done = internal_done; BDR.SCp.Status = 0; BDR.result = -1; BDR.host_scribble = NULL; memset(BDR.sense_buffer, 0, sizeof(BDR.sense_buffer)); ccb = HOSTDATA(SCpnt->host)->ccb; mb = HOSTDATA(SCpnt->host)->mb; mbo = get_next_unused_mbo(&BDR); memset(&ccb[mbo], 0, sizeof(struct ccb)); ccb[mbo].op = 0x81; /* BUS DEVICE RESET */ ccb[mbo].idlun = (target&7)<<5 | (lun & 7); /* SCSI Target Id */ ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; ccb[mbo].commlinkid = 0; /* * Now tell the 1542 to flush all pending commands for this * target. We get mail (with status 1) when done. */ mb[mbo].status = 1; aha1542_out(BDR.host->io_port, &ahacmd, 1); printk("Sent BUS DEVICE RESET to target %d (mbo=%d)\n", target, mbo); /* We must wait for actual completion of the bus device reset */ /* Also need a timeout */ /* for the time being, let us use somewhat busy waiting */ /* surely nothing will happen if we do not drop the lock */ timeout = 1*HZ; /* 1 s - in reality 0.1 sec seems enough */ while (!BDR.SCp.Status && timeout--) scsi_sleep(1); if (timeout < 0) { printk("aha1542_dev_reset timed out.. BAD..\n"); /* But there is still a pointer to BDR... */ /* Maybe abort the reset?? */ return FAILED; } printk("aha1542_dev_reset result %x, tics used %d\n", BDR.result, 1*HZ - timeout); return BDR.result ? BDR.result : SUCCESS; } int aha1542_bus_reset(Scsi_Cmnd * SCpnt) { int i; #ifdef STAY_ALIVE /* * The scsi_error code wants to do all kinds of terrible things * when a CDROM is bad, or a tape is BAD, or a scanner reacts * not quite as it should. * It is however impossible to force things. Some SCSI devices * (especially scanners) do not implement the full SCSI standard, * and errors do not always go away upon abort / device reset. * Continuing with bus reset only makes things worse. */ printk("Someone wants a bus reset, but that kills the system, " "so I am not going to do that\n"); return SUCCESS; #endif /* * This does a scsi reset for all devices on the bus. * In principle, we could also reset the 1542 - should * we do this? Try this first, and we can add that later * if it turns out to be useful. */ outb(SCRST, CONTROL(SCpnt->host->io_port)); /* * Wait for the thing to settle down a bit. Unfortunately * this is going to basically lock up the machine while we * wait for this to complete. To be 100% correct, we need to * check for timeout, and if we are doing something like this * we are pretty desperate anyways. */ scsi_sleep(4*HZ); WAIT(STATUS(SCpnt->host->io_port), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF); /* * Now try to pick up the pieces. For all pending commands, * free any internal data structures, and basically clear things * out. We do not try and restart any commands or anything - * the strategy handler takes care of that crap. */ printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no); for(i=0; i< AHA1542_MAILBOXES; i++) { if(HOSTDATA(SCpnt->host)->SCint[i] != NULL) { Scsi_Cmnd * SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; if( SCtmp->device->soft_reset ) { /* * If this device implements the soft reset option, * then it is still holding onto the command, and * may yet complete it. In this case, we don't * flush the data. */ continue; } if (SCtmp->host_scribble) { scsi_free(SCtmp->host_scribble, 512); SCtmp->host_scribble = NULL; } HOSTDATA(SCpnt->host)->SCint[i] = NULL; HOSTDATA(SCpnt->host)->mb[i].status = 0; } } return SUCCESS; fail: return FAILED; } int aha1542_host_reset(Scsi_Cmnd * SCpnt) { int i; #ifdef STAY_ALIVE printk("Someone wants a host reset, but that crashes the system, " "so I am not going to do that\n"); return SUCCESS; #endif /* * This does a scsi reset for all devices on the bus. * In principle, we could also reset the 1542 - should * we do this? Try this first, and we can add that later * if it turns out to be useful. */ outb(HRST | SCRST, CONTROL(SCpnt->host->io_port)); /* * Wait for the thing to settle down a bit. Unfortunately * this is going to basically lock up the machine while we * wait for this to complete. To be 100% correct, we need to * check for timeout, and if we are doing something like this * we are pretty desperate anyways. */ scsi_sleep(4*HZ); WAIT(STATUS(SCpnt->host->io_port), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF); /* * We need to do this too before the 1542 can interact with * us again. */ setup_mailboxes(SCpnt->host->io_port, SCpnt->host); /* * Now try to pick up the pieces. For all pending commands, * free any internal data structures, and basically clear things * out. We do not try and restart any commands or anything - * the strategy handler takes care of that crap. */ printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no); for(i=0; i< AHA1542_MAILBOXES; i++) { if(HOSTDATA(SCpnt->host)->SCint[i] != NULL) { Scsi_Cmnd * SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; if( SCtmp->device->soft_reset ) { /* * If this device implements the soft reset option, * then it is still holding onto the command, and * may yet complete it. In this case, we don't * flush the data. */ continue; } if (SCtmp->host_scribble) { scsi_free(SCtmp->host_scribble, 512); SCtmp->host_scribble = NULL; } HOSTDATA(SCpnt->host)->SCint[i] = NULL; HOSTDATA(SCpnt->host)->mb[i].status = 0; } } return SUCCESS; fail: return FAILED; } /* * These are the old error handling routines. */ int aha1542_old_abort(Scsi_Cmnd * SCpnt) { printk("aha1542_old_abort called?\n"); return SCSI_ABORT_SNOOZE; } /* We do not implement a reset function here, but the upper level code assumes that it will get some kind of response for the command in SCpnt. We must oblige, or the command will hang the scsi system. For a first go, we assume that the 1542 notifies us with all of the pending commands (it does implement soft reset, after all). */ int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) { unchar ahacmd = CMD_START_SCSI; int i; printk("aha1542_old_reset called?\n"); /* * See if a bus reset was suggested. */ if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) { /* * This does a scsi reset for all devices on the bus. * In principle, we could also reset the 1542 - should * we do this? Try this first, and we can add that later * if it turns out to be useful. */ outb(HRST | SCRST, CONTROL(SCpnt->host->io_port)); /* * Wait for the thing to settle down a bit. Unfortunately * this is going to basically lock up the machine while we * wait for this to complete. To be 100% correct, we need to * check for timeout, and if we are doing something like this * we are pretty desperate anyways. */ WAIT(STATUS(SCpnt->host->io_port), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF); /* * We need to do this too before the 1542 can interact with * us again. */ setup_mailboxes(SCpnt->host->io_port, SCpnt->host); /* * Now try to pick up the pieces. Restart all commands * that are currently active on the bus, and reset all of * the datastructures. We have some time to kill while * things settle down, so print a nice message. */ printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no); for(i=0; i< AHA1542_MAILBOXES; i++) if(HOSTDATA(SCpnt->host)->SCint[i] != NULL) { Scsi_Cmnd * SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; SCtmp->result = DID_RESET << 16; if (SCtmp->host_scribble) { scsi_free(SCtmp->host_scribble, 512); SCtmp->host_scribble = NULL; } printk("Sending DID_RESET for target %d\n", SCpnt->target); SCtmp->scsi_done(SCpnt); HOSTDATA(SCpnt->host)->SCint[i] = NULL; HOSTDATA(SCpnt->host)->mb[i].status = 0; } /* * Now tell the mid-level code what we did here. Since * we have restarted all of the outstanding commands, * then report SUCCESS. */ return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); fail: printk("aha1542.c: Unable to perform hard reset.\n"); printk("Power cycle machine to reset\n"); return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET); } else { /* This does a selective reset of just the one device */ /* First locate the ccb for this command */ for(i=0; i< AHA1542_MAILBOXES; i++) if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { HOSTDATA(SCpnt->host)->ccb[i].op = 0x81; /* BUS DEVICE RESET */ /* Now tell the 1542 to flush all pending commands for this target */ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* Here is the tricky part. What to do next. Do we get an interrupt for the commands that we aborted with the specified target, or do we generate this on our own? Try it without first and see what happens */ printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target); /* If the first does not work, then try the second. I think the first option is more likely to be correct. Free the command block for all commands running on this target... */ for(i=0; i< AHA1542_MAILBOXES; i++) if(HOSTDATA(SCpnt->host)->SCint[i] && HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) { Scsi_Cmnd * SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; SCtmp->result = DID_RESET << 16; if (SCtmp->host_scribble) { scsi_free(SCtmp->host_scribble, 512); SCtmp->host_scribble = NULL; } printk("Sending DID_RESET for target %d\n", SCpnt->target); SCtmp->scsi_done(SCpnt); HOSTDATA(SCpnt->host)->SCint[i] = NULL; HOSTDATA(SCpnt->host)->mb[i].status = 0; } return SCSI_RESET_SUCCESS; } } /* No active command at this time, so this means that each time we got some kind of response the last time through. Tell the mid-level code to request sense information in order to decide what to do next. */ return SCSI_RESET_PUNT; } #include "sd.h" int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int * ip) { int translation_algorithm; int size = disk->capacity; translation_algorithm = HOSTDATA(disk->device->host)->bios_translation; if((size>>11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) { /* Please verify that this is the same as what DOS returns */ ip[0] = 255; ip[1] = 63; ip[2] = size /255/63; } else if (translation_algorithm == BIOS_TRANSLATION_1632) { ip[0] = 16; ip[1] = 32; ip[2] = size >> 9; } else { ip[0] = 64; ip[1] = 32; ip[2] = size >> 11; } return 0; } #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ Scsi_Host_Template driver_template = AHA1542; #include "scsi_module.c" #endif