From a8674363a780af0532dfc8081f7e77fee87b46e4 Mon Sep 17 00:00:00 2001 From: phil Date: Fri, 9 Jun 1995 04:36:14 +0000 Subject: [PATCH] Replacement of the NCR driver by the Leo Weppelman NCR driver as ported by Matthias Pfaller (Thanks to both!) and a RCS id. --- sys/arch/pc532/dev/ncr.c | 2743 +++++++++++++++++++++++---------- sys/arch/pc532/dev/ncr_5380.h | 145 -- sys/arch/pc532/dev/ncr_defs.h | 57 - sys/arch/pc532/dev/ncrreg.h | 145 ++ sys/arch/pc532/dev/scn.c | 2 +- 5 files changed, 2033 insertions(+), 1059 deletions(-) delete mode 100644 sys/arch/pc532/dev/ncr_5380.h delete mode 100644 sys/arch/pc532/dev/ncr_defs.h create mode 100644 sys/arch/pc532/dev/ncrreg.h diff --git a/sys/arch/pc532/dev/ncr.c b/sys/arch/pc532/dev/ncr.c index 63a518eb72dc..a91b3c2434a7 100644 --- a/sys/arch/pc532/dev/ncr.c +++ b/sys/arch/pc532/dev/ncr.c @@ -1,9 +1,8 @@ -/* $NetBSD: ncr.c,v 1.12 1995/05/16 07:30:36 phil Exp $ */ +/* $NetBSD: ncr.c,v 1.13 1995/06/09 04:36:14 phil Exp $ */ /* - * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, - * Michael L. Finch, Bradley A. Grantham, and - * Lawrence A. Kesteloot + * Copyright (c) 1995 Leo Weppelman. + * PC532-Port by Matthias Pfaller. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -16,284 +15,215 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by the Alice Group. - * 4. The names of the Alice Group or any of its members may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission * - * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* Modified for use with the pc532 by Phil Nelson, June 94. */ - -#define PSEUDO_DMA 1 - -static int ncr_debug=1; - -#include -#include #include #include -#include -#include #include -#include -#include #include +#include #include -#include +#include #include - -#include - -#include "ncr_defs.h" -#include "ncr_5380.h" - -#define NCR5380 DP8490 - -#define SCI_PHASE_DISC 0 /* sort of ... */ -#define SCI_CLR_INTR(regs) {register int temp = regs->sci_iack;} -#define SCI_ACK(ptr,phase) (ptr)->sci_tcmd = (phase) -#define SCSI_TIMEOUT_VAL 10000000 -#define WAIT_FOR_NOT_REQ(ptr) { \ - int scsi_timeout = SCSI_TIMEOUT_VAL; \ - while ( ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ - ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ - ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ - (--scsi_timeout) ); \ - if (!scsi_timeout) { \ - printf("scsi timeout--WAIT_FOR_NOT_REQ---ncr.c, \ - line %d.\n", __LINE__); \ - goto scsi_timeout_error; \ - } \ - } - -#define WAIT_FOR_REQ(ptr) { \ - int scsi_timeout = SCSI_TIMEOUT_VAL; \ - while ( (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ - (--scsi_timeout) ); \ - if (!scsi_timeout) { \ - printf("scsi timeout--WAIT_FOR_REQ---ncr.c, \ - line %d.\n", __LINE__); \ - goto scsi_timeout_error; \ - } \ - } -#define WAIT_FOR_BSY(ptr) { \ - int scsi_timeout = SCSI_TIMEOUT_VAL; \ - while ((((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ - (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ - (--scsi_timeout) ); \ - if (!scsi_timeout) { \ - printf("scsi timeout--WAIT_FOR_BSY---ncr.c, \ - line %d.\n", __LINE__); \ - goto scsi_timeout_error; \ - } \ - } - -#ifdef DDB -int Debugger(); -#else -#define Debugger() panic("Should call Debugger here (mac/dev/ncr.c).") -#endif - -typedef unsigned long int physaddr; -typedef sci_regmap_t sci_padded_regmap_t; - -#define NNCR5380 1 - -struct ncr5380_softc { - struct device sc_dev; - struct scsi_link sc_link; -}; - -/* From the mapping of the pc532 address space. See pc532/machdep.c */ -static volatile sci_padded_regmap_t *ncr = (sci_regmap_t *) 0xffd00000; -static volatile long *sci_4byte_addr= (long *) 0xffe00000; -static volatile u_char *sci_1byte_addr=(u_char *) 0xffe00000; - -static void ncr5380_minphys(struct buf *bp); -static int ncr5380_scsi_cmd(struct scsi_xfer *xs); - -static int ncr5380_show_scsi_cmd(struct scsi_xfer *xs); -static int ncr5380_reset_target(int adapter, int target); -static int ncr5380_poll(int adapter, int timeout); -static int ncr5380_send_cmd(struct scsi_xfer *xs); - -extern void ncr5380_intr(int adapter); -extern void spinwait(int); - -static int scsi_gen(int adapter, int id, int lun, - struct scsi_generic *cmd, int cmdlen, - void *databuf, int datalen); -static int scsi_group0(int adapter, int id, int lun, - int opcode, int addr, int len, - int flags, caddr_t databuf, int datalen); - -static char scsi_name[] = "ncr"; - -struct scsi_adapter ncr5380_switch = { - ncr5380_scsi_cmd, /* scsi_cmd() */ - ncr5380_minphys, /* scsi_minphys() */ - 0, /* open_target_lu() */ - 0 /* close_target_lu() */ -}; - -/* This is copied from julian's bt driver */ -/* "so we have a default dev struct for our link struct." */ -struct scsi_device ncr_dev = { - NULL, /* Use default error handler. */ - NULL, /* have a queue, served by this (?) */ - NULL, /* have no async handler. */ - NULL /* Use default "done" routine. */ -}; - -extern int matchbyname(); -static int ncrprobe(); -static void ncrattach(); - -struct cfdriver ncrcd = - { NULL, "ncr", ncrprobe, ncrattach, - DV_DULL, sizeof(struct ncr5380_softc), NULL, 0 }; - -static int -ncrprobe(parent, self, aux) - struct device *parent, *self; - void *aux; -{ -/* int unit = cf->cf_unit; */ - struct ncr5380_softc *ncr5380 = (void *)self; - -#if 0 -DELETE THIS ???? - if (unit >= NNCR5380) { - printf("ncr5380attach: unit %d more than %d configured.\n", - unit+1, NNCR5380); - return 0; - } - ncr5380 = malloc(sizeof(struct ncr5380_data), M_TEMP, M_NOWAIT); - if (!ncr5380) { - printf("ncr5380attach: Can't malloc.\n"); - return 0; - } - - bzero(ncr5380, sizeof(*ncr5380)); - ncr5380data[unit] = ncr5380; -#endif - - /* If we call this, we need to add SPL_DP to the bio mask! */ - /* PL_bio |= SPL_DP; Not yet ... no interrupts */ - - return 1; -} - -static void -ncrattach(parent, self, aux) - struct device *parent, *self; - void *aux; -{ - register volatile sci_padded_regmap_t *regs = ncr; - struct ncr5380_softc *ncr5380 = (void *)self; - int r; - - ncr5380->sc_link.adapter_softc = ncr5380; -/* ncr5380->sc_link.scsibus = 0; */ - ncr5380->sc_link.adapter_target = 7; - ncr5380->sc_link.adapter = &ncr5380_switch; - ncr5380->sc_link.device = &ncr_dev; - ncr5380->sc_link.openings = 1; - - printf("\n"); - - config_found(self, &(ncr5380->sc_link), NULL); -} - -#define MIN_PHYS 65536 /*BARF!!!!*/ -static void -ncr5380_minphys(struct buf *bp) -{ - if (bp->b_bcount > MIN_PHYS) { - printf("Uh-oh... ncr5380_minphys setting bp->b_bcount = %x.\n", MIN_PHYS); - bp->b_bcount = MIN_PHYS; - } -} -#undef MIN_PHYS - -static int -ncr5380_scsi_cmd(struct scsi_xfer *xs) -{ - int flags, s, r; - - flags = xs->flags; - if (xs->bp) flags |= (SCSI_NOSLEEP); - if ( flags & ITSDONE ) { - printf("Already done?"); - xs->flags &= ~ITSDONE; - } - if ( ! ( flags & INUSE ) ) { - printf("Not in use?"); - xs->flags |= INUSE; - } - - if ( flags & SCSI_RESET ) { - printf("flags & SCSIRESET.\n"); - s = splbio(); - ncr5380_reset_target(xs->sc_link->scsibus, - xs->sc_link->target); - splx(s); - return(COMPLETE); - } - - xs->resid = 0; /* Default value? */ - r = ncr5380_send_cmd(xs); - xs->flags |= ITSDONE; - scsi_done(xs); - switch(r) { - case COMPLETE: case SUCCESSFULLY_QUEUED: - r = SUCCESSFULLY_QUEUED; - if (xs->flags&SCSI_POLL) - r = COMPLETE; - break; - default: - break; - } - return r; -} - -static int -ncr5380_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *) xs->cmd; - int i = 0; - - if ( ! ( xs->flags & SCSI_RESET ) ) { - printf("ncr5380(%d:%d:%d)-", - xs->sc_link->scsibus, xs->sc_link->target, xs->sc_link->lun); - while (i < xs->cmdlen) { - if (i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } else { - printf("ncr5380(%d:%d:%d)-RESET-\n", - xs->sc_link->scsibus, xs->sc_link->target, xs->sc_link->lun); - } -} +#include "ncrreg.h" /* - * Actual chip control. + * SCSI completion status codes, should move to sys/scsi/???? */ +#define SCSMASK 0x1e /* status code mask */ +#define SCSGOOD 0x00 /* good status */ +#define SCSCHKC 0x02 /* check condition */ +#define SCSBUSY 0x08 /* busy status */ +#define SCSCMET 0x04 /* condition met / good */ + +/********************************************************************/ + +#define NREQ 18 /* Size of issue queue */ +#define AUTO_SENSE 1 /* Automatically issue a request-sense */ + +#undef DBG_SEL /* Show the selection process */ +#undef DBG_REQ /* Show enqueued/ready requests */ +#undef DBG_NOWRITE /* Do not allow writes to the targets */ +#undef DBG_PIO /* Show the polled-I/O process */ +#undef DBG_INF /* Show information transfer process */ +#undef DBG_NOSTATIC /* No static functions, all in DDB trace*/ +#undef DBG_PID /* Keep track of driver */ +#undef REAL_DMA /* Use DMA if sensible */ +#undef REAL_DMA_POLL 0 /* 1: Poll for end of DMA-transfer */ + +#ifdef DBG_NOSTATIC +# define static +#endif +#ifdef DBG_SEL +# define DBG_SELPRINT(a,b) printf(a,b) +#else +# define DBG_SELPRINT(a,b) +#endif +#ifdef DBG_PIO +# define DBG_PIOPRINT(a,b,c) printf(a,b,c) +#else +# define DBG_PIOPRINT(a,b,c) +#endif +#ifdef DBG_INF +# define DBG_INFPRINT(a,b,c) a(b,c) +#else +# define DBG_INFPRINT(a,b,c) +#endif +#ifdef DBG_PID + static char *last_hit = NULL; +# define PID(a) last_hit = a +#else +# define PID(a) +#endif + +/* + * Return values of check_intr() + */ +#define INTR_SPURIOUS 0 +#define INTR_RESEL 2 +#define INTR_DMA 3 + +/* + * Set bit for target when parity checking must be disabled. + * My (LWP) Maxtor 7245S seems to generate parity errors on about 50% + * of all transfers while the data is correct!? + */ +u_char ncr5380_no_parchk = 0; + +/* + * This is the default sense-command we send. + */ +static u_char sense_cmd[] = { + REQUEST_SENSE, 0, 0, 0, sizeof(struct scsi_sense), 0 +}; + +/* + * True if the main co-routine is running + */ +static volatile int main_running = 0; + +/* + * Mask of targets selected + */ +u_char busy; + +struct ncr_softc { + struct device sc_dev; + struct scsi_link sc_link; +}; + +static void ncr5380_minphys(struct buf *bp); +static int ncr5380_scsi_cmd(struct scsi_xfer *xs); +static int ncr5380_show_scsi_cmd(struct scsi_xfer *xs); + +struct scsi_adapter ncr5380_switch = { + ncr5380_scsi_cmd, /* scsi_cmd() */ + ncr5380_minphys, /* scsi_minphys() */ + 0, /* open_target_lu() */ + 0 /* close_target_lu() */ +}; + +struct scsi_device ncr5380_dev = { + NULL, /* use default error handler */ + NULL, /* do not have a start function */ + NULL, /* have no async handler */ + NULL /* Use default done routine */ +}; + +/* + * Max. number of dma-chains per request + */ +#define MAXDMAIO (MAXPHYS/NBPG + 1) + +/* + * Some requests are not contiguous in physical memory. We need to break them + * up into contiguous parts for DMA. + */ +struct dma_chain { + u_int dm_count; + u_long dm_addr; +}; + +/* + * Define our issue, free and disconnect queue's. + */ +typedef struct req_q { + struct req_q *next; /* next in free, issue or discon queue */ + struct req_q *link; /* next linked command to execute */ + struct scsi_xfer *xs; /* request from high-level driver */ + u_char dr_flag; /* driver state */ + u_char phase; /* current SCSI phase */ + u_char msgout; /* message to send when requested */ + u_char targ_id; /* target for command */ + u_char status; /* returned status byte */ + u_char message; /* returned message byte */ +#ifdef REAL_DMA + struct dma_chain dm_chain[MAXDMAIO]; + struct dma_chain *dm_cur; /* current dma-request */ + struct dma_chain *dm_last; /* last dma-request */ +#endif + long xdata_len; /* length of transfer */ + u_char *xdata_ptr; /* physical address of transfer */ + struct scsi_generic xcmd; /* command to execute */ +} SC_REQ; + +/* + * Values for dr_flag: + */ +#define DRIVER_IN_DMA 1 /* Non-polled DMA activated */ +#define DRIVER_AUTOSEN 2 /* Doing automatic sense */ +#define DRIVER_NOINT 4 /* We are booting: no interrupts */ +#define DRIVER_DMAOK 8 /* DMA can be used on this request */ + + +static SC_REQ req_queue[NREQ]; +static SC_REQ *free_head = NULL; /* Free request structures */ +static SC_REQ *issue_q = NULL; /* Commands waiting to be issued*/ +static SC_REQ *discon_q = NULL; /* Commands disconnected */ +static SC_REQ *connected = NULL; /* Command currently connected */ + +/* + * Function decls: + */ +static int transfer_pio __P((u_char *, u_char *, u_long *)); +static void transfer_pdma __P((u_char *, u_char *, u_long *)); +static int wait_req_true __P((void)); +static int wait_req_false __P((void)); +static int scsi_select __P((SC_REQ *, int)); +static int handle_message __P((SC_REQ *, u_int)); +static int information_transfer __P((void)); +static void reselect __P((void)); +static int dma_ready __P((int, int)); +static int check_autosense __P((SC_REQ *, int)); +static int reach_msg_out __P((u_long)); +static void timer __P((void)); +static int check_intr __P((void)); +static void scsi_reset __P((void)); +static void scsi_main __P((void)); +#ifdef REAL_DMA +static int scsi_dmaok __P((SC_REQ *)); +#else +#define scsi_dmaok(x) 0 +#endif +static void run_main __P((void)); +static void ncr_intr __P((void *)); +static void show_request __P((SC_REQ *, char *)); +static void show_phase __P((SC_REQ *, int)); +static void show_signals __P((void)); void delay(int timeo) @@ -302,649 +232,1750 @@ delay(int timeo) for (len=0;len> 4) & 0xf) { + case 0: + case 1: + return(6); + case 2: + case 3: + return(10); + } + return(12); } + +/* + * Wait for request-line to become active. When it doesn't return 0. + * Otherwise return != 0. + * The timeouts in the 'wait_req_*' functions are arbitrary and rather + * large. In 99% of the invocations nearly no timeout is needed but in + * some cases (especially when using my tapedrive, a Tandberg 3600) the + * device is busy internally and the first SCSI-phase will be delayed. + */ +extern __inline__ int wait_req_true(void) +{ + int timeout = 25000; + + while(!(SCSI_5380->scsi_idstat & SC_S_REQ) && --timeout) + delay(1); + return(SCSI_5380->scsi_idstat & SC_S_REQ); +} + +/* + * Wait for request-line to become inactive. When it doesn't return 0. + * Otherwise return != 0. + */ +extern __inline__ int wait_req_false(void) +{ + int timeout = 25000; + + while((SCSI_5380->scsi_idstat & SC_S_REQ) && --timeout) + delay(1); + return(!(SCSI_5380->scsi_idstat & SC_S_REQ)); +} + +extern __inline__ void finish_req(SC_REQ *reqp) +{ + int sps; + struct scsi_xfer *xs = reqp->xs; + + /* + * Return request to free-q + */ + sps = splbio(); + reqp->next = free_head; + free_head = reqp; + splx(sps); + + xs->flags |= ITSDONE; + scsi_done(xs); +} + +/* + * Auto config stuff.... + */ +void ncr_attach __P((struct device *, struct device *, void *)); +int ncr_match __P((struct device *, struct cfdata *, void *)); + +struct cfdriver ncrcd = { + NULL, "ncr", (cfmatch_t)ncr_match, ncr_attach, + DV_DULL, sizeof(struct ncr_softc), NULL, 0 }; + +int +ncr_match(pdp, cdp, auxp) +struct device *pdp; +struct cfdata *cdp; +void *auxp; +{ + if(cdp->cf_unit != 0) /* Only one unit */ + return(0); + return(1); +} + +void +ncr_attach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + struct ncr_softc *sc; + int i; + + sc = (struct ncr_softc *)dp; + + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = 7; + sc->sc_link.adapter = &ncr5380_switch; + sc->sc_link.device = &ncr5380_dev; + sc->sc_link.openings = NREQ - 1; + + /* + * Initialize request queue freelist. + */ + for(i = 0; i < NREQ; i++) { + req_queue[i].next = free_head; + free_head = &req_queue[i]; + } + + /* + * Initialize the host adapter + */ + SCSI_5380->scsi_icom = 0; + SCSI_5380->scsi_mode = IMODE_BASE; + SCSI_5380->scsi_tcom = 0; + SCSI_5380->scsi_idstat = 0; + intr_disable(IR_SCSI1); + i = intr_establish(SOFTINT, run_main, NULL, "softncr", IPL_BIO, 0); + intr_establish(IR_SCSI1, ncr_intr, (void *)i, "ncr", IPL_BIO, RAISING_EDGE); + printf("\n"); + + /* + * attach all scsi units on us + */ + config_found(dp, &sc->sc_link, NULL); + intr_enable(IR_SCSI1); +} + +/* + * End of auto config stuff.... + */ + +/* + * Carry out a request from the high level driver. + */ +static int +ncr5380_scsi_cmd(struct scsi_xfer *xs) +{ + int sps; + SC_REQ *reqp; + int flags = xs->flags; + + /* + * Sanity check on flags... + */ + if(flags & ITSDONE) { + printf("ncr5380_scsi_cmd: command already done.....\n"); + xs->flags &= ~ITSDONE; + } + if(!(flags & INUSE)) { + printf("ncr5380_scsi_cmd: command not in use.....\n"); + xs->flags |= ~INUSE; + } + + /* + * LWP: No lun support yet XXX + */ + if(xs->sc_link->lun != 0) { + xs->error = XS_DRIVER_STUFFUP; /* XXX */ + return(COMPLETE); + } + + /* + * We do not queue RESET commands + */ + if(flags & SCSI_RESET) { + scsi_reset(); + return(COMPLETE); + } + + /* + * Get a request block + */ + sps = splbio(); + if((reqp = free_head) == 0) { + splx(sps); + return(TRY_AGAIN_LATER); + } + free_head = reqp->next; + reqp->next = NULL; + splx(sps); + + /* + * Initialize our private fields + */ + reqp->dr_flag = (xs->flags & SCSI_POLL) ? DRIVER_NOINT : 0; + reqp->phase = NR_PHASE; + reqp->msgout = MSG_NOOP; + reqp->status = SCSGOOD; + reqp->link = NULL; + reqp->xs = xs; + reqp->targ_id = xs->sc_link->target; + reqp->xdata_ptr = (u_char*)xs->data; + reqp->xdata_len = xs->datalen; + memcpy(&reqp->xcmd, xs->cmd, sizeof(struct scsi_generic)); + + /* + * Check if DMA can be used on this request + */ + if(!(xs->flags & SCSI_POLL) && scsi_dmaok(reqp)) + reqp->dr_flag |= DRIVER_DMAOK; + + /* + * Insert the command into the issue queue. Note that 'REQUEST SENSE' + * commands are inserted at the head of the queue since any command + * will clear the existing contingent allegience condition and the sense + * data is only valid while the condition exists. + * When possible, link the command to a previous command to the same + * target. This is not very sensible when AUTO_SENSE is not defined! + * Interrupts are disabled while we are fiddling with the issue-queue. + */ + sps = splbio(); + if((issue_q == NULL) || (reqp->xcmd.opcode == REQUEST_SENSE)) { + reqp->next = issue_q; + issue_q = reqp; + } + else { + SC_REQ *tmp, *link; + + tmp = issue_q; + link = NULL; + do { + if(!link && (tmp->targ_id == reqp->targ_id) && !tmp->link) + link = tmp; + } while(tmp->next && (tmp = tmp->next)); + tmp->next = reqp; +#ifdef AUTO_SENSE + if(link) { + link->link = reqp; + link->xcmd.bytes[link->xs->cmdlen-1] |= 1; + } +#endif + } + splx(sps); + +#ifdef DBG_REQ + show_request(reqp,(reqp->xcmd.opcode == REQUEST_SENSE) ? "HEAD":"TAIL"); #endif -extern void -ncr5380_intr(int adapter) -{ - register volatile sci_padded_regmap_t *regs = ncr; - - SCI_CLR_INTR(regs); - regs->sci_mode = 0x00; + run_main(); + if(xs->flags & SCSI_POLL) + return(COMPLETE); /* We're booting */ + return(SUCCESSFULLY_QUEUED); } -extern int -scsi_irq_intr(void) +#define MIN_PHYS 65536 /*BARF!!!!*/ +static void +ncr5380_minphys(struct buf *bp) { - register volatile sci_padded_regmap_t *regs = ncr; - -/* if (regs->sci_csr != SCI_CSR_PHASE_MATCH) - printf("scsi_irq_intr called (not just phase match -- " - "csr = 0x%x, bus_csr = 0x%x).\n", - regs->sci_csr, regs->sci_bus_csr); - ncr5380_intr(0); */ - return 1; -} - -extern int -scsi_drq_intr(void) -{ -/* printf("scsi_drq_intr called.\n"); */ -/* ncr5380_intr(0); */ - return 1; + if(bp->b_bcount > MIN_PHYS) { + printf("Uh-oh... ncr5380_minphys setting bp->b_bcount=%x.\n",MIN_PHYS); + bp->b_bcount = MIN_PHYS; + } } +#undef MIN_PHYS static int -ncr5380_reset_target(int adapter, int target) +ncr5380_show_scsi_cmd(struct scsi_xfer *xs) { - register volatile sci_padded_regmap_t *regs = ncr; - int dummy; + u_char *b = (u_char *) xs->cmd; + int i = 0; - scsi_select_ctlr (NCR5380); - regs->sci_icmd = SCI_ICMD_TEST; - regs->sci_icmd = SCI_ICMD_TEST | SCI_ICMD_RST; - delay(2500); - regs->sci_icmd = 0; - - regs->sci_mode = 0; - regs->sci_tcmd = SCI_PHASE_DISC; - regs->sci_sel_enb = 0; - - SCI_CLR_INTR(regs); - SCI_CLR_INTR(regs); + if(!(xs->flags & SCSI_RESET)) { + printf("ncr5380(%d:%d:%d,0x%x)-", xs->sc_link->scsibus, + xs->sc_link->target, xs->sc_link->lun, xs->sc_link->flags); + while(i < xs->cmdlen) { + if(i) + printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else { + printf("ncr5380(%d:%d:%d)-RESET-\n", + xs->sc_link->scsibus,xs->sc_link->target, xs->sc_link->lun); + } } - -static int -ncr5380_send_cmd(struct scsi_xfer *xs) +/* + * The body of the driver. + */ +static void +scsi_main() { - int s, i, sense; + SC_REQ *req, *prev; + int itype; + int sps; -#if 0 - ncr5380_show_scsi_cmd(xs); + /* + * While running in the driver SCSI-interrupts are disabled. + */ + intr_disable(IR_SCSI1); + + scsi_select_ctlr(DP8490); + PID(")"); + for(;;) { + sps = splbio(); + if(!connected) { + + /* + * Search through the issue-queue for a command + * destined for a target that isn't busy. + */ + prev = NULL; + for(req=issue_q; req != NULL; prev = req, req = req->next) { + if(!(busy & (1 << req->targ_id))) { + /* + * Found one, remove it from the issue queue + */ + if(prev == NULL) + issue_q = req->next; + else prev->next = req->next; + req->next = NULL; + break; + } + } + + /* + * When a request has just ended, we get here before an other + * device detects that the bus is free and that it can + * reconnect. The problem is that when this happens, we always + * baffle the device because our (initiator) id is higher. This + * can cause a sort of starvation on slow devices. So we check + * for a pending reselection here. + * Note that 'connected' will be non-null if the reselection + * succeeds. + */ + if((SCSI_5380->scsi_idstat&(SC_S_SEL|SC_S_IO)) + == (SC_S_SEL|SC_S_IO)){ + if(req != NULL) { + req->next = issue_q; + issue_q = req; + } + splx(sps); + + reselect(); + SC_CLINT; + goto connected; + } + + /* + * The host is not connected and there is no request + * pending, exit. + */ + if(req == NULL) { + PID("{"); + goto main_exit; + } + + /* + * Re-enable interrupts before handling the request. + */ + splx(sps); + +#ifdef DBG_REQ + show_request(req, "TARGET"); #endif + /* + * We found a request. Try to connect to the target. If the + * initiator fails arbitration, the command is put back in the + * issue queue. + */ + if(scsi_select(req, 0)) { + sps = splbio(); + req->next = issue_q; + issue_q = req; + splx(sps); +#ifdef DBG_REQ + printf("Select failed on target %d\n", req->targ_id); +#endif + } + } + else splx(sps); +connected: + if(connected) { + /* + * If the host is currently connected but a 'real-dma' transfer + * is in progress, the 'end-of-dma' interrupt restarts main. + * So quit. + */ + sps = splbio(); + if(connected && (connected->dr_flag & DRIVER_IN_DMA)) { + PID("["); + goto main_exit; + } + splx(sps); + + /* + * Let the target guide us through the bus-phases + */ + while(information_transfer() == -1) + ; + } + } + /* NEVER TO REACH HERE */ + panic("ncr0: not designed to come here"); + +main_exit: + /* + * We enter here with interrupts disabled. We are about to exit main + * so interrupts should be re-enabled. Because interrupts are edge + * triggered, we could already have missed the interrupt. Therefore + * we check the IRQ-line here and re-enter when we really missed a + * valid interrupt. + */ + PID("S"); + intr_enable(IR_SCSI1); + SCSI_5380->scsi_idstat = SC_HOST_ID; + if(SCSI_5380->scsi_dmstat & SC_IRQ_SET) { + if((itype = check_intr()) != INTR_SPURIOUS) { + intr_disable(IR_SCSI1); + splx(sps); + + if(itype == INTR_RESEL) + reselect(); + else dma_ready(0, 0); + SC_CLINT; + goto connected; + } + } + main_running = 0; + PID("R"); + splx(sps); +} + +/* + * The SCSI-controller interrupt. This interrupt occurs on reselections and + * at the end of non-polled DMA-interrupts. + */ +static void +ncr_intr(void *softint) +{ + int itype; + int dma_done; + int ctrlr; + + /* PID("$"); */ + ctrlr = scsi_select_ctlr(DP8490); + while(SCSI_5380->scsi_dmstat & SC_IRQ_SET) { + intr_disable(IR_SCSI1); + /* PID("&"); */ + if((itype = check_intr()) != INTR_SPURIOUS) { + /* PID("o"); */ + if(itype == INTR_RESEL) + reselect(); + else { +#ifdef REAL_DMA + if(!(dma_done = dma_ready(0, 0))) { + intr_enable(IR_SCSI1); + transfer_dma(connected, connected->phase, 0); + scsi_select_ctlr(ctrlr); + return; + } +#else + printf("would like to run transfer_dma\n"); +#endif + } + SC_CLINT; + } + /* PID("*"); */ + softintr((int)softint); + scsi_select_ctlr(ctrlr); + return; + } + PID("("); + scsi_select_ctlr(ctrlr); +} + +/* + * Initiate a connection path between the host and the target. The function + * first goes into arbitration for the SCSI-bus. When this succeeds, the target + * is selected and an 'IDENTIFY' message is send. + * Returns -1 when the arbitration failed. Otherwise 0 is returned. When + * the target does not respond (to either selection or 'MESSAGE OUT') the + * 'done' function is executed. + * The result code given by the driver can be influenced by setting 'code' + * to a non-zero value. This is the case when 'select' is called by abort. + */ +static int +scsi_select(reqp, code) +SC_REQ *reqp; +{ + u_long timeout; + u_char tmp[1]; + u_char phase; + u_long cnt; + int sps; + + DBG_SELPRINT ("Starting arbitration\n", 0); + PID("T"); + + sps = splbio(); + + /* + * Prevent a race condition here. If a reslection interrupt occurred + * between the decision to pick a new request and the call to select, + * we abort the selection. + * Interrupts are lowered when the 5380 is setup to arbitrate for the + * bus. + */ + if(connected || (SCSI_5380->scsi_idstat & SC_S_BSY)) { + splx(sps); + PID("Y"); + return(-1); + } + + /* + * Set phase bits to 0, otherwise the 5380 won't drive the bus during + * selection. + */ + SCSI_5380->scsi_tcom = 0; + SCSI_5380->scsi_icom = 0; + + /* + * Arbitrate for the bus. + */ + SCSI_5380->scsi_data = SC_HOST_ID; + SCSI_5380->scsi_mode = SC_ARBIT; + + splx(sps); + + cnt = 10000; + while(!(SCSI_5380->scsi_icom & SC_AIP) && --cnt) + delay(1); + + if(!(SCSI_5380->scsi_icom & SC_AIP)) { + SCSI_5380->scsi_mode = IMODE_BASE; + delay(1); + PID("U"); + + if(SCSI_5380->scsi_idstat & SC_S_BSY) { + /* + * Damn, we have a connected target that we don't know + * of. Some targets seem to respond to a selection + * AFTER the selection-timeout. Try to get the target + * into the Message-out phase so we can send an ABORT + * message. We try to avoid resetting the SCSI-bus! + */ + if(!reach_msg_out(sizeof(struct scsi_generic))) { + u_long len = 1; + u_char phase = PH_MSGOUT; + u_char msg = MSG_ABORT; + + transfer_pio(&phase, &msg, &len); + } + else if(SCSI_5380->scsi_idstat & SC_S_BSY) + scsi_reset(); + } + PID("I"); + return(-1); + } + + /* The arbitration delay is 2.2 usecs */ + delay(3); + + /* + * Check the result of the arbitration. If we failed, return -1. + */ + if(SCSI_5380->scsi_icom & SC_LA) { + /* + * The spec requires that we should read the data register to + * check for higher id's and check the SC_LA again. + */ + tmp[0] = SCSI_5380->scsi_data; + if(SCSI_5380->scsi_icom & SC_LA) { + SCSI_5380->scsi_mode = IMODE_BASE; + SCSI_5380->scsi_icom = 0; + DBG_SELPRINT ("Arbitration lost,deassert SC_ARBIT\n",0); + PID("O"); + return(-1); + } + } + SCSI_5380->scsi_icom = SC_A_SEL | SC_A_BSY; + if(SCSI_5380->scsi_icom & SC_LA) { + SCSI_5380->scsi_mode = IMODE_BASE; + SCSI_5380->scsi_icom = 0; + DBG_SELPRINT ("Arbitration lost, deassert SC_A_SEL\n", 0); + PID("P"); + return(-1); + } + /* Bus settle delay + Bus clear delay = 1.2 usecs */ + delay(2); + DBG_SELPRINT ("Arbitration complete\n", 0); + + /* + * Now that we won the arbitration, start the selection. + */ + SCSI_5380->scsi_data = SC_HOST_ID | (1 << reqp->targ_id); + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after the selection. + */ + SCSI_5380->scsi_icom = SC_A_BSY | SC_A_SEL | SC_A_ATN | SC_ADTB; + SCSI_5380->scsi_mode = IMODE_BASE; + + /* + * Turn off reselection interrupts + */ + SCSI_5380->scsi_idstat = 0; + + /* + * Reset BSY. The delay following it, surpresses a glitch in the + * 5380 which causes us to see our own BSY signal instead of that of + * the target. + */ + SCSI_5380->scsi_icom = SC_A_SEL | SC_A_ATN | SC_ADTB; + delay(1); + + /* + * Wait for the target to react, the specs call for a timeout of + * 250 ms. + */ + cnt = 250000 /* 250 */; + while(!(SCSI_5380->scsi_idstat & SC_S_BSY) && --cnt) + delay(1); + + if(!(SCSI_5380->scsi_idstat & SC_S_BSY)) { + /* + * There is no reaction from the target, start the selection + * timeout procedure. We release the databus but keep SEL + * asserted. After that we wait a 'selection abort time' (200 + * usecs) and 2 deskew delays (90 ns) and check BSY again. + * When BSY is asserted, we assume the selection succeeded, + * otherwise we release the bus. + */ + SCSI_5380->scsi_icom = SC_A_SEL | SC_A_ATN; + delay(201); + if(!(SCSI_5380->scsi_idstat & SC_S_BSY)) { + SCSI_5380->scsi_icom = 0; + reqp->xs->error = code ? code : XS_SELTIMEOUT; + DBG_SELPRINT ("Target %d not responding to sel\n", + reqp->targ_id); + finish_req(reqp); + PID("A"); + return(0); + } + } + SCSI_5380->scsi_icom = SC_A_ATN; + + DBG_SELPRINT ("Target %d responding to select.\n", reqp->targ_id); + + /* + * The SCSI-interrupts are disabled while a request is being handled. + */ + intr_disable(IR_SCSI1); + + /* + * Since we followed the SCSI-spec and raised ATN while SEL was true + * but before BSY was false during the selection, a 'MESSAGE OUT' + * phase should follow. Here we send an 'IDENTIFY' message. + * Allow disconnect only when interrups are allowed. + */ + tmp[0] = MSG_IDENTIFY(0, (reqp->dr_flag & DRIVER_NOINT) ? 0 : 1); + cnt = 1; + phase = PH_MSGOUT; + if(transfer_pio(&phase, tmp, &cnt) || cnt) { + DBG_SELPRINT ("Target %d: failed to send identify\n", + reqp->targ_id); + /* + * Try to disconnect from the target. We cannot leave it just + * hanging here. + */ + if(!reach_msg_out(sizeof(struct scsi_generic))) { + u_long len = 1; + u_char phase = PH_MSGOUT; + u_char msg = MSG_ABORT; + + transfer_pio(&phase, &msg, &len); + } + else scsi_reset(); + + SCSI_5380->scsi_icom = 0; + reqp->xs->error = code ? code : XS_DRIVER_STUFFUP; + finish_req(reqp); + PID("S"); + return(0); + } + reqp->phase = PH_MSGOUT; + +#ifdef notyet /* LWP: Do we need timeouts in the driver? */ + /* + * Command is connected, start timer ticking. + */ + ccb_p->xtimeout = ccb_p->timeout + Lbolt; +#endif + + connected = reqp; + busy |= 1 << reqp->targ_id; + PID("D"); + return(0); +} + +/* + * Return codes: + * -1: quit main, trigger on interrupt + * 0: keep on running main. + */ +static int +information_transfer() +{ + SC_REQ *reqp = connected; + u_char tmp, phase; + u_long len; + + PID("F"); + /* + * Clear pending interrupts from 5380-chip. + */ + SC_CLINT; + + /* + * We only have a valid SCSI-phase when REQ is asserted. Something + * is deadly wrong when BSY has dropped. + */ + tmp = SCSI_5380->scsi_idstat; + + if(!(tmp & SC_S_BSY)) { + busy &= ~(1 << reqp->targ_id); + connected = NULL; + reqp->xs->error = XS_BUSY; + finish_req(reqp); + PID("G"); + return(0); + } + + if(tmp & SC_S_REQ) { + phase = (tmp >> 2) & 7; + if(phase != reqp->phase) { + reqp->phase = phase; + DBG_INFPRINT(show_phase, reqp, phase); + } + } + else return(-1); + + switch(phase) { + case PH_DATAOUT: + +#ifdef DBG_NOWRITE + printf("NOWRITE set -- write attempt aborted."); + reqp->msgout = MSG_ABORT; + SCSI_5380->scsi_icom = SC_A_ATN; + return(-1); +#endif /* DBG_NOWRITE */ + + case PH_DATAIN: +#ifdef REAL_DMA + if(reqp->dr_flag & DRIVER_DMAOK) { + int poll = REAL_DMA_POLL|(reqp->dr_flag & DRIVER_NOINT); + transfer_dma(reqp, phase, poll); + if(!poll) + return(0); + } + else +#endif + { + int s; + PID("H"); + len = reqp->xdata_len; + transfer_pdma(&phase, reqp->xdata_ptr, &len); + reqp->xdata_ptr += reqp->xdata_len - len; + reqp->xdata_len = len; + PID("h"); + } + return(-1); + case PH_MSGIN: + /* + * We only expect single byte messages here. + */ + len = 1; + transfer_pio(&phase, &tmp, &len); + reqp->message = tmp; + return(handle_message(reqp, tmp)); + case PH_MSGOUT: + len = 1; + transfer_pio(&phase, &reqp->msgout, &len); + if(reqp->msgout == MSG_ABORT) { + busy &= ~(1 << reqp->targ_id); + connected = NULL; + reqp->xs->error = XS_DRIVER_STUFFUP; + finish_req(reqp); + PID("J"); + return(0); + } + reqp->msgout = MSG_NOOP; + return(-1); + case PH_CMD : + len = command_size(reqp->xcmd.opcode); + transfer_pio(&phase, (u_char *)&reqp->xcmd, &len); + PID("K"); + return(-1); + case PH_STATUS: + len = 1; + transfer_pio(&phase, &tmp, &len); + reqp->status = tmp; + PID("L"); + return(-1); + default : + printf("ncr0: unknown phase on target %d\n", reqp->targ_id); + } + PID(":"); + return(-1); +} + +/* + * Handle the message 'msg' send to us by the target. + * Return values: + * 0 : The current command has completed. + * -1 : Get on to the next phase. + */ +static int +handle_message(reqp, msg) +SC_REQ *reqp; +u_int msg; +{ + int sps; + + PID(";"); + switch(msg) { + /* + * Linking lets us reduce the time required to get + * the next command to the device, skipping the arbitration + * and selection time. In the current implementation, + * we merely have to start the next command pointed + * to by 'next_link'. + */ + case MSG_LINK_CMD_COMPLETE: + case MSG_LINK_CMD_COMPLETEF: + if(reqp->link == NULL) { + printf("ncr0: no link for linked command" + "on target %d\n", reqp->targ_id); + reqp->msgout = MSG_ABORT; + SCSI_5380->scsi_icom = SC_A_ATN; + PID("@"); + return(-1); + } + reqp->xs->error = 0; + +#ifdef AUTO_SENSE + if(check_autosense(reqp, 0) == -1) + return(-1); +#endif /* AUTO_SENSE */ + +#ifdef DBG_REQ + show_request(reqp->link, "LINK"); +#endif + connected = reqp->link; + finish_req(reqp); + PID("'"); + return(-1); + case MSG_ABORT: + case MSG_CMDCOMPLETE: +#ifdef DBG_REQ + show_request(reqp, "DONE"); +#endif + connected = NULL; + busy &= ~(1 << reqp->targ_id); + if(!(reqp->dr_flag & DRIVER_AUTOSEN)) + reqp->xs->resid = reqp->xdata_len; + reqp->xs->error = 0; + +#ifdef AUTO_SENSE + if(check_autosense(reqp, 0) == -1) { + PID("Z"); + return(0); + } +#endif /* AUTO_SENSE */ + + finish_req(reqp); + PID("X"); + return(0); + case MSG_MESSAGE_REJECT: + PID("C"); + return(-1); + case MSG_DISCONNECT: +#ifdef DBG_REQ + show_request(reqp, "DISCON"); +#endif + PID("v"); + sps = splbio(); + connected = NULL; + reqp->next = discon_q; + discon_q = reqp; + splx(sps); + PID("V"); + return(0); + case MSG_SAVEDATAPOINTER: + case MSG_RESTOREPOINTERS: + /* + * We save pointers implicitely at disconnect. + * So we can ignore these messages. + */ + PID("B"); + return(-1); + default: + printf("ncr0: unkown message %x on target %d\n", msg, + reqp->targ_id); + return(-1); + } + PID("N"); + return(-1); +} + +/* + * Handle reselection. If a valid reconnection occurs, connected + * points at the reconnected command. The command is removed from the + * disconnected queue. + */ +static void +reselect() +{ + u_char phase; + u_long len; + u_char msg; + u_char target_mask; + int abort = 0, s; + SC_REQ *tmp, *prev; + s = splbio(); - sense = scsi_gen( xs->sc_link->scsibus, xs->sc_link->target, - xs->sc_link->lun, xs->cmd, xs->cmdlen, - xs->data, xs->datalen ); - splx(s); - switch (sense) { - case 0x00: - xs->error = XS_NOERROR; - return (COMPLETE); - case 0x02: /* Check condition */ - for (i = 10; i; i--) { - s = splbio(); - sense = scsi_group0(xs->sc_link->scsibus, - xs->sc_link->target, - xs->sc_link->lun, - 0x3, 0x0, - sizeof(struct scsi_sense_data), - 0, (caddr_t) &(xs->sense), - sizeof(struct scsi_sense_data)); - splx(s); - if (sense == 0) break; - if (sense == 8 - && (xs->flags & SCSI_NOSLEEP) == 0) - tsleep((caddr_t)&lbolt, PRIBIO, "ncrbusy", 0); - } - if (!i) - printf("ncr(%d:%d): Sense failed (dev busy)\n", - xs->sc_link->target, xs->sc_link->lun); - xs->error = XS_SENSE; - return COMPLETE; - case 0x08: /* Busy */ - xs->error = XS_BUSY; - return COMPLETE; - default: - xs->error = XS_DRIVER_STUFFUP; - return COMPLETE; - } -} - -static int -select_target(register volatile sci_padded_regmap_t *regs, - u_char myid, u_char tid, int with_atn) -{ - register u_char bid, icmd; - int ret = SCSI_RET_RETRY; - - if ((regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) && - (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) && - (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL))) - return ret; - - /* for our purposes.. */ - myid = 1 << myid; - tid = 1 << tid; - - regs->sci_sel_enb = 0; /*myid; we don't want any interrupts. */ - regs->sci_tcmd = 0; /* get into a harmless state */ - regs->sci_mode = 0; /* get into a harmless state */ - - regs->sci_odata = myid; - regs->sci_mode = SCI_MODE_ARB; -/* regs->sci_mode |= SCI_MODE_ARB; */ - /* AIP might not set if BSY went true after we checked */ - for (bid = 0; bid < 20; bid++) /* 20usec circa */ - if (regs->sci_icmd & SCI_ICMD_AIP) - break; - if ((regs->sci_icmd & SCI_ICMD_AIP) == 0) { - goto lost; - } - - spinwait(2); /* 2.2us arb delay */ - - if (regs->sci_icmd & SCI_ICMD_LST) { - goto lost; - } - - regs->sci_mode &= ~SCI_MODE_PAR_CHK; - bid = regs->sci_data; - - if ((bid & ~myid) > myid) { - goto lost; - } - if (regs->sci_icmd & SCI_ICMD_LST) { - goto lost; - } - - /* Won arbitration, enter selection phase now */ - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); - icmd |= (with_atn ? (SCI_ICMD_SEL|SCI_ICMD_ATN) : SCI_ICMD_SEL); - icmd |= SCI_ICMD_BSY; - regs->sci_icmd = icmd; - - if (regs->sci_icmd & SCI_ICMD_LST) { - goto nosel; - } - - /* XXX a target that violates specs might still drive the bus XXX */ - /* XXX should put our id out, and after the delay check nothi XXX */ - /* XXX ng else is out there. XXX */ - - delay(0); - - regs->sci_tcmd = 0; - regs->sci_odata = myid | tid; - regs->sci_sel_enb = 0; - -/* regs->sci_mode &= ~SCI_MODE_ARB; 2 deskew delays, too */ - regs->sci_mode = 0; /* 2 deskew delays, too */ + PID("M"); + target_mask = SCSI_5380->scsi_data & ~SC_HOST_ID; + /* + * At this point, we have detected that our SCSI-id is on the bus, + * SEL is true and BSY was false for at least one bus settle + * delay (400 ns.). + * We must assert BSY ourselves, until the target drops the SEL signal. + */ + SCSI_5380->scsi_icom = SC_A_BSY; + while(SCSI_5380->scsi_idstat & SC_S_SEL) + ; - icmd |= SCI_ICMD_DATA; - icmd &= ~(SCI_ICMD_BSY); + SCSI_5380->scsi_icom = 0; + + /* + * Get the expected identify message. + */ + phase = PH_MSGIN; + len = 1; + transfer_pio(&phase, &msg, &len); + if(len || !MSG_ISIDENTIFY(msg)) { + printf("ncr0: expecting IDENTIFY, got 0x%x\n", msg); + abort = 1; + } + else { + /* + * Find the command reconnecting + */ + for(tmp = discon_q, prev = NULL; tmp; prev = tmp, tmp = tmp->next){ + if(target_mask == (1 << tmp->targ_id)) { + if(prev) + prev->next = tmp->next; + else discon_q = tmp->next; + tmp->next = NULL; + break; + } + } + if(tmp == NULL) { + printf("ncr0: no disconnected job for targetmask %x\n", + target_mask); + abort = 1; + } + } + if(abort) { + msg = MSG_ABORT; + len = 1; + phase = PH_MSGOUT; - regs->sci_icmd = icmd; + SCSI_5380->scsi_icom = SC_A_ATN; + transfer_pio(&phase, &msg, &len); + } + else { + connected = tmp; +#ifdef DBG_REQ + show_request(tmp, "RECON"); +#endif + } + PID("<"); + splx(s); +} - /* bus settle delay, 400ns */ - delay(2); /* too much (was 2) ? */ +/* + * Transfer data in a given phase using polled I/O. + * Returns -1 when a different phase is entered without transferring the + * maximum number of bytes, 0 if all bytes or exit is in the same + * phase. + */ +static int +transfer_pio(phase, data, len) +u_char *phase; +u_char *data; +u_long *len; +{ + u_int cnt = *len; + u_char ph = *phase; + u_char tmp; -/* regs->sci_mode |= SCI_MODE_PAR_CHK; */ + DBG_PIOPRINT ("ncr0: transfer_pio start: phase: %d, len: %d\n", ph,cnt); + PID(","); + SCSI_5380->scsi_tcom = ph; + do { + if(!wait_req_true()) { + DBG_PIOPRINT ("ncr0: transfer_pio: missing REQ\n", 0, 0); + break; + } + if(((SCSI_5380->scsi_idstat >> 2) & 7) != ph) { + DBG_PIOPRINT ("ncr0: transfer_pio: phase mismatch\n", 0, 0); + break; + } + if(PH_IN(ph)) { + *data++ = SCSI_5380->scsi_data; + SCSI_5380->scsi_icom = SC_A_ACK; + } + else { + SCSI_5380->scsi_data = *data++; - { - register int timeo = 2500;/* 250 msecs in 100 usecs chunks */ - while ((regs->sci_bus_csr & SCI_BUS_BSY) == 0) { - if (--timeo > 0) { - delay(100); - } else { - goto nodev; + /* + * The SCSI-standard suggests that in the 'MESSAGE OUT' phase, + * the initiator should drop ATN on the last byte of the + * message phase after REQ has been asserted for the handshake + * but before the initiator raises ACK. + */ + if(!( (ph == PH_MSGOUT) && (cnt > 1) )) { + SCSI_5380->scsi_icom = SC_ADTB; + SCSI_5380->scsi_icom = SC_ADTB | SC_A_ACK; + } + else { + SCSI_5380->scsi_icom = SC_ADTB | SC_A_ATN; + SCSI_5380->scsi_icom = SC_ADTB | SC_A_ATN | SC_A_ACK; + } + } + if(!wait_req_false()) { + DBG_PIOPRINT ("ncr0: transfer_pio - REQ not dropping\n", 0, 0); + break; + } + + if(!( (ph == PH_MSGOUT) && (cnt > 1) )) + SCSI_5380->scsi_icom = 0; + else SCSI_5380->scsi_icom = SC_A_ATN; + } while(--cnt); + + if((tmp = SCSI_5380->scsi_idstat) & SC_S_REQ) + *phase = (tmp >> 2) & 7; + else *phase = NR_PHASE; + *len = cnt; + DBG_PIOPRINT ("ncr0: transfer_pio done: phase: %d, len: %d\n", + *phase, cnt); + PID(">"); + if(!cnt || (*phase == ph)) + return(0); + return(-1); +} + +#ifdef REAL_DMA +/* + * Start a DMA-transfer on the device using the current pointers. + * If 'poll' is true, the function waits until DMA-has completed. + */ +static void +transfer_dma(reqp, phase, poll) +SC_REQ *reqp; +u_int phase; +int poll; +{ + int dmastat; + u_char mbase = 0; + int sps; + +again: + PID("?"); + /* + * We should be in phase, otherwise we are not allowed to + * drive the bus. + */ + SCSI_5380->scsi_tcom = phase; + + /* + * Defer interrupts until DMA is fully running. + */ + sps = splbio(); + + /* + * Clear pending interrupts and parity errors. + */ + SCSI_DMA->s_dma_ctrl = 0; + SC_CLINT; + + if(!poll) { + /* + * Enable SCSI interrupts and set IN_DMA flag, set 'mbase' + * to the interrupts we want enabled. + */ + intr_enable(IR_SCSI1); + reqp->dr_flag |= DRIVER_IN_DMA; + mbase = SC_E_EOPI | SC_MON_BSY; + } + + if(PH_IN(phase)) { + SCSI_DMA->s_dma_ctrl = SD_IN; + set_scsi_dma(&(SCSI_DMA->s_dma_ptr), reqp->dm_cur->dm_addr); + set_scsi_dma(&(SCSI_DMA->s_dma_cnt), reqp->dm_cur->dm_count); + SCSI_5380->scsi_icom = 0; + SCSI_5380->scsi_mode = IMODE_BASE | mbase | SC_M_DMA; + SCSI_DMA->s_dma_ctrl = SD_ENABLE; + SCSI_5380->scsi_ircv = 0; + } + else { + SCSI_DMA->s_dma_ctrl = SD_OUT; + set_scsi_dma(&(SCSI_DMA->s_dma_ptr), reqp->dm_cur->dm_addr); + set_scsi_dma(&(SCSI_DMA->s_dma_cnt), reqp->dm_cur->dm_count); + SCSI_5380->scsi_mode = IMODE_BASE | mbase | SC_M_DMA; + SCSI_5380->scsi_icom = SC_ADTB; + SCSI_5380->scsi_dmstat = 0; + SCSI_DMA->s_dma_ctrl = SD_ENABLE|SD_OUT; + } + splx(sps); + + if(poll) { + /* + * We wait here until the DMA has finished. This can be + * achieved by checking the following conditions: + * - 5380: + * - End of DMA flag is set + * - We lost BSY (error!!) + * - A phase mismatch has occured (partial transfer) + * - DMA-controller: + * - A bus error occurred (Kernel error!!) + * - All bytes are transferred + * We one of the terminating conditions was met, we call + * 'dma_ready' to check errors and perform the bookkeeping. + */ + u_char dmstat, dmastat; + int dma_done; + + PID("/"); + for(;;) { + dmstat = SCSI_5380->scsi_dmstat; + dmastat = SCSI_DMA->s_dma_ctrl; + if(dmstat & (SC_END_DMA|SC_BSY_ERR|SC_IRQ_SET)) + break; + if(!(dmstat & SC_PHS_MTCH)) + break; + if(dmastat & (SD_BUSERR|SD_ZERO)) + break; + } + PID("q"); + if(dmastat & (SD_BUSERR|SD_ZERO)) + dma_done = dma_ready(1, dmastat); + else dma_done = dma_ready(0, 0); + if(!dma_done) + goto again; + + } + PID("w"); +} +#endif + +/* + * Check results of a DMA data-transfer. + */ +static int +dma_ready(has_dmastat, dmastat) +int has_dmastat, dmastat; +{ + int dmstat, phase; + long tmp, bytes_left, bytes_done; + int i; + SC_REQ *reqp = connected; + + /* + * Get values of the status registers of the 5380 & DMA-controller. + */ + dmstat = SCSI_5380->scsi_dmstat; +#ifdef REAL_DMA + if(!has_dmastat) + dmastat = SCSI_DMA->s_dma_ctrl; +#endif + + /* + * Check if the call is sensible and not caused by any spurious + * interrupt. + */ + if( +#ifdef REAL_DMA + !(dmastat & (SD_BUSERR|SD_ZERO)) && +#endif + !(dmstat & (SC_END_DMA|SC_BSY_ERR)) + && (dmstat & SC_PHS_MTCH) ) { + printf("ncr0: spurious call to dma_ready (dma:%x,dm:%x)\n", + dmastat, dmstat); + return(0); + } + +#ifdef REAL_DMA + /* + * If end of a DMA transfer, check it's results. + */ + get_scsi_dma(SCSI_DMA->s_dma_cnt, bytes_left); + + if(dmastat & SD_BUSERR) { + /* + * The DMA-controller seems to access 8 bytes beyond + * it's limits on output. Therefore check also the byte + * count. If it's zero, ignore the bus error. + */ + if(bytes_left != 0) { + get_scsi_dma(SCSI_DMA->s_dma_ptr, tmp); + printf("SCSI-DMA buserror - accessing 0x%x\n", tmp); + panic("SCSI"); + } + } + + if(bytes_left != 0) { + /* + * The byte-count is not zero. This is not always an error,on + * tape drives this usually means EOF. We check that the + * residu is a multiple of 512-bytes, when we know the device + * type it should be included in the check. + * A severe complication is that if a device wants to + * disconnect in the middle of a DMA-transfer, the 5380 has + * already prefetched the next byte from the DMA-controller + * before the phase mismatch occurs. I don't know how this + * fact can be uniquely identified. For the moment, we round + * up the residual if it is odd. + */ + if(PH_OUT(reqp->phase) && (bytes_left & 1)) + bytes_left++; + + } + else { + if(PH_IN(reqp->phase)) { + /* + * Check for bytes not transfered. This should never occur + * because the buffer-pool is aligned on a 4-byte boundary. + */ + u_char *p, *q; + + if(bytes_left > 3) { + scsi_show(); + printf("ncr0: %d bytes not transferred\n", bytes_left); + panic("ncr0"); + } + p = (u_char*)(bytes_left & ~3); + q = (u_char*)&(SCSI_DMA->s_dma_res); + switch(bytes_left & 3) { + case 3: *p++ = *q++; + case 2: *p++ = *q++; + case 1: *p++ = *q++; + printf("ncr0: dma residue count != 0, "); + printf("Check buffer alignment\n"); + } + } + } + + /* + * Update various transfer-pointers/lengths + */ + bytes_done = reqp->dm_cur->dm_count - bytes_left; + + reqp->xdata_ptr = &reqp->xdata_ptr[bytes_done]; /* XXX */ + reqp->xdata_len -= bytes_done; /* XXX */ + if((reqp->dm_cur->dm_count -= bytes_done) == 0) + reqp->dm_cur++; + else reqp->dm_cur->dm_addr += bytes_done; +#endif + + if(PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) { + if(!(ncr5380_no_parchk & (1 << reqp->targ_id))) + /* XXX: Should be parity error ???? */ + reqp->xs->error = XS_DRIVER_STUFFUP; + } + + /* + * DMA mode should always be reset even when we will continue with the + * next chain. + */ + SCSI_5380->scsi_mode &= ~SC_M_DMA; + + if((dmstat & SC_BSY_ERR) || !(dmstat & SC_PHS_MTCH) +#ifdef REAL_DMA + || (reqp->dm_cur > reqp->dm_last) +#endif + ) { + /* + * Tell interrupt functions DMA mode has ended. + */ + reqp->dr_flag &= ~DRIVER_IN_DMA; + + /* + * Turn off DMA-mode and clear icom + */ + SCSI_5380->scsi_mode &= + ~(SC_M_DMA|SC_E_EOPI|SC_MON_BSY|SC_E_PARI); + SCSI_5380->scsi_icom = 0; + + /* + * Clear all (pending) interrupts. + */ +#ifdef REAL_DMA + SCSI_DMA->s_dma_ctrl = 0; +#endif + SC_CLINT; + + if(dmstat & SC_BSY_ERR) { + if(!reqp->xs->error) + reqp->xs->error = XS_BUSY; + finish_req(reqp); + PID("r"); + return(1); + } + + if(reqp->xs->error != 0) { +printf("dma-ready: code = %d\n", reqp->xs->error); /* LWP */ + reqp->msgout = MSG_ABORT; + SCSI_5380->scsi_icom = SC_A_ATN; + } + PID("t"); + return(1); + } + return(0); +} + +static int +check_autosense(reqp, linked) +SC_REQ *reqp; +int linked; +{ + int sps; + + /* + * If we not executing an auto-sense and the status code + * is request-sense, we automatically issue a request + * sense command. + */ + PID("y"); + if(!(reqp->dr_flag & DRIVER_AUTOSEN)) { + if(reqp->status == SCSCHKC) { + memcpy(&reqp->xcmd, sense_cmd, sizeof(sense_cmd)); + reqp->xdata_ptr = (u_char *)&reqp->xs->sense; + reqp->xdata_len = sizeof(reqp->xs->sense); + reqp->dr_flag |= DRIVER_AUTOSEN; + reqp->dr_flag &= ~DRIVER_DMAOK; + if(!linked) { + sps = splbio(); + reqp->next = issue_q; + issue_q = reqp; + splx(sps); } - } - } + else reqp->xcmd.bytes[4] |= 1; - icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL); - regs->sci_icmd = icmd; -/* regs->sci_sel_enb = myid;*/ /* looks like we should NOT have it */ - return SCSI_RET_SUCCESS; -nodev: - ret = SCSI_RET_DEVICE_DOWN; - regs->sci_sel_enb = myid; -nosel: - icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL|SCI_ICMD_ATN); - regs->sci_icmd = icmd; -lost: - regs->sci_mode = 0; - - return ret; -} - -sci_data_out(regs, phase, count, data) - register sci_padded_regmap_t *regs; - unsigned char *data; -{ - register unsigned char icmd; - register int cnt=0; - - /* ..checks.. */ - - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); -loop: - if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) - return cnt; - - WAIT_FOR_REQ(regs); - icmd |= SCI_ICMD_DATA; - regs->sci_icmd = icmd; - regs->sci_odata = *data++; - icmd |= SCI_ICMD_ACK; - regs->sci_icmd = icmd; - - icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_ACK); - WAIT_FOR_NOT_REQ(regs); - regs->sci_icmd = icmd; - ++cnt; - if (--count > 0) - goto loop; -scsi_timeout_error: - return cnt; -} - -sci_data_in(regs, phase, count, data) - register sci_padded_regmap_t *regs; - unsigned char *data; -{ - register unsigned char icmd; - register int cnt=0; - - /* ..checks.. */ - - icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); - -loop: - if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) - return cnt; - - WAIT_FOR_REQ(regs); - *data++ = regs->sci_data; - icmd |= SCI_ICMD_ACK; - regs->sci_icmd = icmd; - - icmd &= ~SCI_ICMD_ACK; - WAIT_FOR_NOT_REQ(regs); - regs->sci_icmd = icmd; - ++cnt; - if (--count > 0) - goto loop; - -scsi_timeout_error: - return cnt; -} - -static int -command_transfer(register volatile sci_padded_regmap_t *regs, - int maxlen, u_char *data, u_char *status, u_char *msg) -{ - int xfer=0, phase; - -/* printf("command_transfer called for 0x%x.\n", *data); */ - - regs->sci_icmd = 0; - - while (1) { - - WAIT_FOR_REQ(regs); - - phase = SCI_CUR_PHASE(regs->sci_bus_csr); - - switch (phase) { - case SCSI_PHASE_CMD: - SCI_ACK(regs,SCSI_PHASE_CMD); - xfer += sci_data_out(regs, SCSI_PHASE_CMD, - maxlen, data); - return xfer; - case SCSI_PHASE_DATA_IN: - printf("Data in phase in command_transfer?\n"); - return 0; - case SCSI_PHASE_DATA_OUT: - printf("Data out phase in command_transfer?\n"); - return 0; - case SCSI_PHASE_STATUS: - SCI_ACK(regs,SCSI_PHASE_STATUS); - printf("status in command_transfer.\n"); - sci_data_in(regs, SCSI_PHASE_STATUS, - 1, status); - break; - case SCSI_PHASE_MESSAGE_IN: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); - printf("msgin in command_transfer.\n"); - sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, - 1, msg); - break; - case SCSI_PHASE_MESSAGE_OUT: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); - sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, - 1, msg); - break; - default: - printf("Unexpected phase 0x%x in " - "command_transfer().\n", phase); -scsi_timeout_error: - return xfer; - break; - } - } -} - -static int -data_transfer(register volatile sci_padded_regmap_t *regs, - int maxlen, u_char *data, u_char *status, u_char *msg) -{ - int retlen = 0, xfer, phase; - - regs->sci_icmd = 0; - - *status = 0; - - while (1) { - - WAIT_FOR_REQ(regs); - - phase = SCI_CUR_PHASE(regs->sci_bus_csr); - - switch (phase) { - case SCSI_PHASE_CMD: - printf("Command phase in data_transfer().\n"); - return retlen; - case SCSI_PHASE_DATA_IN: - SCI_ACK(regs,SCSI_PHASE_DATA_IN); -#if PSEUDO_DMA - xfer = sci_pdma_in(regs, SCSI_PHASE_DATA_IN, - maxlen, data); -#else - xfer = sci_data_in(regs, SCSI_PHASE_DATA_IN, - maxlen, data); +#ifdef DBG_REQ + show_request(reqp, "AUTO-SENSE"); #endif - retlen += xfer; - maxlen -= xfer; - break; - case SCSI_PHASE_DATA_OUT: - SCI_ACK(regs,SCSI_PHASE_DATA_OUT); -#if PSEUDO_DMA - xfer = sci_pdma_out(regs, SCSI_PHASE_DATA_OUT, - maxlen, data); -#else - xfer = sci_data_out(regs, SCSI_PHASE_DATA_OUT, - maxlen, data); + PID("u"); + return(-1); + } + } + else { + /* + * An auto-sense has finished + */ + if((reqp->status & SCSMASK) != SCSGOOD) + reqp->xs->error = XS_DRIVER_STUFFUP; /* SC_E_AUTOSEN; */ + else reqp->xs->error = XS_SENSE; + reqp->status = SCSCHKC; + } + PID("i"); + return(0); +} + +static int +reach_msg_out(len) +u_long len; +{ + u_char phase; + u_char data; + + printf("ncr0: Trying to reach Message-out phase\n"); + if((phase = SCSI_5380->scsi_idstat) & SC_S_REQ) + phase = (phase >> 2) & 7; + else return(-1); + printf("ncr0: Trying to reach Message-out phase, now: %d\n", phase); + if(phase == PH_MSGOUT) + return(0); + + SCSI_5380->scsi_tcom = phase; + + do { + if(!wait_req_true()) { + break; + } + if(((SCSI_5380->scsi_idstat >> 2) & 7) != phase) { + break; + } + if(PH_IN(phase)) { + data = SCSI_5380->scsi_data; + SCSI_5380->scsi_icom = SC_A_ACK | SC_A_ATN; + } + else { + SCSI_5380->scsi_data = 0; + SCSI_5380->scsi_icom = SC_ADTB | SC_A_ATN | SC_A_ACK; + } + if(!wait_req_false()) { + break; + } + SCSI_5380->scsi_icom = SC_A_ATN; + } while(--len); + + if((phase = SCSI_5380->scsi_idstat) & SC_S_REQ) { + phase = (phase >> 2) & 7; + if(phase == PH_MSGOUT) { + printf("ncr0: Message-out phase reached.\n"); + return(0); + } + } + return(-1); +} + +static void +scsi_reset() +{ + SC_REQ *tmp, *next; + int sps; + + printf("ncr0: resetting SCSI-bus\n"); + + PID("7"); + sps = splbio(); + SCSI_5380->scsi_icom = SC_A_RST; + delay(1); + SCSI_5380->scsi_icom = 0; + + /* + * None of the jobs in the discon_q will ever be reconnected, + * notify this to the higher level code. + */ + for(tmp = discon_q; tmp ;) { + next = tmp->next; + tmp->next = NULL; + tmp->xs->error = XS_TIMEOUT; + busy &= ~(1 << tmp->targ_id); + finish_req(tmp); + tmp = next; + } + discon_q = NULL; + + /* + * The current job will never finish either. + * The problem is that we can't finish the job because an instance + * of main is running on it. Our best guess is that the job is currently + * doing REAL-DMA. In that case 'dma_ready()' should correctly finish + * the job because it detects BSY-loss. + */ + if(tmp = connected) { + if(tmp->dr_flag & DRIVER_IN_DMA) { + tmp->xs->error = XS_DRIVER_STUFFUP; + dma_ready(0, 0); + } + } + splx(sps); + PID("8"); +} + +/* + * Check validity of the IRQ set by the 5380. If the interrupt is valid, + * the appropriate action is carried out (reselection or DMA ready) and + * INTR_RESEL or INTR_DMA is returned. Otherwise a console notice is written + * and INTR_SPURIOUS is returned. + */ +static int +check_intr() +{ + SC_REQ *reqp; + + if((SCSI_5380->scsi_idstat & (SC_S_SEL|SC_S_IO))==(SC_S_SEL|SC_S_IO)) + return(INTR_RESEL); + else { + if((reqp = connected) && (reqp->dr_flag & DRIVER_IN_DMA)){ + reqp->dr_flag &= ~DRIVER_IN_DMA; + return(INTR_DMA); + } + } + SC_CLINT; + printf("-->"); + scsi_show(); + printf("ncr0: spurious interrupt.\n"); + return(INTR_SPURIOUS); +} + +#ifdef REAL_DMA +/* + * Check if DMA can be used for this request. This function also builds + * the dma-chain. + */ +static int +scsi_dmaok(reqp) +SC_REQ *reqp; +{ + u_long phy_buf; + u_long phy_len; + void *req_addr; + u_long req_len; + struct dma_chain *dm; + + /* + * Initialize locals and requests' DMA-chain. + */ + req_len = reqp->xdata_len; + req_addr = (void*)reqp->xdata_ptr; + dm = reqp->dm_cur = reqp->dm_last = reqp->dm_chain; + + dm->dm_count = dm->dm_addr = 0; + + /* + * Do not accept zero length DMA. + */ + if(req_len == 0) + return(0); + + /* + * LWP: I think that this restriction is not strictly nessecary. + */ + if((req_len & 0x1) || ((u_int)req_addr & 0x3)) + return(0); + + /* + * Build the DMA-chain. + */ + dm->dm_addr = phy_buf = kvtop(req_addr); + while(req_len) { + if(req_len < (phy_len = NBPG - ((u_long)req_addr & PGOFSET))) + phy_len = req_len; + + req_addr += phy_len; + req_len -= phy_len; + dm->dm_count += phy_len; + + if(req_len) { + u_long tmp = kvtop(req_addr); + + if((phy_buf + phy_len) != tmp) { + if(++dm >= &reqp->dm_chain[MAXDMAIO]) { + printf("ncr5380_dmaok: DMA chain too long!\n"); + return(0); + } + dm->dm_count = 0; + dm->dm_addr = tmp; + } + phy_buf = tmp; + } + } + reqp->dm_last = dm; + return(1); +} #endif - retlen += xfer; - maxlen -= xfer; - break; - case SCSI_PHASE_STATUS: - SCI_ACK(regs,SCSI_PHASE_STATUS); - sci_data_in(regs, SCSI_PHASE_STATUS, - 1, status); - break; - case SCSI_PHASE_MESSAGE_IN: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); - sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, - 1, msg); - if (*msg == 0) { - return retlen; - } else { - printf( "message 0x%x in " - "data_transfer.\n", *msg); - } - break; - case SCSI_PHASE_MESSAGE_OUT: - SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); - sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, - 1, msg); - break; - default: - printf( "Unexpected phase 0x%x in " - "data_transfer().\n", phase); -scsi_timeout_error: - return retlen; - break; - } - } -} -static int -scsi_request(register volatile sci_padded_regmap_t *regs, - int target, int lun, u_char *cmd, int cmdlen, - char *databuf, int datalen, int *sent, int *ret) +static void +run_main(void) { -/* Returns 0 on success, -1 on internal error, or the status byte */ - int cmd_bytes_sent, r; - u_char stat, msg, c; + int sps = splbio(); - *sent = 0; - scsi_select_ctlr (NCR5380); - - if ( ( r = select_target(regs, 7, target, 1) ) != SCSI_RET_SUCCESS) { - *ret = r; - SCI_CLR_INTR(regs); - switch (r) { - case SCSI_RET_RETRY: - return 0x08; - default: - printf("select_target(target %d, lun %d) failed(%d).\n", - target, lun, r); - case SCSI_RET_DEVICE_DOWN: - return -1; - } - } - - c = 0x80 | lun; - - if ((cmd_bytes_sent = command_transfer(regs, cmdlen, - (u_char *) cmd, &stat, &c)) - != cmdlen) { - SCI_CLR_INTR(regs); - *ret = SCSI_RET_COMMAND_FAIL; - printf("Data underrun sending CCB (%d bytes of %d, sent).\n", - cmd_bytes_sent, cmdlen); - return -1; - } - - *sent=data_transfer(regs, datalen, (u_char *)databuf, - &stat, &msg); - - *ret = 0; - - return stat; + if(!main_running) { + main_running = 1; + splx(sps); + scsi_main(); + } else + splx(sps); } -static int -scsi_gen(int adapter, int id, int lun, struct scsi_generic *cmd, - int cmdlen, void *databuf, int datalen) +/**************************************************************************** + * Start Debugging Functions * + ****************************************************************************/ +static void +show_data_sense(xs) +struct scsi_xfer *xs; { - register volatile sci_padded_regmap_t *regs = ncr; - int i,j,sent,ret; + u_char *b; + int i; + int sz; - cmd->bytes[0] |= ((u_char) lun << 5); - - i = scsi_request(regs, id, lun, (u_char *) cmd, cmdlen, - databuf, datalen, &sent, &ret); - - return i; + b = (u_char *) xs->cmd; + printf("cmd[%d,%d]: ", xs->cmdlen, sz = command_size(*b)); + for(i = 0; i < sz; i++) + printf("%x ", b[i]); + printf("\nsense: "); + b = (u_char *)&xs->sense; + for(i = 0; i < sizeof(xs->sense); i++) + printf("%x ", b[i]); + printf("\n"); } -static int -scsi_group0(int adapter, int id, int lun, int opcode, int addr, int len, - int flags, caddr_t databuf, int datalen) +static void +show_request(reqp, qtxt) +SC_REQ *reqp; +char *qtxt; { - register volatile sci_padded_regmap_t *regs = ncr; - unsigned char cmd[6]; - int i,j,sent,ret; - - cmd[0] = opcode; /* Operation code */ - cmd[1] = (lun << 5) | ((addr >> 16) & 0x1F); /* Lun & MSB of addr */ - cmd[2] = (addr >> 8) & 0xFF; /* addr */ - cmd[3] = addr & 0xFF; /* LSB of addr */ - cmd[4] = len; /* Allocation length */ - cmd[5] = flags; /* Link/Flag */ - - i = scsi_request(regs, id, lun, cmd, 6, databuf, datalen, &sent, &ret); - - return i; + printf("REQ-%s: %d %x[%d] cmd[0]=%x S=%x M=%x R=%x %s\n", qtxt, + reqp->targ_id, reqp->xdata_ptr, reqp->xdata_len, + reqp->xcmd.opcode, reqp->status, reqp->message, + reqp->xs->error, reqp->link ? "L" : ""); + if(reqp->status == SCSCHKC) + show_data_sense(reqp->xs); } -/* pseudo-dma action */ +scsi_show() +{ + SC_REQ *tmp; + int sps = splhigh(); -#if PSEUDO_DMA +#ifndef DBG_PID + #define last_hit "" +#endif + + for(tmp = issue_q; tmp; tmp = tmp->next) + show_request(tmp, "ISSUED"); + for(tmp = discon_q; tmp; tmp = tmp->next) + show_request(tmp, "DISCONNECTED"); + if(connected) + show_request(connected, "CONNECTED"); + /* show_signals(); */ + if(connected) + printf("phase = %d, ", connected->phase); + printf("busy:%x, last_hit:%s, spl:%x dis:%x\n", busy, last_hit, sps, idisabled); + + splx(sps); +} #define TIMEOUT 1000000 -#define READY(poll) \ +#define READY(dataout) \ i = TIMEOUT; \ - while ((regs->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) \ - !=(SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) \ - if ( !(regs->sci_csr & SCI_CSR_PHASE_MATCH) \ - || !(regs->sci_bus_csr & SCI_BUS_BSY) \ + while (((dmstat = SCSI_5380->scsi_dmstat) & (SC_DMA_REQ|SC_PHS_MTCH)) \ + != (SC_DMA_REQ|SC_PHS_MTCH)) \ + if ( !(dmstat & SC_PHS_MTCH) \ + || !(SCSI_5380->scsi_idstat & SC_S_BSY) \ || (i-- < 0) ) { \ - printf("ncr.c: timeout counter = %d, len = %d count=%d (count-len %d).\n", \ - i, len,count,count-len); \ - printf("ncr_debug = %d, 1=out, 2=in",ncr_debug); \ - /*dump_regs();*/ \ - if (poll && !(regs->sci_csr & SCI_CSR_PHASE_MATCH)) { \ - regs->sci_icmd &= ~SCI_ICMD_DATA; \ - len--; \ - } else { \ - regs->sci_mode &= ~SCI_MODE_DMA; \ + if (i < 0) printf("ncr.c: timeout counter = %d, len = %d count=%d (count-len %d).\n", \ + i, len, *count, *count - len); \ + if (dataout) { \ + SCSI_5380->scsi_icom &= ~SC_ADTB; \ } \ - return count-len; \ + SCSI_5380->scsi_mode &= ~SC_M_DMA; \ + *count = len; \ + if((idstat = SCSI_5380->scsi_idstat) & SC_S_REQ) \ + *phase = (idstat >> 2) & 7; \ + else \ + *phase = NR_PHASE; \ + return; \ } -#define W1 *byte_data = *data++ -#define W4 *long_data = *((long*)data)++ +#define WAIT_FOR_BSY do { \ + int scsi_timeout = TIMEOUT; \ + while (((SCSI_5380->scsi_idstat & SC_S_BSY) == 0) && \ + ((SCSI_5380->scsi_idstat & SC_S_BSY) == 0) && \ + ((SCSI_5380->scsi_idstat & SC_S_BSY) == 0) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("ncr0: scsi timeout (WAIT_FOR_BSY)\n"); \ + goto scsi_timeout_error; \ + } \ + } while (0) -sci_pdma_out(regs, phase, count, data) - register volatile sci_padded_regmap_t *regs; - int phase; - int count; - u_char *data; +#define byte_data ((volatile u_char *)pdma) +#define word_data ((volatile u_short *)pdma) +#define long_data ((volatile u_long *)pdma) +#define W1(n) *byte_data = *(data + n) +#define W2(n) *word_data = *((u_short *)data + n) +#define W4(n) *long_data = *((u_long *)data + n) +#define R1(n) *data = *(byte_data + n) +#define R4(n) *((u_long *)data + n) = *long_data + +static void +transfer_pdma(u_char *phase, u_char *data, u_long *count) { - register volatile long *long_data = sci_4byte_addr; - register volatile u_char *byte_data = sci_1byte_addr; - register int len = count, i; + register volatile u_char *pdma = PDMA_ADDRESS; + register int len = *count, dmstat, i, idstat; -ncr_debug=1; - - if (count < 128) - return sci_data_out(regs, phase, count, data); - - WAIT_FOR_BSY(regs); - regs->sci_mode |= SCI_MODE_DMA; - regs->sci_icmd |= SCI_ICMD_DATA; - regs->sci_dma_send = 0; - - while ( len >= 64 ) { - READY(1); W1; READY(1); W1; READY(1); W1; READY(1); W1; - READY(1); - W4;W4;W4; W4;W4;W4;W4; W4;W4;W4;W4; W4;W4;W4;W4; - len -= 64; + if (len < 256) { + transfer_pio(phase, data, count); + return; } - while (len) { - READY(1); - W1; - len--; + SCSI_5380->scsi_tcom = *phase; + WAIT_FOR_BSY; + if (PH_IN(*phase)) { + SCSI_5380->scsi_icom = 0; + SCSI_5380->scsi_mode = IMODE_BASE | SC_M_DMA; + SCSI_5380->scsi_ircv = 0; + while (len >= 64) { + READY(0); + R4( 0); R4( 1); R4( 2); R4( 3); + R4( 4); R4( 5); R4( 6); R4( 7); + R4( 8); R4( 9); R4(10); R4(11); + R4(12); R4(13); R4(14); R4(15); + data += 64; + len -= 64; + } + while (len) { + READY(0); + R1(0); + data++; + len--; + } + } else { + SCSI_5380->scsi_mode = IMODE_BASE | SC_M_DMA; + SCSI_5380->scsi_icom = SC_ADTB; + SCSI_5380->scsi_dmstat = SC_S_SEND; + while (len >= 256) { + /* The second ready is to + * compensate for DMA-prefetch. + * Since we adjust len only at + * the end of the block, there + * is no need to correct the + * residue. + */ + READY(1); W1(0); READY(1); W1(1); + W2( 1); W4( 1); W4( 2); W4( 3); + W4( 4); W4( 5); W4( 6); W4( 7); + W4( 8); W4( 9); W4(10); W4(11); + W4(12); W4(13); W4(14); W4(15); + data += 64; + len -= 64; + } + if (len) { + READY(1); + while (len) { + W1(0); + READY(1); + data++; + len--; + } + } + i = TIMEOUT; + while (((SCSI_5380->scsi_dmstat & (SC_DMA_REQ|SC_PHS_MTCH)) + == SC_PHS_MTCH) && --i); + if (!i) + printf("ncr0: timeout waiting for SC_DMA_REQ.\n"); + *byte_data = 0; } - i = TIMEOUT; - while ( ((regs->sci_csr & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH)) - == SCI_CSR_PHASE_MATCH) && --i); - if (!i) - printf("ncr.c:%d: timeout waiting for SCI_CSR_DREQ.\n", __LINE__); - *byte_data = 0; + scsi_timeout_error: - regs->sci_mode &= ~SCI_MODE_DMA; - return count-len; -} - -#undef W1 -#undef W4 - -#define R4 *((long *)data)++ = *long_data -#define R1 *data++ = *byte_data - -sci_pdma_in(regs, phase, count, data) - register volatile sci_padded_regmap_t *regs; - int phase; - int count; - u_char *data; -{ - register volatile long *long_data = sci_4byte_addr; - register volatile u_char *byte_data = sci_1byte_addr; - register int len = count, i; - -ncr_debug=2; - if (count < 128) - return sci_data_in(regs, phase, count, data); - -/* printf("Called sci_pdma_in(0x%x, 0x%x, %d, 0x%x.\n", regs, phase, count, data); */ - - WAIT_FOR_BSY(regs); - regs->sci_mode |= SCI_MODE_DMA; - regs->sci_icmd |= SCI_ICMD_DATA; - regs->sci_irecv = 0; - - while (len >= 1024) { - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 128 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 256 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 384 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 512 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 640 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 768 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 896 */ - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /*1024 */ - len -= 1024; - } - while (len >= 128) { - READY(0); - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; - R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; R4;R4;R4;R4; /* 128 */ - len -= 128; - } - while (len) { - READY(0); - R1; - len--; - } -scsi_timeout_error: - regs->sci_mode &= ~SCI_MODE_DMA; - return count - len; -} -#undef R4 -#undef R1 -#endif - -/* Some stuff from dp.c ... */ - -/* Select a SCSI device. - */ -scsi_select_ctlr (ctlr) -int ctlr; -{ - /* May need other stuff here to syncronize between dp & aic. */ - - RD_ADR (u_char, ICU_IO) &= ~ICU_SCSI_BIT; /* i/o, not port */ - RD_ADR (u_char, ICU_DIR) &= ~ICU_SCSI_BIT; /* output */ - if (ctlr == NCR5380) - RD_ADR (u_char, ICU_DATA) &= ~ICU_SCSI_BIT; /* select = 0 for 8490 */ - else - RD_ADR (u_char, ICU_DATA) |= ICU_SCSI_BIT; /* select = 1 for AIC6250 */ + SCSI_5380->scsi_mode &= ~SC_M_DMA; + if((idstat = SCSI_5380->scsi_idstat) & SC_S_REQ) + *phase = (idstat >> 2) & 7; + else + *phase = NR_PHASE; + *count = len; + return; } diff --git a/sys/arch/pc532/dev/ncr_5380.h b/sys/arch/pc532/dev/ncr_5380.h deleted file mode 100644 index cd8c093c27a3..000000000000 --- a/sys/arch/pc532/dev/ncr_5380.h +++ /dev/null @@ -1,145 +0,0 @@ -/* $NetBSD: ncr_5380.h,v 1.2 1994/10/26 08:24:13 cgd Exp $ */ - -/* - * Mach Operating System - * Copyright (c) 1991,1990,1989 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ -/* - * File: scsi_5380.h - * Author: Alessandro Forin, Carnegie Mellon University - * Date: 5/91 - * - * Defines for the NCR 5380 (SCSI chip), aka Am5380 - * - * Modified for the pc532 by Phil Nelson. 1/94 - */ - -/* - * Register map - */ - -typedef struct { - volatile unsigned char sci_data; /* r: Current data */ -#define sci_odata sci_data /* w: Out data */ - - volatile unsigned char sci_icmd; /* rw: Initiator command */ - - volatile unsigned char sci_mode; /* rw: Mode */ - - volatile unsigned char sci_tcmd; /* rw: Target command */ - - volatile unsigned char sci_bus_csr; /* r: Bus Status */ -#define sci_sel_enb sci_bus_csr /* w: Select enable */ - - volatile unsigned char sci_csr; /* r: Status */ -#define sci_dma_send sci_csr /* w: Start dma send data */ - - volatile unsigned char sci_idata; /* r: Input data */ -#define sci_trecv sci_idata /* w: Start dma receive, target */ - - volatile unsigned char sci_iack; /* r: Interrupt Acknowledge */ -#define sci_irecv sci_iack /* w: Start dma receive, initiator */ -} sci_regmap_t; - - -/* - * Initiator command register - */ - -#define SCI_ICMD_DATA 0x01 /* rw: Assert data bus */ -#define SCI_ICMD_ATN 0x02 /* rw: Assert ATN signal */ -#define SCI_ICMD_SEL 0x04 /* rw: Assert SEL signal */ -#define SCI_ICMD_BSY 0x08 /* rw: Assert BSY signal */ -#define SCI_ICMD_ACK 0x10 /* rw: Assert ACK signal */ -#define SCI_ICMD_LST 0x20 /* r: Lost arbitration */ -#define SCI_ICMD_DIFF SCI_ICMD_LST /* w: Differential cable */ -#define SCI_ICMD_AIP 0x40 /* r: Arbitration in progress */ -#define SCI_ICMD_TEST SCI_ICMD_AIP /* w: Test mode */ -#define SCI_ICMD_RST 0x80 /* rw: Assert RST signal */ - - -/* - * Mode register - */ - -#define SCI_MODE_ARB 0x01 /* rw: Start arbitration */ -#define SCI_MODE_DMA 0x02 /* rw: Enable DMA xfers */ -#define SCI_MODE_MONBSY 0x04 /* rw: Monitor BSY signal */ -#define SCI_MODE_DMA_IE 0x08 /* rw: Enable DMA complete interrupt */ -#define SCI_MODE_PERR_IE 0x10 /* rw: Interrupt on parity errors */ -#define SCI_MODE_PAR_CHK 0x20 /* rw: Check parity */ -#define SCI_MODE_TARGET 0x40 /* rw: Target mode (Initiator if 0) */ -#define SCI_MODE_BLOCKDMA 0x80 /* rw: Block-mode DMA handshake (MBZ) */ - - -/* - * Target command register - */ - -#define SCI_TCMD_IO 0x01 /* rw: Assert I/O signal */ -#define SCI_TCMD_CD 0x02 /* rw: Assert C/D signal */ -#define SCI_TCMD_MSG 0x04 /* rw: Assert MSG signal */ -#define SCI_TCMD_PHASE_MASK 0x07 /* r: Mask for current bus phase */ -#define SCI_TCMD_REQ 0x08 /* rw: Assert REQ signal */ -#define SCI_TCMD_LAST_SENT 0x80 /* ro: Last byte was xferred - * (not on 5380/1) */ - -#define SCI_PHASE(x) SCSI_PHASE(x) - -/* - * Current (SCSI) Bus status - */ - -#define SCI_BUS_DBP 0x01 /* r: Data Bus parity */ -#define SCI_BUS_SEL 0x02 /* r: SEL signal */ -#define SCI_BUS_IO 0x04 /* r: I/O signal */ -#define SCI_BUS_CD 0x08 /* r: C/D signal */ -#define SCI_BUS_MSG 0x10 /* r: MSG signal */ -#define SCI_BUS_REQ 0x20 /* r: REQ signal */ -#define SCI_BUS_BSY 0x40 /* r: BSY signal */ -#define SCI_BUS_RST 0x80 /* r: RST signal */ - -#define SCI_CUR_PHASE(x) SCSI_PHASE((x)>>2) - -/* - * Bus and Status register - */ - -#define SCI_CSR_ACK 0x01 /* r: ACK signal */ -#define SCI_CSR_ATN 0x02 /* r: ATN signal */ -#define SCI_CSR_DISC 0x04 /* r: Disconnected (BSY==0) */ -#define SCI_CSR_PHASE_MATCH 0x08 /* r: Bus and SCI_TCMD match */ -#define SCI_CSR_INT 0x10 /* r: Interrupt request */ -#define SCI_CSR_PERR 0x20 /* r: Parity error */ -#define SCI_CSR_DREQ 0x40 /* r: DMA request */ -#define SCI_CSR_DONE 0x80 /* r: DMA count is zero */ - - -/* icu scsi chip switching */ - -#define ICU_ADR 0xfffffe00 -#define ICU_IO (ICU_ADR+20) -#define ICU_DIR (ICU_ADR+21) -#define ICU_DATA (ICU_ADR+19) -#define ICU_SCSI_BIT 0x80 diff --git a/sys/arch/pc532/dev/ncr_defs.h b/sys/arch/pc532/dev/ncr_defs.h deleted file mode 100644 index 303c8aa70faf..000000000000 --- a/sys/arch/pc532/dev/ncr_defs.h +++ /dev/null @@ -1,57 +0,0 @@ -/* $NetBSD: ncr_defs.h,v 1.2 1994/10/26 08:24:14 cgd Exp $ */ - -/*- - * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, - * Michael L. Finch, Bradley A. Grantham, and - * Lawrence A. Kesteloot - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the Alice Group. - * 4. The names of the Alice Group or any of its members may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCSI_DEFS_H -#define _SCSI_DEFS_H - -#define SCSI_PHASE_DATA_OUT 0x0 -#define SCSI_PHASE_DATA_IN 0x1 -#define SCSI_PHASE_CMD 0x2 -#define SCSI_PHASE_STATUS 0x3 -#define SCSI_PHASE_UNSPEC1 0x4 -#define SCSI_PHASE_UNSPEC2 0x5 -#define SCSI_PHASE_MESSAGE_OUT 0x6 -#define SCSI_PHASE_MESSAGE_IN 0x7 - -#define SCSI_PHASE(x) ((x)&0x7) - -/* These should be fixed up. */ - -#define SCSI_RET_SUCCESS 0 -#define SCSI_RET_RETRY 1 -#define SCSI_RET_DEVICE_DOWN 2 -#define SCSI_RET_COMMAND_FAIL 3 - -#endif diff --git a/sys/arch/pc532/dev/ncrreg.h b/sys/arch/pc532/dev/ncrreg.h new file mode 100644 index 000000000000..e64f295cc1e7 --- /dev/null +++ b/sys/arch/pc532/dev/ncrreg.h @@ -0,0 +1,145 @@ +/* $NetBSD: ncrreg.h,v 1.1 1995/06/09 04:36:26 phil Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * PC532-Port by Matthias Pfaller. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NCR5380REG_H +#define _NCR5380REG_H + +#define PDMA_ADDRESS ((volatile u_char *) 0xffe00000) +#define SCSI_5380 ((volatile struct scsi_5380 *) 0xffd00000) + +struct scsi_5380 { + volatile u_char scsi_5380[8]; /* use only the odd bytes */ +}; + +#define scsi_data scsi_5380[0] /* Data register */ +#define scsi_icom scsi_5380[1] /* Initiator command register */ +#define scsi_mode scsi_5380[2] /* Mode register */ +#define scsi_tcom scsi_5380[3] /* Target command register */ +#define scsi_idstat scsi_5380[4] /* Bus status register */ +#define scsi_dmstat scsi_5380[5] /* DMA status register */ +#define scsi_trcv scsi_5380[6] /* Target receive register */ +#define scsi_ircv scsi_5380[7] /* Initiator receive register */ + +/* + * Definitions for Initiator command register. + */ +#define SC_A_RST 0x80 /* RW - Assert RST */ +#define SC_TEST 0x40 /* W - Test mode */ +#define SC_AIP 0x40 /* R - Arbitration in progress */ +#define SC_LA 0x20 /* R - Lost arbitration */ +#define SC_A_ACK 0x10 /* RW - Assert ACK */ +#define SC_A_BSY 0x08 /* RW - Assert BSY */ +#define SC_A_SEL 0x04 /* RW - Assert SEL */ +#define SC_A_ATN 0x02 /* RW - Assert ATN */ +#define SC_ADTB 0x01 /* RW - Assert Data To Bus */ + +/* + * Definitions for mode register + */ +#define SC_B_DMA 0x80 /* RW - Block mode DMA (not on TT!) */ +#define SC_T_MODE 0x40 /* RW - Target mode */ +#define SC_E_PAR 0x20 /* RW - Enable parity check */ +#define SC_E_PARI 0x10 /* RW - Enable parity interrupt */ +#define SC_E_EOPI 0x08 /* RW - Enable End Of Process Interrupt */ +#define SC_MON_BSY 0x04 /* RW - Monitor BSY */ +#define SC_M_DMA 0x02 /* RW - Set DMA mode */ +#define SC_ARBIT 0x01 /* RW - Arbitrate */ + +/* + * Definitions for tcom register + */ +#define SC_LBS 0x80 /* RW - Last Byte Send (not on TT!) */ +#define SC_A_REQ 0x08 /* RW - Assert REQ */ +#define SC_A_MSG 0x04 /* RW - Assert MSG */ +#define SC_A_CD 0x02 /* RW - Assert C/D */ +#define SC_A_IO 0x01 /* RW - Assert I/O */ + +/* + * Definitions for idstat register + */ +#define SC_S_RST 0x80 /* R - RST is set */ +#define SC_S_BSY 0x40 /* R - BSY is set */ +#define SC_S_REQ 0x20 /* R - REQ is set */ +#define SC_S_MSG 0x10 /* R - MSG is set */ +#define SC_S_CD 0x08 /* R - C/D is set */ +#define SC_S_IO 0x04 /* R - I/O is set */ +#define SC_S_SEL 0x02 /* R - SEL is set */ +#define SC_S_PAR 0x01 /* R - Parity bit */ + +/* + * Definitions for dmastat register + */ +#define SC_END_DMA 0x80 /* R - End of DMA */ +#define SC_DMA_REQ 0x40 /* R - DMA request */ +#define SC_PAR_ERR 0x20 /* R - Parity error */ +#define SC_IRQ_SET 0x10 /* R - IRQ is active */ +#define SC_PHS_MTCH 0x08 /* R - Phase Match */ +#define SC_BSY_ERR 0x04 /* R - Busy error */ +#define SC_ATN_STAT 0x02 /* R - State of ATN line */ +#define SC_ACK_STAT 0x01 /* R - State of ACK line */ +#define SC_S_SEND 0x00 /* W - Start DMA output */ + +#define SC_CLINT { /* Clear interrupts */ \ + int i = SCSI_5380->scsi_ircv; \ + } + + +/* + * Definition of SCSI-bus phases. The values are determined by signals + * on the SCSI-bus. DO NOT CHANGE! + * The values must be used to index the pointers in SCSI-PARMS. + */ +#define NR_PHASE 8 +#define PH_DATAOUT 0 +#define PH_DATAIN 1 +#define PH_CMD 2 +#define PH_STATUS 3 +#define PH_RES1 4 +#define PH_RES2 5 +#define PH_MSGOUT 6 +#define PH_MSGIN 7 + +#define PH_OUT(phase) (!(phase & 1)) /* TRUE if output phase */ +#define PH_IN(phase) (phase & 1) /* TRUE if input phase */ + +/* + * Id of Host-adapter + */ +#define SC_HOST_ID 0x80 + +/* + * Base setting for 5380 mode register + */ +#define IMODE_BASE SC_E_PAR + +#endif /* _NCR5380REG_H */ diff --git a/sys/arch/pc532/dev/scn.c b/sys/arch/pc532/dev/scn.c index 573a9568aa15..6af7a6bf79fa 100644 --- a/sys/arch/pc532/dev/scn.c +++ b/sys/arch/pc532/dev/scn.c @@ -1,4 +1,4 @@ -/* $NetBSD: scn.c,v 1.17 1995/05/16 07:30:38 phil Exp $ */ +/* $NetBSD: scn.c,v 1.18 1995/06/09 04:36:30 phil Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California.