AM53C974.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:89k
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/signal.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/pci.h>
- #include <linux/string.h>
- #include <linux/blk.h>
- #include <linux/init.h>
- #include <linux/spinlock.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #include "scsi.h"
- #include "hosts.h"
- #include "AM53C974.h"
- #include "constants.h"
- #include "sd.h"
- /* AM53/79C974 (PCscsi) driver release 0.5
- * The architecture and much of the code of this device
- * driver was originally developed by Drew Eckhardt for
- * the NCR5380. The following copyrights apply:
- * For the architecture and all pieces of code which can also be found
- * in the NCR5380 device driver:
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
- *
- * The AM53C974_nobios_detect code was originally developed by
- * Robin Cutshaw (robin@xfree86.org) and is used here in a
- * slightly modified form.
- *
- * PCI detection rewritten by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *
- * For the remaining code:
- * Copyright 1994, D. Frieauff
- * EMail: fri@rsx42sun0.dofn.de
- * Phone: x49-7545-8-2256 , x49-7541-42305
- */
- /*
- * $Log: AM53C974.c,v $
- */
- #ifdef AM53C974_DEBUG
- #define DEB(x) x
- #ifdef AM53C974_DEBUG_KEYWAIT
- #define KEYWAIT() AM53C974_keywait()
- #else
- #define KEYWAIT()
- #endif
- #ifdef AM53C974_DEBUG_INIT
- #define DEB_INIT(x) x
- #else
- #define DEB_INIT(x)
- #endif
- #ifdef AM53C974_DEBUG_MSG
- #define DEB_MSG(x) x
- #else
- #define DEB_MSG(x)
- #endif
- #ifdef AM53C974_DEB_RESEL
- #define DEB_RESEL(x) x
- #else
- #define DEB_RESEL(x)
- #endif
- #ifdef AM53C974_DEBUG_QUEUE
- #define DEB_QUEUE(x) x
- #define LIST(x,y) {printk("LINE:%d Adding %p to %pn", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
- #define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
- #else
- #define DEB_QUEUE(x)
- #define LIST(x,y)
- #define REMOVE(w,x,y,z)
- #endif
- #ifdef AM53C974_DEBUG_INFO
- #define DEB_INFO(x) x
- #else
- #define DEB_INFO(x)
- #endif
- #ifdef AM53C974_DEBUG_LINKED
- #define DEB_LINKED(x) x
- #else
- #define DEB_LINKED(x)
- #endif
- #ifdef AM53C974_DEBUG_INTR
- #define DEB_INTR(x) x
- #else
- #define DEB_INTR(x)
- #endif
- #else
- #define DEB_INIT(x)
- #define DEB(x)
- #define DEB_QUEUE(x)
- #define LIST(x,y)
- #define REMOVE(w,x,y,z)
- #define DEB_INFO(x)
- #define DEB_LINKED(x)
- #define DEB_INTR(x)
- #define DEB_MSG(x)
- #define DEB_RESEL(x)
- #define KEYWAIT()
- #endif
- #ifdef AM53C974_DEBUG_ABORT
- #define DEB_ABORT(x) x
- #else
- #define DEB_ABORT(x)
- #endif
- #ifdef VERBOSE_AM53C974_DEBUG
- #define VDEB(x) x
- #else
- #define VDEB(x)
- #endif
- #define INSIDE(x,l,h) ( ((x) >= (l)) && ((x) <= (h)) )
- #include <scsi/scsicam.h>
- /***************************************************************************************
- * Default setting of the controller's SCSI id. Edit and uncomment this only if your *
- * BIOS does not correctly initialize the controller's SCSI id. *
- * If you don't get a warning during boot, it is correctly initialized. *
- ****************************************************************************************/
- /* #define AM53C974_SCSI_ID 7 */
- /***************************************************************************************
- * Default settings for sync. negotiation enable, transfer rate and sync. offset. *
- * These settings can be replaced by LILO overrides (append) with the following syntax: *
- * AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offset *
- * Sync. negotiation is disabled by default and will be enabled for those targets which *
- * are specified in the LILO override *
- ****************************************************************************************/
- #define DEFAULT_SYNC_NEGOTIATION_ENABLED 0 /* 0 or 1 */
- #define DEFAULT_RATE 5 /* MHz, min: 3; max: 10 */
- #define DEFAULT_SYNC_OFFSET 0 /* bytes, min: 0; max: 15; use 0 for async. mode */
- /***************************************************************************************
- * If defined, don't allow targets to disconnect during commands. This will reduce *
- * performance, but may be worthwhile if you suspect the driver of corrupting data when *
- * a disconnect happens. *
- ***************************************************************************************/
- #define AM53C974_PROHIBIT_DISCONNECT
- /* --------------------- don't edit below here --------------------- */
- #define AM53C974_DRIVER_REVISION_MAJOR 0
- #define AM53C974_DRIVER_REVISION_MINOR 5
- #define SEPARATOR_LINE
- "--------------------------------------------------------------------------n"
- /* debug control */
- /* #define AM53C974_DEBUG */
- /* #define AM53C974_DEBUG_MSG */
- /* #define AM53C974_DEBUG_KEYWAIT */
- /* #define AM53C974_DEBUG_INIT */
- /* #define AM53C974_DEBUG_QUEUE */
- /* #define AM53C974_DEBUG_INFO */
- /* #define AM53C974_DEBUG_LINKED */
- /* #define VERBOSE_AM53C974_DEBUG */
- /* #define AM53C974_DEBUG_INTR */
- /* #define AM53C974_DEB_RESEL */
- #define AM53C974_DEBUG_ABORT
- /* #define AM53C974_OPTION_DEBUG_PROBE_ONLY */
- /* special options/constants */
- #define DEF_CLK 40 /* chip clock freq. in MHz */
- #define MIN_PERIOD 4 /* for negotiation: min. number of clocks per cycle */
- #define MAX_PERIOD 13 /* for negotiation: max. number of clocks per cycle */
- #define MAX_OFFSET 15 /* for negotiation: max. offset (0=async) */
- #define DEF_SCSI_TIMEOUT 245 /* STIMREG value, 40 Mhz */
- #define DEF_STP 8 /* STPREG value assuming 5.0 MB/sec, FASTCLK, FASTSCSI */
- #define DEF_SOF_RAD 0 /* REQ/ACK deassertion delay */
- #define DEF_SOF_RAA 0 /* REQ/ACK assertion delay */
- #define DEF_ETM 0 /* CNTLREG1, ext. timing mode */
- #define DEF_PERE 1 /* CNTLREG1, parity error reporting */
- #define DEF_CLKF 0 /* CLKFREG, 0=40 Mhz */
- #define DEF_ENF 1 /* CNTLREG2, enable features */
- #define DEF_ADIDCHK 0 /* CNTLREG3, additional ID check */
- #define DEF_FASTSCSI 1 /* CNTLREG3, fast SCSI */
- #define DEF_FASTCLK 1 /* CNTLREG3, fast clocking, 5 MB/sec at 40MHz chip clk */
- #define DEF_GLITCH 1 /* CNTLREG4, glitch eater, 0=12ns, 1=35ns, 2=25ns, 3=off */
- #define DEF_PWD 0 /* CNTLREG4, reduced power feature */
- #define DEF_RAE 0 /* CNTLREG4, RAE active negation on REQ, ACK only */
- #define DEF_RADE 1 /* 1CNTLREG4, active negation on REQ, ACK and data */
- /*** SCSI block ***/
- #define CTCLREG 0x00 /* r current transf. count, low byte */
- #define CTCMREG 0x04 /* r current transf. count, middle byte */
- #define CTCHREG 0x38 /* r current transf. count, high byte */
- #define STCLREG 0x00 /* w start transf. count, low byte */
- #define STCMREG 0x04 /* w start transf. count, middle byte */
- #define STCHREG 0x38 /* w start transf. count, high byte */
- #define FFREG 0x08 /* rw SCSI FIFO reg. */
- #define STIMREG 0x14 /* w SCSI timeout reg. */
- #define SDIDREG 0x10 /* w SCSI destination ID reg. */
- #define SDIREG_MASK 0x07 /* mask */
- #define STPREG 0x18 /* w synchronous transf. period reg. */
- #define STPREG_STP 0x1F /* synchr. transfer period */
- #define CLKFREG 0x24 /* w clock factor reg. */
- #define CLKFREG_MASK 0x07 /* mask */
- #define CMDREG 0x0C /* rw SCSI command reg. */
- #define CMDREG_DMA 0x80 /* set DMA mode (set together with opcodes below) */
- #define CMDREG_IT 0x10 /* information transfer */
- #define CMDREG_ICCS 0x11 /* initiator command complete steps */
- #define CMDREG_MA 0x12 /* message accepted */
- #define CMDREG_TPB 0x98 /* transfer pad bytes, DMA mode only */
- #define CMDREG_SATN 0x1A /* set ATN */
- #define CMDREG_RATN 0x1B /* reset ATN */
- #define CMDREG_SOAS 0x41 /* select without ATN steps */
- #define CMDREG_SAS 0x42 /* select with ATN steps (1 msg byte) */
- #define CMDREG_SASS 0x43 /* select with ATN and stop steps */
- #define CMDREG_ESR 0x44 /* enable selection/reselection */
- #define CMDREG_DSR 0x45 /* disable selection/reselection */
- #define CMDREG_SA3S 0x46 /* select with ATN 3 steps (3 msg bytes) */
- #define CMDREG_NOP 0x00 /* no operation */
- #define CMDREG_CFIFO 0x01 /* clear FIFO */
- #define CMDREG_RDEV 0x02 /* reset device */
- #define CMDREG_RBUS 0x03 /* reset SCSI bus */
- #define STATREG 0x10 /* r SCSI status reg. */
- #define STATREG_INT 0x80 /* SCSI interrupt condition detected */
- #define STATREG_IOE 0x40 /* SCSI illegal operation error detected */
- #define STATREG_PE 0x20 /* SCSI parity error detected */
- #define STATREG_CTZ 0x10 /* CTC reg decremented to zero */
- #define STATREG_MSG 0x04 /* SCSI MSG phase (latched?) */
- #define STATREG_CD 0x02 /* SCSI C/D phase (latched?) */
- #define STATREG_IO 0x01 /* SCSI I/O phase (latched?) */
- #define STATREG_PHASE 0x07 /* SCSI phase mask */
- #define INSTREG 0x14 /* r interrupt status reg. */
- #define INSTREG_SRST 0x80 /* SCSI reset detected */
- #define INSTREG_ICMD 0x40 /* SCSI invalid command detected */
- #define INSTREG_DIS 0x20 /* target disconnected or sel/resel timeout */
- #define INSTREG_SR 0x10 /* device on bus has service request */
- #define INSTREG_SO 0x08 /* successful operation */
- #define INSTREG_RESEL 0x04 /* device reselected as initiator */
- #define ISREG 0x18 /* r internal state reg. */
- #define ISREG_SOF 0x08 /* synchronous offset flag (act. low) */
- #define ISREG_IS 0x07 /* status of intermediate op. */
- #define ISREG_OK_NO_STOP 0x04 /* selection successful */
- #define ISREG_OK_STOP 0x01 /* selection successful */
- #define CFIREG 0x1C /* r current FIFO/internal state reg. */
- #define CFIREG_IS 0xE0 /* status of intermediate op. */
- #define CFIREG_CF 0x1F /* number of bytes in SCSI FIFO */
- #define SOFREG 0x1C /* w synchr. offset reg. */
- #define SOFREG_RAD 0xC0 /* REQ/ACK deassertion delay (sync.) */
- #define SOFREG_RAA 0x30 /* REQ/ACK assertion delay (sync.) */
- #define SOFREG_SO 0x0F /* synch. offset (sync.) */
- #define CNTLREG1 0x20 /* rw control register one */
- #define CNTLREG1_ETM 0x80 /* set extended timing mode */
- #define CNTLREG1_DISR 0x40 /* disable interrupt on SCSI reset */
- #define CNTLREG1_PERE 0x10 /* enable parity error reporting */
- #define CNTLREG1_SID 0x07 /* host adapter SCSI ID */
- #define CNTLREG2 0x2C /* rw control register two */
- #define CNTLREG2_ENF 0x40 /* enable features */
- #define CNTLREG3 0x30 /* rw control register three */
- #define CNTLREG3_ADIDCHK 0x80 /* additional ID check */
- #define CNTLREG3_FASTSCSI 0x10 /* fast SCSI */
- #define CNTLREG3_FASTCLK 0x08 /* fast SCSI clocking */
- #define CNTLREG4 0x34 /* rw control register four */
- #define CNTLREG4_GLITCH 0xC0 /* glitch eater */
- #define CNTLREG4_PWD 0x20 /* reduced power feature */
- #define CNTLREG4_RAE 0x08 /* write only, active negot. ctrl. */
- #define CNTLREG4_RADE 0x04 /* active negot. ctrl. */
- #define CNTLREG4_RES 0x10 /* reserved bit, must be 1 */
- /*** DMA block ***/
- #define DMACMD 0x40 /* rw command */
- #define DMACMD_DIR 0x80 /* transfer direction (1=read from device) */
- #define DMACMD_INTE_D 0x40 /* DMA transfer interrupt enable */
- #define DMACMD_INTE_P 0x20 /* page transfer interrupt enable */
- #define DMACMD_MDL 0x10 /* map to memory descriptor list */
- #define DMACMD_DIAG 0x04 /* diagnostics, set to 0 */
- #define DMACMD_IDLE 0x00 /* idle cmd */
- #define DMACMD_BLAST 0x01 /* flush FIFO to memory */
- #define DMACMD_ABORT 0x02 /* terminate DMA */
- #define DMACMD_START 0x03 /* start DMA */
- #define DMASTATUS 0x54 /* r status register */
- #define DMASTATUS_BCMPLT 0x20 /* BLAST complete */
- #define DMASTATUS_SCSIINT 0x10 /* SCSI interrupt pending */
- #define DMASTATUS_DONE 0x08 /* DMA transfer terminated */
- #define DMASTATUS_ABORT 0x04 /* DMA transfer aborted */
- #define DMASTATUS_ERROR 0x02 /* DMA transfer error */
- #define DMASTATUS_PWDN 0x02 /* power down indicator */
- #define DMASTC 0x44 /* rw starting transfer count */
- #define DMASPA 0x48 /* rw starting physical address */
- #define DMAWBC 0x4C /* r working byte counter */
- #define DMAWAC 0x50 /* r working address counter */
- #define DMASMDLA 0x58 /* rw starting MDL address */
- #define DMAWMAC 0x5C /* r working MDL counter */
- /*** SCSI phases ***/
- #define PHASE_MSGIN 0x07
- #define PHASE_MSGOUT 0x06
- #define PHASE_RES_1 0x05
- #define PHASE_RES_0 0x04
- #define PHASE_STATIN 0x03
- #define PHASE_CMDOUT 0x02
- #define PHASE_DATAIN 0x01
- #define PHASE_DATAOUT 0x00
- #define AM53C974_local_declare() unsigned long io_port
- #define AM53C974_setio(instance) io_port = instance->io_port
- #define AM53C974_read_8(addr) inb(io_port + (addr))
- #define AM53C974_write_8(addr,x) outb((x), io_port + (addr))
- #define AM53C974_read_16(addr) inw(io_port + (addr))
- #define AM53C974_write_16(addr,x) outw((x), io_port + (addr))
- #define AM53C974_read_32(addr) inl(io_port + (addr))
- #define AM53C974_write_32(addr,x) outl((x), io_port + (addr))
- #define AM53C974_poll_int() { do { statreg = AM53C974_read_8(STATREG); }
- while (!(statreg & STATREG_INT)) ;
- AM53C974_read_8(INSTREG) ; } /* clear int */
- #define AM53C974_cfifo() (AM53C974_read_8(CFIREG) & CFIREG_CF)
- /* These are "special" values for the tag parameter passed to AM53C974_select. */
- #define TAG_NEXT -1 /* Use next free tag */
- #define TAG_NONE -2 /* Establish I_T_L nexus instead of I_T_L_Q
- * even on SCSI-II devices */
- /************ LILO overrides *************/
- typedef struct _override_t {
- int host_scsi_id; /* SCSI id of the bus controller */
- int target_scsi_id; /* SCSI id of target */
- int max_rate; /* max. transfer rate */
- int max_offset; /* max. sync. offset, 0 = asynchronous */
- } override_t;
- #ifdef AM53C974_DEBUG
- static void AM53C974_print_phase(struct Scsi_Host *instance);
- static void AM53C974_print_queues(struct Scsi_Host *instance);
- #endif /* AM53C974_DEBUG */
- static void AM53C974_print(struct Scsi_Host *instance);
- static void AM53C974_keywait(void);
- static __inline__ int AM53C974_pci_detect(Scsi_Host_Template * tpnt);
- static int AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev);
- static void AM53C974_config_after_reset(struct Scsi_Host *instance);
- static __inline__ void initialize_SCp(Scsi_Cmnd * cmd);
- static __inline__ void run_main(void);
- static void AM53C974_main(void);
- static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
- static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs);
- static void AM53C974_intr_disconnect(struct Scsi_Host *instance);
- static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg);
- static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target);
- static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target);
- static void AM53C974_information_transfer(struct Scsi_Host *instance,
- unsigned char statreg, unsigned char isreg,
- unsigned char instreg, unsigned char cfifo,
- unsigned char dmastatus);
- static int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd * cmd, unsigned char msg);
- static void AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
- static void AM53C974_intr_reselect(struct Scsi_Host *instance, unsigned char statreg);
- static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir,
- unsigned long length, char *data);
- static void AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus,
- unsigned char statreg);
- static void AM53C974_intr_bus_reset(struct Scsi_Host *instance);
- static struct Scsi_Host *first_instance;
- static Scsi_Host_Template *the_template;
- static struct Scsi_Host *first_host; /* Head of list of AMD boards */
- static volatile int main_running;
- static int commandline_current;
- override_t overrides[7] =
- {
- {-1, 0, 0, 0},}; /* LILO overrides */
- #ifdef AM53C974_DEBUG
- static int deb_stop = 1;
- static struct {
- unsigned char value;
- char *name;
- } phases[] = {
- {
- PHASE_DATAOUT, "DATAOUT"
- }, {
- PHASE_DATAIN, "DATAIN"
- }, {
- PHASE_CMDOUT, "CMDOUT"
- },
- {
- PHASE_STATIN, "STATIN"
- }, {
- PHASE_MSGOUT, "MSGOUT"
- }, {
- PHASE_MSGIN, "MSGIN"
- },
- {
- PHASE_RES_0, "RESERVED 0"
- }, {
- PHASE_RES_1, "RESERVED 1"
- }
- };
- /**************************************************************************
- * Function : void AM53C974_print_phase(struct Scsi_Host *instance)
- *
- * Purpose : print the current SCSI phase for debugging purposes
- *
- * Input : instance - which AM53C974
- **************************************************************************/
- static void AM53C974_print_phase(struct Scsi_Host *instance)
- {
- AM53C974_local_declare();
- unsigned char statreg, latched;
- int i;
- AM53C974_setio(instance);
- latched = (AM53C974_read_8(CNTLREG2)) & CNTLREG2_ENF;
- statreg = AM53C974_read_8(STATREG);
- for (i = 0; (phases[i].value != PHASE_RES_1) &&
- (phases[i].value != (statreg & STATREG_PHASE)); ++i);
- if (latched)
- printk("scsi%d : phase %s, latched at end of last commandn", instance->host_no, phases[i].name);
- else
- printk("scsi%d : phase %s, real timen", instance->host_no, phases[i].name);
- }
- /**************************************************************************
- * Function : void AM53C974_print_queues(struct Scsi_Host *instance)
- *
- * Purpose : print commands in the various queues
- *
- * Inputs : instance - which AM53C974
- **************************************************************************/
- static void AM53C974_print_queues(struct Scsi_Host *instance)
- {
- unsigned long flags;
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- Scsi_Cmnd *ptr;
- printk("AM53C974: coroutine is%s running.n", main_running ? "" : "n't");
- save_flags(flags);
- cli();
- if (!hostdata->connected) {
- printk("scsi%d: no currently connected commandn", instance->host_no);
- } else {
- print_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected);
- }
- if (!hostdata->sel_cmd) {
- printk("scsi%d: no currently arbitrating commandn", instance->host_no);
- } else {
- print_Scsi_Cmnd((Scsi_Cmnd *) hostdata->sel_cmd);
- }
- printk("scsi%d: issue_queue ", instance->host_no);
- if (!hostdata->issue_queue)
- printk("emptyn");
- else {
- printk(":n");
- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- print_Scsi_Cmnd(ptr);
- }
- printk("scsi%d: disconnected_queue ", instance->host_no);
- if (!hostdata->disconnected_queue)
- printk("emptyn");
- else {
- printk(":n");
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- print_Scsi_Cmnd(ptr);
- }
- restore_flags(flags);
- }
- #endif /* AM53C974_DEBUG */
- /**************************************************************************
- * Function : void AM53C974_print(struct Scsi_Host *instance)
- *
- * Purpose : dump the chip registers for debugging purposes
- *
- * Input : instance - which AM53C974
- **************************************************************************/
- static void AM53C974_print(struct Scsi_Host *instance)
- {
- AM53C974_local_declare();
- unsigned long flags;
- unsigned long ctcreg, dmastc, dmaspa, dmawbc, dmawac;
- unsigned char cmdreg, statreg, isreg, cfireg, cntlreg[4], dmacmd,
- dmastatus;
- AM53C974_setio(instance);
- save_flags(flags);
- cli();
- ctcreg = AM53C974_read_8(CTCHREG) << 16;
- ctcreg |= AM53C974_read_8(CTCMREG) << 8;
- ctcreg |= AM53C974_read_8(CTCLREG);
- cmdreg = AM53C974_read_8(CMDREG);
- statreg = AM53C974_read_8(STATREG);
- isreg = AM53C974_read_8(ISREG);
- cfireg = AM53C974_read_8(CFIREG);
- cntlreg[0] = AM53C974_read_8(CNTLREG1);
- cntlreg[1] = AM53C974_read_8(CNTLREG2);
- cntlreg[2] = AM53C974_read_8(CNTLREG3);
- cntlreg[3] = AM53C974_read_8(CNTLREG4);
- dmacmd = AM53C974_read_8(DMACMD);
- dmastc = AM53C974_read_32(DMASTC);
- dmaspa = AM53C974_read_32(DMASPA);
- dmawbc = AM53C974_read_32(DMAWBC);
- dmawac = AM53C974_read_32(DMAWAC);
- dmastatus = AM53C974_read_8(DMASTATUS);
- restore_flags(flags);
- printk("AM53C974 register dump:n");
- printk("IO base: 0x%04lx; CTCREG: 0x%04lx; CMDREG: 0x%02x; STATREG: 0x%02x; ISREG: 0x%02xn",
- io_port, ctcreg, cmdreg, statreg, isreg);
- printk("CFIREG: 0x%02x; CNTLREG1-4: 0x%02x; 0x%02x; 0x%02x; 0x%02xn",
- cfireg, cntlreg[0], cntlreg[1], cntlreg[2], cntlreg[3]);
- printk("DMACMD: 0x%02x; DMASTC: 0x%04lx; DMASPA: 0x%04lxn", dmacmd, dmastc, dmaspa);
- printk("DMAWBC: 0x%04lx; DMAWAC: 0x%04lx; DMASTATUS: 0x%02xn", dmawbc, dmawac, dmastatus);
- printk("---------------------------------------------------------n");
- }
- /**************************************************************************
- * Function : void AM53C974_keywait(void)
- *
- * Purpose : wait until a key is pressed, if it was the 'r' key leave singlestep mode;
- * this function is used for debugging only
- *
- * Input : none
- **************************************************************************/
- static void AM53C974_keywait(void)
- {
- unsigned long flags;
- #ifdef AM53C974_DEBUG
- int key;
- if (!deb_stop)
- return;
- #endif
- save_flags(flags);
- cli();
- while ((inb_p(0x64) & 0x01) != 0x01);
- #ifdef AM53C974_DEBUG
- key = inb(0x60);
- if (key == 0x93)
- deb_stop = 0; /* don't stop if 'r' was pressed */
- #endif
- restore_flags(flags);
- }
- #ifndef MODULE
- /**************************************************************************
- * Function : AM53C974_setup(char *str)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Input : str - parameter string.
- *
- * Returns : 1.
- *
- * NOTE : this function needs to be declared as an external function
- * in init/main.c and included there in the bootsetups list
- ***************************************************************************/
- static int AM53C974_setup(char *str)
- {
- int ints[5];
- get_options(str, ARRAY_SIZE(ints), ints);
- if (ints[0] < 4)
- printk("AM53C974_setup: wrong number of parameters;n correct syntax is: AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offsetn");
- else {
- if (commandline_current < (sizeof(overrides) / sizeof(override_t))) {
- if ((ints[1] < 0) || (ints[1] > 7) ||
- (ints[2] < 0) || (ints[2] > 7) ||
- (ints[1] == ints[2]) ||
- (ints[3] < (DEF_CLK / MAX_PERIOD)) || (ints[3] > (DEF_CLK / MIN_PERIOD)) ||
- (ints[4] < 0) || (ints[4] > MAX_OFFSET))
- printk("AM53C974_setup: illegal parametern");
- else {
- overrides[commandline_current].host_scsi_id = ints[1];
- overrides[commandline_current].target_scsi_id = ints[2];
- overrides[commandline_current].max_rate = ints[3];
- overrides[commandline_current].max_offset = ints[4];
- commandline_current++;
- }
- } else
- printk("AM53C974_setup: too many overridesn");
- }
- return 1;
- }
- __setup("AM53C974=", AM53C974_setup);
- #endif /* !MODULE */
- /**************************************************************************
- * Function : int AM53C974_pci_detect(Scsi_Host_Template *tpnt)
- *
- * Purpose : detects and initializes AM53C974 SCSI chips with PCI Bios
- *
- * Inputs : tpnt - host template
- *
- * Returns : number of host adapters detected
- **************************************************************************/
- static int __init AM53C974_pci_detect(Scsi_Host_Template * tpnt)
- {
- int count = 0; /* number of boards detected */
- struct pci_dev *pdev = NULL;
- unsigned short command;
- while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, pdev))) {
- if (pci_enable_device(pdev))
- continue;
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- /* check whether device is I/O mapped -- should be */
- if (!(command & PCI_COMMAND_IO))
- continue;
- pci_set_master (pdev);
- /* everything seems OK now, so initialize */
- if (AM53C974_init(tpnt, pdev))
- count++;
- }
- return (count);
- }
- /**************************************************************************
- * Function : int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev)
- *
- * Purpose : initializes instance and corresponding AM53/79C974 chip,
- *
- * Inputs : tpnt - template, pci_config - PCI configuration,
- *
- * Returns : 1 on success, 0 on failure.
- *
- * NOTE: If no override for the controller's SCSI id is given and AM53C974_SCSI_ID
- * is not defined we assume that the SCSI address of this controller is correctly
- * set up by the BIOS (as reflected by contents of register CNTLREG1).
- * This is the only BIOS assistance we need.
- **************************************************************************/
- static int __init AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev)
- {
- AM53C974_local_declare();
- int i, j;
- struct Scsi_Host *instance, *search;
- struct AM53C974_hostdata *hostdata;
- #ifdef AM53C974_OPTION_DEBUG_PROBE_ONLY
- printk("AM53C974: probe only enabled, aborting initializationn");
- return 0;
- #endif
- instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata));
- if (!instance) {
- printk(KERN_WARNING "AM53C974: Unable to register host, aborting.n");
- return 0;
- }
- scsi_set_pci_device(instance, pdev);
- hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- instance->base = 0;
- instance->io_port = pci_resource_start(pdev, 0);
- instance->irq = pdev->irq;
- instance->dma_channel = -1;
- AM53C974_setio(instance);
- #ifdef AM53C974_SCSI_ID
- instance->this_id = AM53C974_SCSI_ID;
- AM53C974_write_8(CNTLREG1, instance->this_id & CNTLREG1_SID);
- #else
- instance->this_id = AM53C974_read_8(CNTLREG1) & CNTLREG1_SID;
- if (instance->this_id != 7)
- printk("scsi%d: WARNING: unusual hostadapter SCSI id %d; please verify!n",
- instance->host_no, instance->this_id);
- #endif
- for (i = 0; i < sizeof(hostdata->msgout); i++) {
- hostdata->msgout[i] = NOP;
- hostdata->last_message[i] = NOP;
- }
- for (i = 0; i < 8; i++) {
- hostdata->busy[i] = 0;
- hostdata->sync_per[i] = DEF_STP;
- hostdata->sync_off[i] = 0;
- hostdata->sync_neg[i] = 0;
- hostdata->sync_en[i] = DEFAULT_SYNC_NEGOTIATION_ENABLED;
- hostdata->max_rate[i] = DEFAULT_RATE;
- hostdata->max_offset[i] = DEFAULT_SYNC_OFFSET;
- }
- /* overwrite defaults by LILO overrides */
- for (i = 0; i < commandline_current; i++) {
- if (overrides[i].host_scsi_id == instance->this_id) {
- j = overrides[i].target_scsi_id;
- hostdata->sync_en[j] = 1;
- hostdata->max_rate[j] = overrides[i].max_rate;
- hostdata->max_offset[j] = overrides[i].max_offset;
- }
- }
- hostdata->sel_cmd = NULL;
- hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
- hostdata->in_reset = 0;
- hostdata->aborted = 0;
- hostdata->selecting = 0;
- hostdata->disconnecting = 0;
- hostdata->dma_busy = 0;
- /* Set up an interrupt handler if we aren't already sharing an IRQ with another board */
- for (search = first_host;
- search && (((the_template != NULL) && (search->hostt != the_template)) ||
- (search->irq != instance->irq) || (search == instance));
- search = search->next);
- if (!search) {
- if (request_irq(instance->irq, do_AM53C974_intr, SA_SHIRQ, "AM53C974", instance)) {
- printk("scsi%d: IRQ%d not free, detachingn", instance->host_no, instance->irq);
- scsi_unregister(instance);
- return 0;
- }
- } else {
- printk("scsi%d: using interrupt handler previously installed for scsi%dn",
- instance->host_no, search->host_no);
- }
- if (!the_template) {
- the_template = instance->hostt;
- first_instance = instance;
- }
- /* do hard reset */
- AM53C974_write_8(CMDREG, CMDREG_RDEV); /* reset device */
- udelay(5);
- AM53C974_write_8(CMDREG, CMDREG_NOP);
- AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id);
- AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */
- udelay(10);
- AM53C974_config_after_reset(instance);
- mdelay(500);
- return (1);
- }
- /*********************************************************************
- * Function : AM53C974_config_after_reset(struct Scsi_Host *instance) *
- * *
- * Purpose : initializes chip registers after reset *
- * *
- * Inputs : instance - which AM53C974 *
- * *
- * Returns : nothing *
- **********************************************************************/
- static void AM53C974_config_after_reset(struct Scsi_Host *instance)
- {
- AM53C974_local_declare();
- AM53C974_setio(instance);
- /* clear SCSI FIFO */
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- /* configure device */
- AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT);
- AM53C974_write_8(STPREG, DEF_STP & STPREG_STP);
- AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4));
- AM53C974_write_8(CLKFREG, DEF_CLKF & CLKFREG_MASK);
- AM53C974_write_8(CNTLREG1, (DEF_ETM << 7) | CNTLREG1_DISR | (DEF_PERE << 4) | instance->this_id);
- AM53C974_write_8(CNTLREG2, (DEF_ENF << 6));
- AM53C974_write_8(CNTLREG3, (DEF_ADIDCHK << 7) | (DEF_FASTSCSI << 4) | (DEF_FASTCLK << 3));
- AM53C974_write_8(CNTLREG4, (DEF_GLITCH << 6) | (DEF_PWD << 5) | (DEF_RAE << 3) | (DEF_RADE << 2) | CNTLREG4_RES);
- }
- /***********************************************************************
- * Function : const char *AM53C974_info(struct Scsi_Host *instance) *
- * *
- * Purpose : return device driver information *
- * *
- * Inputs : instance - which AM53C974 *
- * *
- * Returns : info string *
- ************************************************************************/
- static const char *AM53C974_info(struct Scsi_Host *instance)
- {
- static char info[100];
- sprintf(info, "AM53/79C974 PCscsi driver rev. %d.%d; host I/O address: 0x%lx; irq: %dn",
- AM53C974_DRIVER_REVISION_MAJOR, AM53C974_DRIVER_REVISION_MINOR,
- instance->io_port, instance->irq);
- return (info);
- }
- /**************************************************************************
- * Function : int AM53C974_command (Scsi_Cmnd *SCpnt) *
- * *
- * Purpose : the unqueued SCSI command function, replaced by the *
- * AM53C974_queue_command function *
- * *
- * Inputs : SCpnt - pointer to command structure *
- * *
- * Returns :status, see hosts.h for details *
- ***************************************************************************/
- static int AM53C974_command(Scsi_Cmnd * SCpnt)
- {
- DEB(printk("AM53C974_command calledn"));
- return 0;
- }
- /**************************************************************************
- * Function : void initialize_SCp(Scsi_Cmnd *cmd) *
- * *
- * Purpose : initialize the saved data pointers for cmd to point to the *
- * start of the buffer. *
- * *
- * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. *
- * *
- * Returns : nothing *
- **************************************************************************/
- static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
- {
- if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
- cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- } else {
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = (char *) cmd->request_buffer;
- cmd->SCp.this_residual = cmd->request_bufflen;
- }
- }
- /**************************************************************************
- * Function : run_main(void) *
- * *
- * Purpose : insure that the coroutine is running and will process our *
- * request. main_running is checked/set here (in an inline *
- * function rather than in AM53C974_main itself to reduce the *
- * chances of stack overflow. *
- * *
- * *
- * Inputs : none *
- * *
- * Returns : nothing *
- **************************************************************************/
- static __inline__ void run_main(void)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- if (!main_running) {
- /* main_running is cleared in AM53C974_main once it can't do
- more work, and AM53C974_main exits with interrupts disabled. */
- main_running = 1;
- AM53C974_main();
- }
- restore_flags(flags);
- }
- /**************************************************************************
- * Function : int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
- *
- * Purpose : writes SCSI command into AM53C974 FIFO
- *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
- *
- * Returns : status, see hosts.h for details
- *
- * Side effects :
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
- * main coroutine is not running, it is restarted.
- **************************************************************************/
- static int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
- {
- unsigned long flags;
- struct Scsi_Host *instance = cmd->host;
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- Scsi_Cmnd *tmp;
- save_flags(flags);
- cli();
- DEB_QUEUE(printk(SEPARATOR_LINE));
- DEB_QUEUE(printk("scsi%d: AM53C974_queue_command calledn", instance->host_no));
- DEB_QUEUE(printk("cmd=%02x target=%02x lun=%02x bufflen=%d use_sg = %02xn",
- cmd->cmnd[0], cmd->target, cmd->lun, cmd->request_bufflen, cmd->use_sg));
- /* We use the host_scribble field as a pointer to the next command in a queue */
- cmd->host_scribble = NULL;
- cmd->scsi_done = done;
- cmd->result = 0;
- cmd->device->disconnect = 0;
- /* Insert the cmd into the issue queue. Note that REQUEST SENSE
- * commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
- * sense data is only guaranteed to be valid while the condition exists. */
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble;
- tmp = (Scsi_Cmnd *) tmp->host_scribble);
- LIST(cmd, tmp);
- tmp->host_scribble = (unsigned char *) cmd;
- }
- DEB_QUEUE(printk("scsi%d : command added to %s of queuen", instance->host_no,
- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"));
- /* Run the coroutine if it isn't already running. */
- run_main();
- restore_flags(flags);
- return 0;
- }
- /**************************************************************************
- * Function : AM53C974_main (void)
- *
- * Purpose : AM53C974_main is a coroutine that runs as long as more work can
- * be done on the AM53C974 host adapters in a system. Both
- * AM53C974_queue_command() and AM53C974_intr() will try to start it
- * in case it is not running.
- *
- * NOTE : AM53C974_main exits with interrupts *disabled*, the caller should
- * reenable them. This prevents reentrancy and kernel stack overflow.
- **************************************************************************/
- static void AM53C974_main(void)
- {
- AM53C974_local_declare();
- unsigned long flags;
- Scsi_Cmnd *tmp, *prev;
- struct Scsi_Host *instance;
- struct AM53C974_hostdata *hostdata;
- int done;
- /* We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set main_running to 0 and exit. */
- save_flags(flags);
- cli(); /* Freeze request queues */
- do {
- done = 1;
- for (instance = first_instance; instance && instance->hostt == the_template;
- instance = instance->next) {
- hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- AM53C974_setio(instance);
- /* start to select target if we are not connected and not in the
- selection process */
- if (!hostdata->connected && !hostdata->sel_cmd) {
- /* Search through the issue_queue for a command destined for a target
- that is not busy. */
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp;
- prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) {
- /* When we find one, remove it from the issue queue. */
- if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) {
- if (prev) {
- REMOVE(prev, (Scsi_Cmnd *) (prev->host_scribble), tmp,
- (Scsi_Cmnd *) (tmp->host_scribble));
- prev->host_scribble = tmp->host_scribble;
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
- hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
- }
- tmp->host_scribble = NULL;
- /* go into selection mode, disable reselection and wait for
- SO interrupt which will continue with the selection process */
- hostdata->selecting = 1;
- hostdata->sel_cmd = tmp;
- AM53C974_write_8(CMDREG, CMDREG_DSR);
- break;
- } /* if target/lun is not busy */
- } /* for */
- }
- /* if (!hostdata->connected) */
- else {
- DEB(printk("main: connected; cmd = 0x%lx, sel_cmd = 0x%lxn",
- (long) hostdata->connected, (long) hostdata->sel_cmd));
- }
- } /* for instance */
- } while (!done);
- main_running = 0;
- restore_flags(flags);
- }
- /************************************************************************
- * Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
- * *
- * Purpose : interrupt handler *
- * *
- * Inputs : irq - interrupt line, regs - ? *
- * *
- * Returns : nothing *
- ************************************************************************/
- static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
- {
- unsigned long flags;
- spin_lock_irqsave(&io_request_lock, flags);
- AM53C974_intr(irq, dev_id, regs);
- spin_unlock_irqrestore(&io_request_lock, flags);
- }
- /************************************************************************
- * Function : AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) *
- * *
- * Purpose : interrupt handler *
- * *
- * Inputs : irq - interrupt line, regs - ? *
- * *
- * Returns : nothing *
- ************************************************************************/
- static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs)
- {
- AM53C974_local_declare();
- struct Scsi_Host *instance;
- struct AM53C974_hostdata *hostdata;
- unsigned char cmdreg, dmastatus, statreg, isreg, instreg, cfifo;
- /* find AM53C974 hostadapter responsible for this interrupt */
- for (instance = first_instance; instance; instance = instance->next)
- if ((instance->irq == irq) && (instance->hostt == the_template))
- goto FOUND;
- return;
- /* found; now decode and process */
- FOUND:
- hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- AM53C974_setio(instance);
- dmastatus = AM53C974_read_8(DMASTATUS);
- DEB_INTR(printk(SEPARATOR_LINE));
- DEB_INTR(printk("AM53C974 interrupt; dmastatus=0x%02xn", dmastatus));
- KEYWAIT();
- /*** DMA related interrupts ***/
- if (hostdata->connected && (dmastatus & (DMASTATUS_ERROR | DMASTATUS_PWDN |
- DMASTATUS_ABORT))) {
- /* DMA error or POWERDOWN */
- printk("scsi%d: DMA error or powerdown; dmastatus: 0x%02xn",
- instance->host_no, dmastatus);
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- panic("scsi%d: cannot recovern", instance->host_no);
- }
- if (hostdata->connected && (dmastatus & DMASTATUS_DONE)) {
- /* DMA transfer done */
- unsigned long residual;
- unsigned long flags;
- save_flags(flags);
- cli();
- if (!(AM53C974_read_8(DMACMD) & DMACMD_DIR)) {
- do {
- dmastatus = AM53C974_read_8(DMASTATUS);
- residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) |
- (AM53C974_read_8(CTCHREG) << 16);
- residual += AM53C974_read_8(CFIREG) & CFIREG_CF;
- } while (!(dmastatus & DMASTATUS_SCSIINT) && residual);
- residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) |
- (AM53C974_read_8(CTCHREG) << 16);
- residual += AM53C974_read_8(CFIREG) & CFIREG_CF;
- } else
- residual = 0;
- hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - residual;
- hostdata->connected->SCp.this_residual = residual;
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- /* if service request missed before, process it now (ugly) */
- if (hostdata->dma_busy) {
- hostdata->dma_busy = 0;
- cmdreg = AM53C974_read_8(CMDREG);
- statreg = AM53C974_read_8(STATREG);
- isreg = AM53C974_read_8(ISREG);
- instreg = AM53C974_read_8(INSTREG);
- cfifo = AM53C974_cfifo();
- AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo,
- dmastatus);
- }
- restore_flags(flags);
- }
- if (!(dmastatus & DMASTATUS_SCSIINT)) {
- return;
- }
- /*** SCSI related interrupts ***/
- cmdreg = AM53C974_read_8(CMDREG);
- statreg = AM53C974_read_8(STATREG);
- isreg = AM53C974_read_8(ISREG);
- instreg = AM53C974_read_8(INSTREG);
- cfifo = AM53C974_cfifo();
- DEB_INTR(printk("scsi%d: statreg: 0x%02x; isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02xn",
- instance->host_no, statreg, isreg, instreg, cfifo));
- if (statreg & STATREG_PE) {
- /* parity error */
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- printk("scsi%d : PARITY errorn", instance->host_no);
- if (hostdata->connected)
- hostdata->sync_off[hostdata->connected->target] = 0; /* setup asynchronous transfer */
- hostdata->aborted = 1;
- }
- if (statreg & STATREG_IOE) {
- /* illegal operation error */
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- printk("scsi%d : ILLEGAL OPERATION errorn", instance->host_no);
- printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; n"
- "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02xn",
- cmdreg, AM53C974_read_8(DMACMD), statreg, isreg, instreg, cfifo);
- }
- if (hostdata->in_reset && (instreg & INSTREG_SRST)) {
- unsigned long flags;
- /* RESET INTERRUPT */
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- DEB(printk("Bus reset interrupt receivedn"));
- AM53C974_intr_bus_reset(instance);
- save_flags(flags);
- cli();
- if (hostdata->connected) {
- hostdata->connected->result = DID_RESET << 16;
- hostdata->connected->scsi_done((Scsi_Cmnd *) hostdata->connected);
- hostdata->connected = NULL;
- } else {
- if (hostdata->sel_cmd) {
- hostdata->sel_cmd->result = DID_RESET << 16;
- hostdata->sel_cmd->scsi_done((Scsi_Cmnd *) hostdata->sel_cmd);
- hostdata->sel_cmd = NULL;
- }
- }
- restore_flags(flags);
- if (hostdata->in_reset == 1)
- goto EXIT;
- else
- return;
- }
- if (instreg & INSTREG_ICMD) {
- /* INVALID COMMAND INTERRUPT */
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- printk("scsi%d: Invalid command interruptn", instance->host_no);
- printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; dmastatus: 0x%02x; n"
- "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02xn",
- cmdreg, AM53C974_read_8(DMACMD), statreg, dmastatus, isreg, instreg, cfifo);
- panic("scsi%d: cannot recovern", instance->host_no);
- }
- if (instreg & INSTREG_DIS) {
- unsigned long flags;
- /* DISCONNECT INTERRUPT */
- DEB_INTR(printk("Disconnect interrupt received; "));
- save_flags(flags);
- cli();
- AM53C974_intr_disconnect(instance);
- restore_flags(flags);
- goto EXIT;
- }
- if (instreg & INSTREG_RESEL) {
- unsigned long flags;
- /* RESELECTION INTERRUPT */
- DEB_INTR(printk("Reselection interrupt receivedn"));
- save_flags(flags);
- cli();
- AM53C974_intr_reselect(instance, statreg);
- restore_flags(flags);
- goto EXIT;
- }
- if (instreg & INSTREG_SO) {
- DEB_INTR(printk("Successful operation interrupt receivedn"));
- if (hostdata->selecting) {
- unsigned long flags;
- DEB_INTR(printk("DSR completed, starting selectn"));
- save_flags(flags);
- cli();
- AM53C974_select(instance, (Scsi_Cmnd *) hostdata->sel_cmd,
- (hostdata->sel_cmd->cmnd[0] == REQUEST_SENSE) ?
- TAG_NONE : TAG_NEXT);
- hostdata->selecting = 0;
- AM53C974_set_sync(instance, hostdata->sel_cmd->target);
- restore_flags(flags);
- return;
- }
- if (hostdata->sel_cmd != NULL) {
- if (((isreg & ISREG_IS) != ISREG_OK_NO_STOP) &&
- ((isreg & ISREG_IS) != ISREG_OK_STOP)) {
- unsigned long flags;
- /* UNSUCCESSFUL SELECTION */
- DEB_INTR(printk("unsuccessful selectionn"));
- save_flags(flags);
- cli();
- hostdata->dma_busy = 0;
- LIST(hostdata->sel_cmd, hostdata->issue_queue);
- hostdata->sel_cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = hostdata->sel_cmd;
- hostdata->sel_cmd = NULL;
- hostdata->selecting = 0;
- restore_flags(flags);
- goto EXIT;
- } else {
- unsigned long flags;
- /* SUCCESSFUL SELECTION */
- DEB(printk("successful selection; cmd=0x%02lxn", (long) hostdata->sel_cmd));
- save_flags(flags);
- cli();
- hostdata->dma_busy = 0;
- hostdata->disconnecting = 0;
- hostdata->connected = hostdata->sel_cmd;
- hostdata->sel_cmd = NULL;
- hostdata->selecting = 0;
- #ifdef SCSI2
- if (!hostdata->connected->device->tagged_queue)
- #endif
- hostdata->busy[hostdata->connected->target] |= (1 << hostdata->connected->lun);
- /* very strange -- use_sg is sometimes nonzero for request sense commands !! */
- if ((hostdata->connected->cmnd[0] == REQUEST_SENSE) && hostdata->connected->use_sg) {
- DEB(printk("scsi%d: REQUEST_SENSE command with nonzero use_sgn", instance->host_no));
- KEYWAIT();
- hostdata->connected->use_sg = 0;
- }
- initialize_SCp((Scsi_Cmnd *) hostdata->connected);
- hostdata->connected->SCp.phase = PHASE_CMDOUT;
- AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus);
- restore_flags(flags);
- return;
- }
- } else {
- unsigned long flags;
- save_flags(flags);
- cli();
- AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus);
- restore_flags(flags);
- return;
- }
- }
- if (instreg & INSTREG_SR) {
- DEB_INTR(printk("Service request interrupt received, "));
- if (hostdata->connected) {
- unsigned long flags;
- DEB_INTR(printk("calling information_transfern"));
- save_flags(flags);
- cli();
- AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus);
- restore_flags(flags);
- } else {
- printk("scsi%d: weird: service request when no command connectedn", instance->host_no);
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- } /* clear FIFO */
- return;
- }
- EXIT:
- DEB_INTR(printk("intr: starting mainn"));
- run_main();
- DEB_INTR(printk("end of intrn"));
- }
- /**************************************************************************
- * Function : AM53C974_intr_disconnect(struct Scsi_Host *instance)
- *
- * Purpose : manage target disconnection
- *
- * Inputs : instance -- which AM53C974
- *
- * Returns : nothing
- **************************************************************************/
- static void AM53C974_intr_disconnect(struct Scsi_Host *instance)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- Scsi_Cmnd *cmd;
- AM53C974_setio(instance);
- if (hostdata->sel_cmd != NULL) {
- /* normal selection timeout, typical for nonexisting targets */
- cmd = (Scsi_Cmnd *) hostdata->sel_cmd;
- DEB_INTR(printk("bad targetn"));
- cmd->result = DID_BAD_TARGET << 16;
- goto EXIT_FINISHED;
- }
- if (!hostdata->connected) {
- /* can happen if controller was reset, a device tried to reconnect,
- failed and disconnects now */
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- return;
- }
- if (hostdata->disconnecting) {
- /* target sent disconnect message, so we are prepared */
- cmd = (Scsi_Cmnd *) hostdata->connected;
- AM53C974_set_async(instance, cmd->target);
- DEB_INTR(printk("scsi%d : disc. from cmnd %d for ta %d, lun %dn",
- instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun));
- if (cmd->device->disconnect) {
- /* target wants to reselect later */
- DEB_INTR(printk("ok, re-enabling selectionn"));
- LIST(cmd, hostdata->disconnected_queue);
- cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue;
- hostdata->disconnected_queue = cmd;
- DEB_QUEUE(printk("scsi%d : command for target %d lun %d this %d was moved from connected to"
- " the disconnected_queuen", instance->host_no, cmd->target,
- cmd->lun, hostdata->disconnected_queue->SCp.this_residual));
- DEB_QUEUE(AM53C974_print_queues(instance));
- goto EXIT_UNFINISHED;
- } else {
- /* target does not want to reselect later, we are really finished */
- #ifdef AM53C974_DEBUG
- if (cmd->cmnd[0] == REQUEST_SENSE) {
- int i;
- printk("Request sense data dump:n");
- for (i = 0; i < cmd->request_bufflen; i++) {
- printk("%02x ", *((char *) (cmd->request_buffer) + i));
- if (i && !(i % 16))
- printk("n");
- }
- printk("n");
- }
- #endif
- goto EXIT_FINISHED;
- } /* !cmd->device->disconnect */
- } /* if (hostdata->disconnecting) */
- /* no disconnect message received; unexpected disconnection */
- cmd = (Scsi_Cmnd *) hostdata->connected;
- if (cmd) {
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- AM53C974_set_async(instance, cmd->target);
- printk("scsi%d: Unexpected disconnect; phase: %d; target: %d; this_residual: %d; buffers_residual: %d; message: %dn",
- instance->host_no, cmd->SCp.phase, cmd->target, cmd->SCp.this_residual, cmd->SCp.buffers_residual,
- cmd->SCp.Message);
- printk("cmdreg: 0x%02x; statreg: 0x%02x; isreg: 0x%02x; cfifo: 0x%02xn",
- AM53C974_read_8(CMDREG), AM53C974_read_8(STATREG), AM53C974_read_8(ISREG),
- AM53C974_read_8(CFIREG) & CFIREG_CF);
- if ((hostdata->last_message[0] == EXTENDED_MESSAGE) &&
- (hostdata->last_message[2] == EXTENDED_SDTR)) {
- /* sync. negotiation was aborted, setup asynchronous transfer with target */
- hostdata->sync_off[cmd->target] = 0;
- }
- if (hostdata->aborted || hostdata->msgout[0] == ABORT)
- cmd->result = DID_ABORT << 16;
- else
- cmd->result = DID_ERROR << 16;
- goto EXIT_FINISHED;
- }
- EXIT_FINISHED:
- hostdata->aborted = 0;
- hostdata->msgout[0] = NOP;
- hostdata->sel_cmd = NULL;
- hostdata->connected = NULL;
- hostdata->selecting = 0;
- hostdata->disconnecting = 0;
- hostdata->dma_busy = 0;
- hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lxn",
- (long) hostdata->issue_queue, (long) hostdata->disconnected_queue));
- cmd->scsi_done(cmd);
- if (!hostdata->selecting) {
- AM53C974_set_async(instance, cmd->target);
- AM53C974_write_8(CMDREG, CMDREG_ESR);
- } /* allow reselect */
- return;
- EXIT_UNFINISHED:
- hostdata->msgout[0] = NOP;
- hostdata->sel_cmd = NULL;
- hostdata->connected = NULL;
- hostdata->aborted = 0;
- hostdata->selecting = 0;
- hostdata->disconnecting = 0;
- hostdata->dma_busy = 0;
- DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lxn",
- (long) hostdata->issue_queue, (long) hostdata->disconnected_queue));
- if (!hostdata->selecting) {
- AM53C974_set_async(instance, cmd->target);
- AM53C974_write_8(CMDREG, CMDREG_ESR);
- } /* allow reselect */
- return;
- }
- /**************************************************************************
- * Function : int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg)
- *
- * Purpose : setup message string for sync. negotiation
- *
- * Inputs : instance -- which AM53C974
- * target -- which SCSI target to deal with
- * msg -- input message string
- *
- * Returns : 0 if parameters accepted or 1 if not accepted
- *
- * Side effects: hostdata is changed
- *
- * Note: we assume here that fastclk is enabled
- **************************************************************************/
- static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- int period, offset, i, rate, rate_rem;
- AM53C974_setio(instance);
- period = (DEF_CLK * msg[3] * 8 + 1000) / 2000;
- if (period < MIN_PERIOD) {
- period = MIN_PERIOD;
- hostdata->msgout[3] = period / 4;
- } else if (period > MAX_PERIOD) {
- period = MAX_PERIOD;
- hostdata->msgout[3] = period / 4;
- } else
- hostdata->msgout[3] = msg[3];
- offset = msg[4];
- if (offset > MAX_OFFSET)
- offset = MAX_OFFSET;
- hostdata->msgout[4] = offset;
- hostdata->sync_per[target] = period;
- hostdata->sync_off[target] = offset;
- for (i = 0; i < 3; i++)
- hostdata->msgout[i] = msg[i];
- if ((hostdata->msgout[3] != msg[3]) || (msg[4] != offset))
- return (1);
- rate = DEF_CLK / period;
- rate_rem = 10 * (DEF_CLK - period * rate) / period;
- if (offset)
- printk("ntarget %d: rate=%d.%d Mhz, synchronous, sync offset=%d bytesn",
- target, rate, rate_rem, offset);
- else
- printk("ntarget %d: rate=%d.%d Mhz, asynchronousn", target, rate, rate_rem);
- return (0);
- }
- /**************************************************************************
- * Function : AM53C974_set_async(struct Scsi_Host *instance, int target)
- *
- * Purpose : put controller into async. mode
- *
- * Inputs : instance -- which AM53C974
- * target -- which SCSI target to deal with
- *
- * Returns : nothing
- **************************************************************************/
- static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- AM53C974_setio(instance);
- AM53C974_write_8(STPREG, hostdata->sync_per[target]);
- AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4));
- }
- /**************************************************************************
- * Function : AM53C974_set_sync(struct Scsi_Host *instance, int target)
- *
- * Purpose : put controller into sync. mode
- *
- * Inputs : instance -- which AM53C974
- * target -- which SCSI target to deal with
- *
- * Returns : nothing
- **************************************************************************/
- static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- AM53C974_setio(instance);
- AM53C974_write_8(STPREG, hostdata->sync_per[target]);
- AM53C974_write_8(SOFREG, (SOFREG_SO & hostdata->sync_off[target]) |
- (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4));
- }
- /***********************************************************************
- * Function : AM53C974_information_transfer(struct Scsi_Host *instance, *
- * unsigned char statreg, unsigned char isreg, *
- * unsigned char instreg, unsigned char cfifo, *
- * unsigned char dmastatus) *
- * *
- * Purpose : handle phase changes *
- * *
- * Inputs : instance - which AM53C974 *
- * statreg - status register *
- * isreg - internal state register *
- * instreg - interrupt status register *
- * cfifo - number of bytes in FIFO *
- * dmastatus - dma status register *
- * *
- * Returns : nothing *
- ************************************************************************/
- static void AM53C974_information_transfer(struct Scsi_Host *instance,
- unsigned char statreg, unsigned char isreg,
- unsigned char instreg, unsigned char cfifo,
- unsigned char dmastatus)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
- int ret, i, len, residual = -1;
- AM53C974_setio(instance);
- DEB_INFO(printk(SEPARATOR_LINE));
- switch (statreg & STATREG_PHASE) { /* scsi phase */
- case PHASE_DATAOUT:
- DEB_INFO(printk("Dataout phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%dn",
- (long) hostdata->connected, (long) hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual));
- cmd->SCp.phase = PHASE_DATAOUT;
- goto PHASE_DATA_IO;
- case PHASE_DATAIN:
- DEB_INFO(printk("Datain phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%dn",
- (long) hostdata->connected, (long) hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual));
- cmd->SCp.phase = PHASE_DATAIN;
- PHASE_DATA_IO:
- if (hostdata->aborted) {
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- return;
- }
- if ((!cmd->SCp.this_residual) && cmd->SCp.buffers_residual) {
- cmd->SCp.buffer++;
- cmd->SCp.buffers_residual--;
- cmd->SCp.ptr = (unsigned char *) cmd->SCp.buffer->address;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- }
- if (cmd->SCp.this_residual) {
- if (!(AM53C974_read_8(DMACMD) & DMACMD_START)) {
- hostdata->dma_busy = 0;
- AM53C974_transfer_dma(instance, statreg & STATREG_IO,
- (unsigned long) cmd->SCp.this_residual,
- cmd->SCp.ptr);
- } else
- hostdata->dma_busy = 1;
- }
- return;
- case PHASE_MSGIN:
- DEB_INFO(printk("Message-In phase; cmd=0x%lx, sel_cmd=0x%lxn",
- (long) hostdata->connected, (long) hostdata->sel_cmd));
- AM53C974_set_async(instance, cmd->target);
- if (cmd->SCp.phase == PHASE_DATAIN)
- AM53C974_dma_blast(instance, dmastatus, statreg);
- if ((cmd->SCp.phase == PHASE_DATAOUT) && (AM53C974_read_8(DMACMD) & DMACMD_START)) {
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) |
- (AM53C974_read_8(CTCHREG) << 16));
- cmd->SCp.ptr += cmd->SCp.this_residual - residual;
- cmd->SCp.this_residual = residual;
- if (cfifo) {
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- cfifo = 0;
- }
- }
- if (cmd->SCp.phase == PHASE_STATIN) {
- while ((AM53C974_read_8(CFIREG) & CFIREG_CF) < 2);
- cmd->SCp.Status = AM53C974_read_8(FFREG);
- cmd->SCp.Message = AM53C974_read_8(FFREG);
- DEB_INFO(printk("Message-In phase; status=0x%02x, message=0x%02xn",
- cmd->SCp.Status, cmd->SCp.Message));
- ret = AM53C974_message(instance, cmd, cmd->SCp.Message);
- } else {
- if (!cfifo) {
- AM53C974_write_8(CMDREG, CMDREG_IT);
- AM53C974_poll_int();
- cmd->SCp.Message = AM53C974_read_8(FFREG);
- }
- ret = AM53C974_message(instance, cmd, cmd->SCp.Message);
- }
- cmd->SCp.phase = PHASE_MSGIN;
- AM53C974_set_sync(instance, cmd->target);
- break;
- case PHASE_MSGOUT:
- DEB_INFO(printk("Message-Out phase; cfifo=%d; msgout[0]=0x%02xn",
- AM53C974_read_8(CFIREG) & CFIREG_CF, hostdata->msgout[0]));
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- AM53C974_set_async(instance, cmd->target);
- for (i = 0; i < sizeof(hostdata->last_message); i++)
- hostdata->last_message[i] = hostdata->msgout[i];
- if ((hostdata->msgout[0] == 0) || INSIDE(hostdata->msgout[0], 0x02, 0x1F) ||
- INSIDE(hostdata->msgout[0], 0x80, 0xFF))
- len = 1;
- else {
- if (hostdata->msgout[0] == EXTENDED_MESSAGE) {
- #ifdef AM53C974_DEBUG_INFO
- printk("Extended message dump:n");
- for (i = 0; i < hostdata->msgout[1] + 2; i++) {
- printk("%02x ", hostdata->msgout[i]);
- if (i && !(i % 16))
- printk("n");
- }
- printk("n");
- #endif
- len = hostdata->msgout[1] + 2;
- } else
- len = 2;
- }
- for (i = 0; i < len; i++)
- AM53C974_write_8(FFREG, hostdata->msgout[i]);
- AM53C974_write_8(CMDREG, CMDREG_IT);
- cmd->SCp.phase = PHASE_MSGOUT;
- hostdata->msgout[0] = NOP;
- AM53C974_set_sync(instance, cmd->target);
- break;
- case PHASE_CMDOUT:
- DEB_INFO(printk("Command-Out phasen"));
- AM53C974_set_async(instance, cmd->target);
- for (i = 0; i < cmd->cmd_len; i++)
- AM53C974_write_8(FFREG, cmd->cmnd[i]);
- AM53C974_write_8(CMDREG, CMDREG_IT);
- cmd->SCp.phase = PHASE_CMDOUT;
- AM53C974_set_sync(instance, cmd->target);
- break;
- case PHASE_STATIN:
- DEB_INFO(printk("Status phasen"));
- if (cmd->SCp.phase == PHASE_DATAIN)
- AM53C974_dma_blast(instance, dmastatus, statreg);
- AM53C974_set_async(instance, cmd->target);
- if (cmd->SCp.phase == PHASE_DATAOUT) {
- unsigned long residual;
- if (AM53C974_read_8(DMACMD) & DMACMD_START) {
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) |
- (AM53C974_read_8(CTCHREG) << 16));
- cmd->SCp.ptr += cmd->SCp.this_residual - residual;
- cmd->SCp.this_residual = residual;
- }
- if (cfifo) {
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- cfifo = 0;
- }
- }
- cmd->SCp.phase = PHASE_STATIN;
- AM53C974_write_8(CMDREG, CMDREG_ICCS); /* command complete */
- break;
- case PHASE_RES_0:
- case PHASE_RES_1:
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- DEB_INFO(printk("Reserved phasen"));
- break;
- }
- KEYWAIT();
- }
- /******************************************************************************
- * Function : int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd *cmd,
- * unsigned char msg)
- *
- * Purpose : handle SCSI messages
- *
- * Inputs : instance -- which AM53C974
- * cmd -- SCSI command the message belongs to
- * msg -- message id byte
- *
- * Returns : 1 on success, 0 on failure.
- **************************************************************************/
- static int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd * cmd,
- unsigned char msg)
- {
- AM53C974_local_declare();
- static unsigned char extended_msg[10];
- unsigned char statreg;
- int len, ret = 0;
- unsigned char *p;
- #ifdef AM53C974_DEBUG_MSG
- int j;
- #endif
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- AM53C974_setio(instance);
- DEB_MSG(printk(SEPARATOR_LINE));
- /* Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands. */
- switch (msg) {
- #ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by releasing ACK */
- DEB_LINKED(printk("scsi%d : target %d lun %d linked command complete.n",
- instance->host_no, cmd->target, cmd->lun));
- /* Sanity check : A linked command should only terminate with
- * one of these messages if there are more linked commands available. */
- if (!cmd->next_link) {
- printk("scsi%d : target %d lun %d linked command complete, no next_linkn"
- instance->host_no, cmd->target, cmd->lun);
- hostdata->aborted = 1;
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- AM53C974_write_8(CMDREG, CMDREG_MA);
- break;
- }
- if (hostdata->aborted) {
- DEB_ABORT(printk("ATN set for cmnd %d upon reception of LINKED_CMD_COMPLETE or"
- "LINKED_FLG_CMD_COMPLETE messagen", cmd->cmnd[0]));
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- }
- AM53C974_write_8(CMDREG, CMDREG_MA);
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- DEB_LINKED(printk("scsi%d : target %d lun %d linked request done, calling scsi_done().n",
- instance->host_no, cmd->target, cmd->lun));
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
- #endif /* def LINKED */
- case ABORT:
- case COMMAND_COMPLETE:
- DEB_MSG(printk("scsi%d: command complete message received; cmd %d for target %d, lun %dn",
- instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun));
- hostdata->disconnecting = 1;
- cmd->device->disconnect = 0;
- /* I'm not sure what the correct thing to do here is :
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- * If it was a REQUEST SENSE command, we need some way
- * to differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the result
- * code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed */
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (cmd->SCp.Status != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- if (hostdata->aborted) {
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- AM53C974_write_8(CMDREG, CMDREG_MA);
- DEB_ABORT(printk("ATN set for cmnd %d upon reception of ABORT or"
- "COMMAND_COMPLETE messagen", cmd->cmnd[0]));
- break;
- }
- if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) {
- DEB_MSG(printk("scsi%d : performing request sensen", instance->host_no));
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = (char *) cmd->sense_buffer;
- cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
- LIST(cmd, hostdata->issue_queue);
- cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- DEB_MSG(printk("scsi%d : REQUEST SENSE added to head of issue queuen", instance->host_no));
- }
- /* Accept message by clearing ACK */
- AM53C974_write_8(CMDREG, CMDREG_MA);
- break;
- case MESSAGE_REJECT:
- DEB_MSG(printk("scsi%d: reject message received; cmd %d for target %d, lun %dn",
- instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun));
- switch (hostdata->last_message[0]) {
- case EXTENDED_MESSAGE:
- if (hostdata->last_message[2] == EXTENDED_SDTR) {
- /* sync. negotiation was rejected, setup asynchronous transfer with target */
- printk("ntarget %d: rate=%d Mhz, asynchronous (sync. negotiation rejected)n",
- cmd->target, DEF_CLK / DEF_STP);
- hostdata->sync_off[cmd->target] = 0;
- hostdata->sync_per[cmd->target] = DEF_STP;
- }
- break;
- case HEAD_OF_QUEUE_TAG:
- case ORDERED_QUEUE_TAG:
- case SIMPLE_QUEUE_TAG:
- cmd->device->tagged_queue = 0;
- hostdata->busy[cmd->target] |= (1 << cmd->lun);
- break;
- default:
- break;
- }
- if (hostdata->aborted)
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- AM53C974_write_8(CMDREG, CMDREG_MA);
- break;
- case DISCONNECT:
- DEB_MSG(printk("scsi%d: disconnect message received; cmd %d for target %d, lun %dn",
- instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun));
- cmd->device->disconnect = 1;
- hostdata->disconnecting = 1;
- AM53C974_write_8(CMDREG, CMDREG_MA); /* Accept message by clearing ACK */
- break;
- case SAVE_POINTERS:
- case RESTORE_POINTERS:
- DEB_MSG(printk("scsi%d: save/restore pointers message received; cmd %d for target %d, lun %dn",
- instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun));
- /* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
- * operation, in violation of the SCSI spec so we can safely
- * ignore SAVE/RESTORE pointers calls.
- *
- * Unfortunately, some disks violate the SCSI spec and
- * don't issue the required SAVE_POINTERS message before
- * disconnecting, and we have to break spec to remain
- * compatible. */
- if (hostdata->aborted) {
- DEB_ABORT(printk("ATN set for cmnd %d upon reception of SAVE/REST. POINTERS messagen",
- cmd->cmnd[0]));
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- }
- AM53C974_write_8(CMDREG, CMDREG_MA);
- break;
- case EXTENDED_MESSAGE:
- DEB_MSG(printk("scsi%d: extended message received; cmd %d for target %d, lun %dn",
- instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun));
- /* Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't include first two bytes)
- * 2 code
- * 3..length+1 arguments
- */
- /* BEWARE!! THIS CODE IS EXTREMELY UGLY */
- extended_msg[0] = EXTENDED_MESSAGE;
- AM53C974_read_8(INSTREG); /* clear int */
- AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */
- AM53C974_poll_int();
- /* get length */
- AM53C974_write_8(CMDREG, CMDREG_IT);
- AM53C974_poll_int();
- AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */
- AM53C974_poll_int();
- extended_msg[1] = len = AM53C974_read_8(FFREG); /* get length */
- p = extended_msg + 2;
- /* read the remaining (len) bytes */
- while (len) {
- AM53C974_write_8(CMDREG, CMDREG_IT);
- AM53C974_poll_int();
- if (len > 1) {
- AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */
- AM53C974_poll_int();
- }
- *p = AM53C974_read_8(FFREG);
- p++;
- len--;
- }
- #ifdef AM53C974_DEBUG_MSG
- printk("scsi%d: received extended message: ", instance->host_no);
- for (j = 0; j < extended_msg[1] + 2; j++) {
- printk("0x%02x ", extended_msg[j]);
- if (j && !(j % 16))
- printk("n");
- }
- printk("n");
- #endif
- /* check message */
- if (extended_msg[2] == EXTENDED_SDTR)
- ret = AM53C974_sync_neg(instance, cmd->target, extended_msg);
- if (ret || hostdata->aborted)
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- AM53C974_write_8(CMDREG, CMDREG_MA);
- break;
- default:
- printk("scsi%d: unknown message 0x%02x receivedn", instance->host_no, msg);
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- /* reject message */
- hostdata->msgout[0] = MESSAGE_REJECT;
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- AM53C974_write_8(CMDREG, CMDREG_MA);
- return (0);
- break;
- } /* switch (msg) */
- KEYWAIT();
- return (1);
- }
- /**************************************************************************
- * Function : AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
- *
- * Purpose : try to establish nexus for the command;
- * start sync negotiation via start stop and transfer the command in
- * cmdout phase in case of an inquiry or req. sense command with no
- * sync. neg. performed yet
- *
- * Inputs : instance -- which AM53C974
- * cmd -- command which requires the selection
- * tag -- tagged queueing
- *
- * Returns : nothing
- *
- * Note: this function initializes the selection process, which is continued
- * in the interrupt handler
- **************************************************************************/
- static void AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- unsigned char cfifo, tmp[3];
- unsigned int i, len, cmd_size = COMMAND_SIZE(cmd->cmnd[0]);
- AM53C974_setio(instance);
- cfifo = AM53C974_cfifo();
- if (cfifo) {
- printk("scsi%d: select error; %d residual bytes in FIFOn", instance->host_no, cfifo);
- AM53C974_write_8(CMDREG, CMDREG_CFIFO); /* clear FIFO */
- }
- #ifdef AM53C974_PROHIBIT_DISCONNECT
- tmp[0] = IDENTIFY(0, cmd->lun);
- #else
- tmp[0] = IDENTIFY(1, cmd->lun);
- #endif
- #ifdef SCSI2
- if (cmd->device->tagged_queue && (tag != TAG_NONE)) {
- tmp[1] = SIMPLE_QUEUE_TAG;
- if (tag == TAG_NEXT) {
- /* 0 is TAG_NONE, used to imply no tag for this command */
- if (cmd->device->current_tag == 0)
- cmd->device->current_tag = 1;
- cmd->tag = cmd->device->current_tag;
- cmd->device->current_tag++;
- } else
- cmd->tag = (unsigned char) tag;
- tmp[2] = cmd->tag;
- hostdata->last_message[0] = SIMPLE_QUEUE_TAG;
- len = 3;
- AM53C974_write_8(FFREG, tmp[0]);
- AM53C974_write_8(FFREG, tmp[1]);
- AM53C974_write_8(FFREG, tmp[2]);
- } else
- #endif /* def SCSI2 */
- {
- len = 1;
- AM53C974_write_8(FFREG, tmp[0]);
- cmd->tag = 0;
- }
- /* in case of an inquiry or req. sense command with no sync. neg performed yet, we start
- sync negotiation via start stops and transfer the command in cmdout phase */
- if (((cmd->cmnd[0] == INQUIRY) || (cmd->cmnd[0] == REQUEST_SENSE)) &&
- !(hostdata->sync_neg[cmd->target]) && hostdata->sync_en[cmd->target]) {
- hostdata->sync_neg[cmd->target] = 1;
- hostdata->msgout[0] = EXTENDED_MESSAGE;
- hostdata->msgout[1] = 3;
- hostdata->msgout[2] = EXTENDED_SDTR;
- hostdata->msgout[3] = 250 / (int) hostdata->max_rate[cmd->target];
- hostdata->msgout[4] = hostdata->max_offset[cmd->target];
- len += 5;
- }
- AM53C974_write_8(SDIDREG, SDIREG_MASK & cmd->target); /* setup dest. id */
- AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT); /* setup timeout reg */
- switch (len) {
- case 1:
- for (i = 0; i < cmd_size; i++)
- AM53C974_write_8(FFREG, cmd->cmnd[i]);
- AM53C974_write_8(CMDREG, CMDREG_SAS); /* select with ATN, 1 msg byte */
- hostdata->msgout[0] = NOP;
- break;
- case 3:
- for (i = 0; i < cmd_size; i++)
- AM53C974_write_8(FFREG, cmd->cmnd[i]);
- AM53C974_write_8(CMDREG, CMDREG_SA3S); /* select with ATN, 3 msg bytes */
- hostdata->msgout[0] = NOP;
- break;
- default:
- AM53C974_write_8(CMDREG, CMDREG_SASS); /* select with ATN, stop steps; continue in message out phase */
- break;
- }
- }
- /**************************************************************************
- * Function : AM53C974_intr_select(struct Scsi_Host *instance, unsigned char statreg)
- *
- * Purpose : handle reselection
- *
- * Inputs : instance -- which AM53C974
- * statreg -- status register
- *
- * Returns : nothing
- *
- * side effects: manipulates hostdata
- **************************************************************************/
- static void AM53C974_intr_reselect(struct Scsi_Host *instance, unsigned char statreg)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- unsigned char cfifo, msg[3], lun, t, target = 0;
- #ifdef SCSI2
- unsigned char tag;
- #endif
- Scsi_Cmnd *tmp = NULL, *prev;
- AM53C974_setio(instance);
- cfifo = AM53C974_cfifo();
- if (hostdata->selecting) {
- /* caught reselect interrupt in selection process;
- put selecting command back into the issue queue and continue with the
- reselecting command */
- DEB_RESEL(printk("AM53C974_intr_reselect: in selection processn"));
- LIST(hostdata->sel_cmd, hostdata->issue_queue);
- hostdata->sel_cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = hostdata->sel_cmd;
- hostdata->sel_cmd = NULL;
- hostdata->selecting = 0;
- }
- /* 2 bytes must be in the FIFO now */
- if (cfifo != 2) {
- printk("scsi %d: error: %d bytes in fifo, 2 expectedn", instance->host_no, cfifo);
- hostdata->aborted = 1;
- goto EXIT_ABORT;
- }
- /* determine target which reselected */
- t = AM53C974_read_8(FFREG);
- if (!(t & (1 << instance->this_id))) {
- printk("scsi %d: error: invalid host idn", instance->host_no);
- hostdata->aborted = 1;
- goto EXIT_ABORT;
- }
- t ^= (1 << instance->this_id);
- target = 0;
- while (t != 1) {
- t >>= 1;
- target++;
- }
- DEB_RESEL(printk("scsi %d: reselect; target: %dn", instance->host_no, target));
- if (hostdata->aborted)
- goto EXIT_ABORT;
- if ((statreg & STATREG_PHASE) != PHASE_MSGIN) {
- printk("scsi %d: error: upon reselection interrupt not in MSGINn", instance->host_no);
- hostdata->aborted = 1;
- goto EXIT_ABORT;
- }
- msg[0] = AM53C974_read_8(FFREG);
- if (!msg[0] & 0x80) {
- printk("scsi%d: error: expecting IDENTIFY message, got ", instance->host_no);
- print_msg(msg);
- hostdata->aborted = 1;
- goto EXIT_ABORT;
- }
- lun = (msg[0] & 0x07);
- /* We need to add code for SCSI-II to track which devices have
- * I_T_L_Q nexuses established, and which have simple I_T_L
- * nexuses so we can chose to do additional data transfer. */
- #ifdef SCSI2
- #error "SCSI-II tagged queueing is not supported yet"
- #endif
- /* Find the command corresponding to the I_T_L or I_T_L_Q nexus we
- * just reestablished, and remove it from the disconnected queue. */
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
- tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
- if ((target == tmp->target) && (lun == tmp->lun)
- #ifdef SCSI2
- && (tag == tmp->tag)
- #endif
- ) {
- if (prev) {
- REMOVE(prev, (Scsi_Cmnd *) (prev->host_scribble), tmp,
- (Scsi_Cmnd *) (tmp->host_scribble));
- prev->host_scribble = tmp->host_scribble;
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
- hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble;
- }
- tmp->host_scribble = NULL;
- hostdata->connected = tmp;
- break;
- }
- if (!tmp) {
- #ifdef SCSI2
- printk("scsi%d: warning : target %d lun %d tag %d not in disconnect_queue.n",
- instance->host_no, target, lun, tag);
- #else
- printk("scsi%d: warning : target %d lun %d not in disconnect_queue.n",
- instance->host_no, target, lun);
- #endif
- /* Since we have an established nexus that we can't do anything with, we must abort it. */
- hostdata->aborted = 1;
- DEB(AM53C974_keywait());
- goto EXIT_ABORT;
- } else
- goto EXIT_OK;
- EXIT_ABORT:
- AM53C974_write_8(CMDREG, CMDREG_SATN);
- AM53C974_write_8(CMDREG, CMDREG_MA);
- return;
- EXIT_OK:
- DEB_RESEL(printk("scsi%d: nexus established, target = %d, lun = %d, tag = %dn",
- instance->host_no, target, tmp->lun, tmp->tag));
- AM53C974_set_sync(instance, target);
- AM53C974_write_8(SDIDREG, SDIREG_MASK & target); /* setup dest. id */
- AM53C974_write_8(CMDREG, CMDREG_MA);
- hostdata->dma_busy = 0;
- hostdata->connected->SCp.phase = PHASE_CMDOUT;
- }
- /**************************************************************************
- * Function : AM53C974_transfer_dma(struct Scsi_Host *instance, short dir,
- * unsigned long length, char *data)
- *
- * Purpose : setup DMA transfer
- *
- * Inputs : instance -- which AM53C974
- * dir -- direction flag, 0: write to device, read from memory;
- * 1: read from device, write to memory
- * length -- number of bytes to transfer to from buffer
- * data -- pointer to data buffer
- *
- * Returns : nothing
- **************************************************************************/
- static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir,
- unsigned long length, char *data)
- {
- AM53C974_local_declare();
- AM53C974_setio(instance);
- AM53C974_write_8(CMDREG, CMDREG_NOP);
- AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D); /* idle command */
- AM53C974_write_8(STCLREG, (unsigned char) (length & 0xff));
- AM53C974_write_8(STCMREG, (unsigned char) ((length & 0xff00) >> 8));
- AM53C974_write_8(STCHREG, (unsigned char) ((length & 0xff0000) >> 16));
- AM53C974_write_32(DMASTC, length & 0xffffff);
- AM53C974_write_32(DMASPA, virt_to_bus(data));
- AM53C974_write_8(CMDREG, CMDREG_IT | CMDREG_DMA);
- AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D | DMACMD_START);
- }
- /**************************************************************************
- * Function : AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus,
- * unsigned char statreg)
- *
- * Purpose : cleanup DMA transfer
- *
- * Inputs : instance -- which AM53C974
- * dmastatus -- dma status register
- * statreg -- status register
- *
- * Returns : nothing
- **************************************************************************/
- static void AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus,
- unsigned char statreg)
- {
- AM53C974_local_declare();
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- unsigned long ctcreg;
- int dir = statreg & STATREG_IO;
- int cfifo, pio, i = 0;
- AM53C974_setio(instance);
- do {
- cfifo = AM53C974_cfifo();
- i++;
- } while (cfifo && (i < 50000));
- pio = (i == 50000) ? 1 : 0;
- if (statreg & STATREG_CTZ) {
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- return;
- }
- if (dmastatus & DMASTATUS_DONE) {
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- return;
- }
- AM53C974_write_8(DMACMD, ((dir << 7) & DMACMD_DIR) | DMACMD_BLAST);
- while (!(AM53C974_read_8(DMASTATUS) & DMASTATUS_BCMPLT));
- AM53C974_write_8(DMACMD, DMACMD_IDLE);
- if (pio) {
- /* transfer residual bytes via PIO */
- unsigned char *wac = (unsigned char *) AM53C974_read_32(DMAWAC);
- printk("pio mode, residual=%dn", AM53C974_read_8(CFIREG) & CFIREG_CF);
- while (AM53C974_read_8(CFIREG) & CFIREG_CF)
- *(wac++) = AM53C974_read_8(FFREG);
- }
- ctcreg = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) |
- (AM53C974_read_8(CTCHREG) << 16);
- hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - ctcreg;
- hostdata->connected->SCp.this_residual = ctcreg;
- }
- /**************************************************************************
- * Function : AM53C974_intr_bus_reset(struct Scsi_Host *instance)
- *
- * Purpose : handle bus reset interrupt
- *
- * Inputs : instance -- which AM53C974
- *
- * Returns : nothing
- **************************************************************************/
- static void AM53C974_intr_bus_reset(struct Scsi_Host *instance)
- {
- AM53C974_local_declare();
- unsigned char cntlreg1;
- AM53C974_setio(instance);
- AM53C974_write_8(CMDREG, CMDREG_CFIFO);
- AM53C974_write_8(CMDREG, CMDREG_NOP);
- cntlreg1 = AM53C974_read_8(CNTLREG1);
- AM53C974_write_8(CNTLREG1, cntlreg1 | CNTLREG1_DISR);
- }
- /**************************************************************************
- * Function : int AM53C974_abort(Scsi_Cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
- * used.
- *
- * Returns : 0 - success, -1 on failure.
- **************************************************************************/
- static int AM53C974_abort(Scsi_Cmnd * cmd)
- {
- AM53C974_local_declare();
- unsigned long flags;
- struct Scsi_Host *instance = cmd->host;
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- Scsi_Cmnd *tmp, **prev;
- #ifdef AM53C974_DEBUG
- deb_stop = 1;
- #endif
- save_flags(flags);
- cli();
- AM53C974_setio(instance);
- DEB_ABORT(printk(SEPARATOR_LINE));
- DEB_ABORT(printk("scsi%d : AM53C974_abort called -- trouble starts!!n", instance->host_no));
- DEB_ABORT(AM53C974_print(instance));
- DEB_ABORT(AM53C974_keywait());
- /* Case 1 : If the command is the currently executing command,
- we'll set the aborted flag and return control so that the
- information transfer routine can exit cleanly. */
- if ((hostdata->connected == cmd) || (hostdata->sel_cmd == cmd)) {
- DEB_ABORT(printk("scsi%d: aborting connected commandn", instance->host_no));
- hostdata->aborted = 1;
- hostdata->msgout[0] = ABORT;
- restore_flags(flags);
- return (SCSI_ABORT_PENDING);
- }
- /* Case 2 : If the command hasn't been issued yet,
- we simply remove it from the issue queue. */
- for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue),
- tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp;
- prev = (Scsi_Cmnd **) & (tmp->host_scribble),
- tmp = (Scsi_Cmnd *) tmp->host_scribble) {
- if (cmd == tmp) {
- DEB_ABORT(printk("scsi%d : abort removed command from issue queue.n", instance->host_no));
- REMOVE(5, *prev, tmp, tmp->host_scribble);
- (*prev) = (Scsi_Cmnd *) tmp->host_scribble;
- tmp->host_scribble = NULL;
- tmp->result = DID_ABORT << 16;
- restore_flags(flags);
- tmp->done(tmp);
- return (SCSI_ABORT_SUCCESS);
- }
- #ifdef AM53C974_DEBUG_ABORT
- else {
- if (prev == (Scsi_Cmnd **) tmp)
- printk("scsi%d : LOOPn", instance->host_no);
- }
- #endif
- }
- /* Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail. */
- if (hostdata->connected || hostdata->sel_cmd) {
- DEB_ABORT(printk("scsi%d : abort failed, other command connected.n", instance->host_no));
- restore_flags(flags);
- return (SCSI_ABORT_NOT_RUNNING);
- }
- /* Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message. */
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
- tmp = (Scsi_Cmnd *) tmp->host_scribble) {
- if (cmd == tmp) {
- DEB_ABORT(printk("scsi%d: aborting disconnected commandn", instance->host_no));
- hostdata->aborted = 1;
- hostdata->msgout[0] = ABORT;
- hostdata->selecting = 1;
- hostdata->sel_cmd = tmp;
- AM53C974_write_8(CMDREG, CMDREG_DSR);
- restore_flags(flags);
- return (SCSI_ABORT_PENDING);
- }
- }
- /* Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke. */
- DEB_ABORT(printk("scsi%d : abort failed, command not found.n", instance->host_no));
- restore_flags(flags);
- return (SCSI_ABORT_NOT_RUNNING);
- }
- /**************************************************************************
- * Function : int AM53C974_reset(Scsi_Cmnd *cmd)
- *
- * Purpose : reset the SCSI controller and bus
- *
- * Inputs : cmd -- which command within the command block was responsible for the reset
- *
- * Returns : status (SCSI_ABORT_SUCCESS)
- *
- * FIXME(eric) the reset_flags are ignored.
- **************************************************************************/
- static int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int reset_flags)
- {
- AM53C974_local_declare();
- unsigned long flags;
- int i;
- struct Scsi_Host *instance = cmd->host;
- struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata;
- AM53C974_setio(instance);
- save_flags(flags);
- cli();
- DEB(printk("AM53C974_reset called; "));
- printk("AM53C974_reset calledn");
- AM53C974_print(instance);
- AM53C974_keywait();
- /* do hard reset */
- AM53C974_write_8(CMDREG, CMDREG_RDEV);
- AM53C974_write_8(CMDREG, CMDREG_NOP);
- hostdata->msgout[0] = NOP;
- for (i = 0; i < 8; i++) {
- hostdata->busy[i] = 0;
- hostdata->sync_per[i] = DEF_STP;
- hostdata->sync_off[i] = 0;
- hostdata->sync_neg[i] = 0;
- }
- hostdata->last_message[0] = NOP;
- hostdata->sel_cmd = NULL;
- hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
- hostdata->in_reset = 0;
- hostdata->aborted = 0;
- hostdata->selecting = 0;
- hostdata->disconnecting = 0;
- hostdata->dma_busy = 0;
- /* reset bus */
- AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
- AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */
- udelay(40);
- AM53C974_config_after_reset(instance);
- restore_flags(flags);
- cmd->result = DID_RESET << 16;
- cmd->scsi_done(cmd);
- return SCSI_ABORT_SUCCESS;
- }
- /*
- * AM53C974_release()
- *
- * Release resources allocated for a single AM53C974 adapter.
- */
- static int AM53C974_release(struct Scsi_Host *shp)
- {
- free_irq(shp->irq, shp);
- scsi_unregister(shp);
- return 0;
- }
- /* You can specify overrides=a,b,c,d in the same format at AM53C974=a,b,c,d
- on boot up */
- MODULE_PARM(overrides, "1-32i");
- MODULE_LICENSE("GPL");
- static Scsi_Host_Template driver_template = AM53C974;
- #include "scsi_module.c"