⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 esp.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1988, 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: *	This product includes software developed by the University of *	California, Lawrence Berkeley Laboratory. * * 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 University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * *	@(#)esp.c	8.2 (Berkeley) 12/14/93 * * from: $Header: esp.c,v 1.28 93/04/27 14:40:44 torek Exp $ (LBL) * * Loosely derived from Mary Baker's devSCSIC90.c from the Berkeley * Sprite project, which is: * * Copyright 1988 Regents of the University of California * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies.  The University of California * makes no representations about the suitability of this * software for any purpose.  It is provided "as is" without * express or implied warranty. * * from /sprite/src/kernel/dev/sun4c.md/RCS/devSCSIC90.c,v 1.4 * 90/12/19 12:37:58 mgbaker Exp $ SPRITE (Berkeley) *//* * Sbus ESP/DMA driver.  A single driver must be used for both devices * as they are physically tied to each other:  The DMA chip can only * be used to assist ESP SCSI transactions; the ESP interrupt enable is * in the DMA chip csr. * * Since DMA and SCSI interrupts are handled in the same routine, the * DMA device does not declare itself as an sbus device.  This saves * some space. */#include <sys/param.h>#include <sys/buf.h>#include <sys/device.h>#include <sys/malloc.h>#include <dev/scsi/scsi.h>#include <dev/scsi/scsivar.h>#include <machine/autoconf.h>#include <machine/cpu.h>#include <sparc/sbus/dmareg.h>#define ESP_PHASE_NAMES#include <sparc/sbus/espreg.h>#include <sparc/sbus/sbusvar.h>#include <libkern/libkern.h>/* * This driver is largely a giant state machine: * *	Given some previous SCSI state (as set up or tracked by us *	earlier) and the interrupt registers provided on the chips *	(dmacsr, espstat, espstep, and espintr), derive an action. *	In many cases this is just a matter of reading the target's *	phase and following its orders, which sets a new state. * * This sequencing is done in espact(); the state is primed in espselect(). * * Data transfer is always done via DMA.  Unfortunately, there are * limits in the DMA and ESP chips on how much data can be moved * in a single operation.  The ESP chip has a 16-bit counter, so * it is limited to 65536 bytes.  More insidiously, while the DMA * chip has a 32-bit address, this is composed of a 24-bit counter * with an 8-bit latch, so it cannot cross a 16 MB boundary.  To * handle these, we program a smaller count than our caller requests; * when this shorter transfer is done, if the target is still up * for data transfer, we simply keep going (updating the DMA address) * as needed. * * Another state bit is used to recover from bus resets: * *	A single TEST UNIT READY is attempted on each target before any *	real communication begins; this TEST UNIT READY is allowed to *	fail in any way.  This is required for the Quantum ProDrive 100 *	MB disks, for instance, which respond to their first selection *	with status phase, and for anything that insists on implementing *	the broken SCSI-2 synch transfer initial message. * * This is done in espclear() (which calls espselect(); functions that * call espselect() must check for clearing first). * * The state machines actually intermingle, as some SCSI sequences are * only allowed during clearing. *//* per-DMA variables */struct dma_softc {	struct	device dc_dev;		/* base device */	volatile struct dmareg *dc_dma;	/* register virtual address */	int	dc_dmarev;		/* revision */	char	*dc_dmafmt;		/* format for error messages */};void	dmaattach(struct device *, struct device *, void *);struct cfdriver dmacd =    { NULL, "dma", matchbyname, dmaattach, DV_DULL, sizeof(struct dma_softc) };/* per-ESP variables */struct esp_softc {	/*	 * External interfaces.	 */	struct	hba_softc sc_hba;	/* base device + hba, must be first */#define	sc_dev	sc_hba.hba_dev	struct	sbusdev sc_sd;		/* sbus device */	struct	intrhand sc_ih;		/* interrupt entry */	struct	evcnt sc_intrcnt;	/* interrupt counter */	struct	dma_softc *sc_dc;	/* pointer to corresponding dma sc */	/*	 * Addresses mapped to hardware registers.	 */	volatile struct espreg *sc_esp;	volatile struct dmareg *sc_dma;	/*	 * Copies of registers cleared/unlatched by reading.	 * (FIFO flags is not cleared, but we want it for debugging.)	 */	u_long	sc_dmacsr;	u_char	sc_espstat;	u_char	sc_espstep;	u_char	sc_espintr;	u_char	sc_espfflags;	/* miscellaneous */	int	sc_clockfreq;		/* clock frequency */	u_char	sc_sel_timeout;		/* select timeout */	u_char	sc_id;			/* initiator ID (default = 7) */	u_char	sc_needclear;		/* uncleared targets (1 bit each) */	u_char	sc_esptype;		/* 100, 100A, 2xx (see below) */	u_char	sc_ccf;			/* clock conversion factor */	u_char	sc_conf1;		/* value for config reg 1 */	u_char	sc_conf2;		/* value for config reg 2 */	u_char	sc_conf3;		/* value for config reg 3 */	struct	bootpath *sc_bp;	/* esp bootpath so far */	/*	 * Information pertaining to the current transfer,	 * including sequencing.	 *	 * The size of sc_msg is the size of the ESP fifo,	 * since we do message-in simply by allowing the fifo to fill.	 */	char	sc_probing;		/* used during autoconf; see below */	char	sc_clearing;		/* true => cmd is just to clear targ */	char	sc_state;		/* SCSI protocol state; see below */	char	sc_sentcmd;		/* set once we get cmd out */	char	sc_dmaactive;		/* true => doing dma */#ifdef notyet	u_char	sc_sync;		/* synchronous transfer stuff (?) */#endif	u_char	sc_stat[2];		/* status from last `status' phase */	u_char	sc_msg[16];		/* message from device */	u_short	sc_dmactl;		/* control to load into dma csr */	u_long	sc_dmaaddr;		/* address for next xfer */	int	sc_dmasize;		/* size of current xfer */	int	sc_resid;		/* count of bytes not yet xferred */	int	sc_targ;		/* the target involved */	struct	scsi_cdb *sc_curcdb;	/* ptr to current command */	/* might cdbspace eventually be per-target? */	struct	scsi_cdb sc_cdbspace;	/* space for one command */};/* * Values for sc_esptype (used to control configuration reset, and for * workarounds for chip bugs).  The order is important; see espreset(). */#define	ESP100	0#define	ESP100A	1#define	ESP2XX	2/* * Probe state.  0 means not probing.  While looking for each target * we set this to PROBE_TESTING and do a TEST UNIT READY on unit 0. * If selection fails, this is changed to PROBE_NO_TARGET; otherwise * we assume the target exists, regardless of the result of the test. */#define	PROBE_TESTING	1#define	PROBE_NO_TARGET	2/* * States in sc_state. * * Note that S_SVC is rare: normally we load the SCSI command into the * ESP fifo and get interrupted only when the device has gone to data * or status phase.  If the device wants to play games, though, we end * up doing things differently. */char *espstates[] = {#define	S_IDLE		0	/* not doing anything */	"idle",#define	S_SEL		1	/* expecting select done interrupt */	"selecting",#define	S_SVC		2	/* expecting service req interrupt */	"waiting for svc req",#define	S_DI		3	/* expecting data-in done interrupt */	"receiving data",#define	S_DO		4	/* expecting data-out done interrupt */	"sending data",#define	S_STAT		5	/* expecting status done interrupt */	"receiving status",#define	S_MI		6	/* expecting message-in done interrupt */	"receiving message",#define	S_FI		7	/* expecting final disconnect interrupt */	"waiting for disconnect"};/* * Hardware limits on transfer sizes (see comments at top). */#define	ESPMAX		(64 * 1024)#define	DMAMAX(a)	(0x01000000 - ((a) & 0x00ffffff))/* * Return values from espact(). */#define	ACT_CONT	0	/* espact() handled everything */#define	ACT_IO		1	/* espact() is xferring data */#define	ACT_DONE	2	/* handled everything, and op is now done */#define	ACT_ERROR	3	/* an error occurred, op has been trashed */#define	ACT_RESET	4	/* please reset ESP, then do ACT_ERROR */#define	ACT_QUICKINTR	5	/* another interrupt is expected immediately *//* autoconfiguration driver */void	espattach(struct device *, struct device *, void *);struct cfdriver espcd =    { NULL, "esp", matchbyname, espattach, DV_DULL, sizeof(struct esp_softc),      "intr" };/* Sbus driver */void	espsbreset(struct device *);/* interrupt interface */int	espintr(void *);/* SCSI HBA driver */int	espicmd(struct hba_softc *, int, struct scsi_cdb *, caddr_t, int, int);int	espdump(struct hba_softc *, int, struct scsi_cdb *, caddr_t, int);void	espstart(struct device *, struct sq *, struct buf *,		scdgo_fn, struct device *);int	espgo(struct device *, int, scintr_fn, struct device *,		struct buf *, int);void	esprel(struct device *);void	esphbareset(struct hba_softc *, int);static struct hbadriver esphbadriver =    { espicmd, espdump, espstart, espgo, esprel, esphbareset };/* other prototypes */static void espdoattach(int);static void dmareset(struct esp_softc *);static void espreset(struct esp_softc *, int);static void esperror(struct esp_softc *, const char *);static int espact(struct esp_softc *);void espselect(struct esp_softc *, int, struct scsi_cdb *);/* second arg to espreset() */#define	RESET_ESPCHIP	0x1#define	RESET_SCSIBUS	0x2#define	RESET_BOTH	(RESET_ESPCHIP | RESET_SCSIBUS)/* * Attach a found DMA chip. * The second argument is really a pointer to an sbus_attach_args. */voiddmaattach(parent, dev, args)	struct device *parent;	struct device *dev;	void *args;{	register struct dma_softc *dc = (struct dma_softc *)dev;	register struct sbus_attach_args *sa = args;	register volatile struct dmareg *dma;	register int rev;	struct esp_softc *esc;	if (sa->sa_ra.ra_vaddr)		dma = (volatile struct dmareg *)sa->sa_ra.ra_vaddr;	else		dma = (volatile struct dmareg *)		    mapiodev(sa->sa_ra.ra_paddr, sizeof(struct dmareg));	dc->dc_dma = dma;	switch (rev = DMA_REV(dma->dma_csr)) {	case DMAREV_1:		printf(": rev 1\n");		dc->dc_dmafmt = DMA_REV1_BITS;		break;	case DMAREV_2:		printf(": rev 2\n");		dc->dc_dmafmt = DMA_REV2_BITS;		break;	case DMAREV_3:		printf(": rev 3\n");		printf("WARNING: esp.c not yet updated for rev 3\n");		dc->dc_dmafmt = DMA_REV3_BITS;		break;	default:		printf(": unknown revision code 0x%x\n", rev);		dc->dc_dmafmt = DMA_REV3_BITS;	/* cross fingers */		break;	}	dc->dc_dmarev = rev;	espdoattach(dc->dc_dev.dv_unit);}/* * Attach a found ESP chip.  Search for targets; attach each one found. * The latter must be deferred if the corresponding dma chip has not yet * been configured. */voidespattach(parent, self, args)	struct device *parent;	struct device *self;	void *args;{	register struct esp_softc *sc = (struct esp_softc *)self;	register struct sbus_attach_args *sa = args;	register volatile struct espreg *esp;	register struct bootpath *bp;	int node, pri, freq, t;	if (sa->sa_ra.ra_nintr != 1) {		printf(": expected 1 interrupt, got %d\n", sa->sa_ra.ra_nintr);		return;	}	pri = sa->sa_ra.ra_intr[0].int_pri;	printf(" pri %d", pri);	if (sa->sa_ra.ra_vaddr)		esp = (volatile struct espreg *)sa->sa_ra.ra_vaddr;	else		esp = (volatile struct espreg *)		    mapiodev(sa->sa_ra.ra_paddr, sizeof(struct espreg));	sc->sc_esp = esp;	node = sa->sa_ra.ra_node;	sc->sc_id = getpropint(node, "initiator-id", 7);	freq = getpropint(node, "clock-frequency", -1);	if (freq < 0)		freq =		    ((struct sbus_softc *)sc->sc_dev.dv_parent)->sc_clockfreq;	/* MIGHT NEED TO RESET ESP CHIP HERE ...? */	/*	 * Find out whether we have a -100, -100A, or -2xx,	 * and what speed it runs at.	 */	sc->sc_conf1 = sc->sc_id | ESPCONF1_PARENB;	/* sc->sc_conf2 = 0; */	/* sc->sc_conf3 = 0; */	esp->esp_conf1 = sc->sc_conf1;	esp->esp_conf2 = 0;	esp->esp_conf2 = ESPCONF2_SCSI2 | ESPCONF2_RPE;	if ((esp->esp_conf2 & ~ESPCONF2_RSVD) !=	    (ESPCONF2_SCSI2 | ESPCONF2_RPE)) {		printf(": ESP100");		sc->sc_esptype = ESP100;	} else {		esp->esp_conf2 = 0;		esp->esp_conf3 = 0;		esp->esp_conf3 = 5;		if (esp->esp_conf3 != 5) {	/* XXX def bits */			printf(": ESP100A");			sc->sc_esptype = ESP100A;		} else {			esp->esp_conf3 = 0;			printf(": ESP2XX");			sc->sc_esptype = ESP2XX;		}	}	printf(", clock = %s MHz, ID = %d\n", clockfreq(freq), sc->sc_id);	/*	 * Set clock conversion factor and select timeout.	 * N.B.: clock frequency is not actually used in the rest	 * of the driver; I calculate it here for completeness only	 * (so I can see it when debugging).	 */	sc->sc_clockfreq = freq;	freq = howmany(freq, 1000 * 1000);	/* convert to MHz */	t = ESPCCF_FROMMHZ(freq);	if (t < ESPCCF_MIN)		t = ESPCCF_MIN;	sc->sc_ccf = t;	t = ESPTIMO_REGVAL(250, t, freq);	/* timeout = 250 ms. */	if (t >= 256)		t = 0;	sc->sc_sel_timeout = t;	/*	 * Link into sbus; set interrupt handler.	 */	sc->sc_sd.sd_reset = espsbreset;	sbus_establish(&sc->sc_sd, &sc->sc_dev);	sc->sc_ih.ih_fun = espintr;	sc->sc_ih.ih_arg = sc;	intr_establish(pri, &sc->sc_ih);	evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);#define SAME_ESP(bp, sa) \	((bp->val[0] == sa->sa_slot && bp->val[1] == sa->sa_offset) || \

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -