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

📄 ncr.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* @(#)ncr.c 1.1 92/07/30 SMI *//* * Copyright (c) 1989 by Sun Microsystems, Inc. */#include "ncr.h"#if NNCR > 0#ifndef lintstatic  char sccsid[] = "@(#)ncr.c 1.1  92/07/30";#endif  lint/* * Features of this version: * * A.	Set up dma before any possibility of going into a DATA PHASE. * 	This means that the dma engine must be setup: * *	1:  prior to dropping SEL and deasserting NCR_ICR_DATA *	    in the selection process * *	2:  prior to acknowledging any message (including the IDENTIFY *	    message received during reselection). * *	Ick. This must be done because this way because the 3/50 && 3/60 * 	DMA engines don't work on sending out the SCSI bus otherwise. * * B.	We get mostly PHASE NOT MATCHED interrupts on other than DATA PHASE. * * C.	Linked commands now work */#include <scsi/scsi.h>#include <scsi/adapters/ncrreg.h>#include <sys/mman.h>#include <machine/pte.h>#include <machine/cpu.h>#include <vm/seg.h>/* * Debugging macros */int	ncr_debug = 0;#define	PRINTF1	if (ncr_debug) printf#define	PRINTF2	if (ncr_debug > 1) printf#define	PRINTF3	if (ncr_debug > 2) printf/* #define	EPRINTF	if (scsi_options & SCSI_DEBUG_HA) printf */#define	EPRINTF	printf#define	INFORMATIVE 	(ncr_debug)/* * Short hand defines */#define	UNDEFINED		-1#define	CURRENT_CMD(ncr)	((ncr)->n_slots[(ncr)->n_cur_slot])#define	SLOT(sp)		((short)(Tgt((sp))<<3|(Lun((sp)))))#define	NEXTSLOT(slot)		((slot)+1) & ((NTARGETS*NLUNS_PER_TARGET)-1)#define	Tgt(sp)			((sp)->cmd_pkt.pkt_address.a_target)#define	Lun(sp)			((sp)->cmd_pkt.pkt_address.a_lun)#define	NON_INTR(sp)	((sp->cmd_pkt.pkt_flags & FLAG_NOINTR) != 0)#define	CNAME	ncrdriver.mdr_cname#define	CNUM	(ncr-ncr_softc)/* * Global function declarations */void ncrintr();/* * Local function declarations */static int ncr_start(), ncr_abort(), ncr_reset(), ncr_getcap(), ncr_setcap();static int ncr_NACKmsg(), ncr_ACKmsg(), ncr_sbcwait(), ncr_csrwait();static int ncr_xfrin(), ncr_xfrin_noack();static int ncr_ustart();static void ncr_phasemanage();static int ncr_getphase();static int ncr_dopoll(), ncrpoll();static void ncrsvc();static int ncr_select(), ncr_reselect();static void ncr_preempt(), ncr_disconnect();static int ncr_sendcmd(), ncr_sendmsg(), ncr_recvmsg(), ncr_senddata();static int ncr_recvdata(), ncr_recvstatus();static void ncr_finish();static int ncr_watch();static void ncr_printstate(), ncr_curcmd_timeout(), ncr_internal_abort();static void ncr_do_abort(), ncr_internal_reset(), ncr_hw_reset();static void ncr_dump_datasegs();static caddr_t ncr_mapdmabuf();/* * DMA function declarations */static int ncr_flushbyte(), ncr_dma_wait(), ncr_dma_cleanup();static void ncr_dma_enable(), ncr_dma_setup();static int ncr_vme_dma_cleanup(), ncr_vme_waitdma(), ncr_vme_dma_recv();#ifdef	sun4static int ncr_cobra_dma_cleanup();static int ncr_cobra_dma_chkerr(), ncr_cobra_dma_recv();#endif	sun4#ifdef	sun3static int  ncr_ob_dma_cleanup();static void ncr_ob_dma_setup();#endifstatic int ncr_3e_dma_cleanup();static int ncr_3e_fetchdata(), ncr_3e_storedata();/* * Local static data */static struct ncr *ncr_softc = (struct ncr *) 0;static long  Dmabase;	/*			 * Base address to stuff into DMA engine			 * and or into the assumed offset from DVMA			 * that is in the dma cookies we get.			 */static char *Cname;	/*			 * pointer to controller name- copied here so that			 * error printouts don't generated long sequences			 * of structure pointer de-references.			 */static int ncr_arbitration_delay	= NCR_ARBITRATION_DELAY;static int ncr_bus_clear_delay		= NCR_BUS_CLEAR_DELAY;static int ncr_bus_settle_delay		= NCR_BUS_SETTLE_DELAY;static char *cbsr_bits = CBSR_BITS;/* * Probe, Slave and Attach routines */static int ncr_probe(), ncr_slave(), ncr_attach();static int nncr = NNCR;struct mb_ctlr *ncrctlr[NNCR];struct mb_driver ncrdriver = {	ncr_probe, ncr_slave, ncr_attach, 0, 0, ncrpoll,	NCR_HWSIZE, "scsibus", 0, "ncr", ncrctlr, MDR_BIODMA};static intncr_probe(reg, ctlr)u_short *reg;int ctlr;{	register struct ncrsbc *ncrp = (struct ncrsbc *) reg;	register struct ncr *ncr;	long val;	u_long dma_base, sbcaddr, ctladdr, dmaaddr;#ifdef	sun3	u_long udcp;#endif	caddr_t dmabuf;	int host_type = -1;	u_short *shortp;	/*	 * Check for ncr 5380 Scsi Bus Ctlr chip with "peekc()"; struct	 * ncr-5380 is common to all onboard scsi and vme scsi board. if not	 * exist, return 0.	 */	PRINTF3("ncr_probe: reg= %x virt, %x phys\n", reg,		getdevaddr((caddr_t) reg));	/*	 * We can use the first byte address of reg, 'coz we'll guarantee	 * (by the time we are through) that that will always be the first	 * byte of the NCR 5380 SBC (which should be the cbsr register).	 */	if (peekc((caddr_t)reg) == -1) {		return (0);	}	sbcaddr = (u_long) reg;	dmaaddr = ((u_long) reg) + sizeof (struct ncrsbc);	/*	 * probe for different host adaptor interfaces	 */	switch (cpu) {#ifdef sun4	case CPU_SUN4_110:		/*		 * probe for 4/110 dma interface		 */		ctladdr = ((u_long) reg) + COBRA_CSR_OFF;		if (peekl((long *) (dmaaddr), (long *) &val) == -1) {			return (0);		}		host_type = IS_COBRA;		dma_base = DMA_BASE_110;		break;#endif	sun4#ifdef	sun3	case CPU_SUN3_50:	case CPU_SUN3_60:		ctladdr = ((u_long) reg) + CSR_OFF;		if (peek((short *)&		    ((struct ncrdma *)dmaaddr)->udc_rdata) == -1)			return (0);		udcp = (u_long) IOPBALLOC(sizeof (struct udc_table));		if (udcp == 0 || udcp & 0x3) {			printf("%s%d: no udc table\n", CNAME, ctlr);			if (udcp)				IOPBFREE(udcp, sizeof (struct udc_table));			return (0);		}		host_type = IS_3_50;		dma_base = DMA_BASE_3_50;		break;#endif	sun3	default:		/*		 * This is either a SCSI-3 or a 3/E VME board		 *		 * First see whether the dma address register is there		 * The low 16 bits is common across all platforms.		 *		 */		if (peek((short *) (dmaaddr + 2)) == -1) {			return (0);		}		/*		 * Okay, now whether it is a 3/E board		 */		ctladdr = ((u_long) reg) + SUN3E_CSR_OFF;		if (peek((short *) (ctladdr + 2)) != -1) {			if (poke ((short *) (ctladdr + 2), 0) == 0) {				if (peek((short *) (ctladdr + 2)) == 0x402) {					dmabuf = ncr_mapdmabuf(reg);					if (dmabuf == (caddr_t) 0)						return (0);					host_type = IS_3E;					dma_base = 0;					break;				}			}		}		/*		 * Okay- it wasn't a 3/E. Now see whether it's a scsi-3 board.		 *		 * Make sure that it isn't a SCSI-2 board (which occupies 4k		 * of VME space instead of the 2k that the SCSI-3 occupies).		 * (the above is a quote from si.c. The code below doesn't		 *  seem to bear this out exactly).		 *		 */		if (peek((short *) (((u_long) reg) + 0x800)) != -1) {			return (0);		}		/*		 * Make sure that we're cool (really a scsi-3 board).		 */		ctladdr = ((u_long) reg) + CSR_OFF;		if (peek((short *) (ctladdr + 2)) == -1)			return (0);		if ((((struct ncrctl *) ctladdr)->csr.lsw & NCR_CSR_ID) == 0) {			printf("%s%d: unmodified scsi-3 board- you lose..\n",				CNAME, ctlr);			return (0);		}		host_type = IS_SCSI3;		dma_base = 0;		break;	}	/*	 * Establish initial softc values	 */	if (ncr_softc == 0) {		ncr_softc = (struct ncr *)			kmem_zalloc((unsigned) (NNCR * sizeof (struct ncr)));		if (ncr_softc == 0)			return (0);		Dmabase = dma_base;		timeout(ncr_watch, (caddr_t) 0, hz);	}	/*	 * initialize software structure	 */	ncr = &ncr_softc[ctlr];	/*	 * Allocate a page for being able to	 * flush the last bit of a data transfer.	 */	ncr->n_kment = rmalloc(kernelmap, mmu_btopr(MMU_PAGESIZE));	if (ncr->n_kment == 0) {		return (0);	}	ncr->n_dev = &ncrdriver;	ncr->n_id = NCR_HOST_ID;	ncr->n_sbc = (struct ncrsbc *) (sbcaddr);	ncr->n_dma = (struct ncrdma *) (dmaaddr);	ncr->n_ctl = (struct ncrctl *) (ctladdr);	ncr->n_type = host_type;	ncr->n_tran.tran_start = ncr_start;	ncr->n_tran.tran_abort = ncr_abort;	ncr->n_tran.tran_reset = ncr_reset;	ncr->n_tran.tran_getcap = ncr_getcap;	ncr->n_tran.tran_setcap = ncr_setcap;	ncr->n_tran.tran_pktalloc = scsi_std_pktalloc;	ncr->n_tran.tran_dmaget = scsi_std_dmaget;	ncr->n_tran.tran_pktfree = scsi_std_pktfree;	ncr->n_tran.tran_dmafree = scsi_std_dmafree;	ncr->n_last_slot = ncr->n_cur_slot = UNDEFINED;	switch (host_type) {#ifdef	sun4	case IS_COBRA:		ncr->n_dma_setup = ncr_dma_setup;		ncr->n_dma_cleanup = ncr_cobra_dma_cleanup;		break;#endif	sun4#ifdef	sun3	case IS_3_50:		ncr->n_dma_setup = ncr_ob_dma_setup;		ncr->n_dma_cleanup = ncr_ob_dma_cleanup;		ncr->n_udc = (struct udc_table *) udcp;		break;#endif	sun3	case IS_SCSI3:		ncr->n_dma_setup = ncr_dma_setup;		ncr->n_dma_cleanup = ncr_vme_dma_cleanup;		break;	case IS_3E:		ncr->n_dmabuf = dmabuf;		ncr->n_dma_setup = ncr_dma_setup;		ncr->n_dma_cleanup = ncr_3e_dma_cleanup;		break;	}	ncr_internal_reset(ncr, NCR_RESET_ALL, RESET_NOMSG);	return (NCR_HWSIZE);}/*ARGSUSED*/static intncr_slave(md, reg)struct mb_device *md;caddr_t reg;{	struct ncr *ncr = &ncr_softc[md->md_unit];	md->md_slave = ncr->n_id << 3;	return (TRUE);}static intncr_attach(md)struct mb_device *md;{	int i;	static int ncr_spl = 0;	struct ncr *ncr = &ncr_softc[md->md_unit];	/*	 * calculate max spl value so far seen and the default config_value	 */	ncr_spl = MAX(ncr_spl, pritospl(md->md_intpri));	/*	 * make sure that everyone, including us, is locking at the same	 * priority	 */	for (i = 0; i <= md->md_unit; i++) {		ncr_softc[i].n_tran.tran_spl = ncr_spl;	}	/*	 * Initialize interrupt vector register (if any)	 */	if (IS_VME(ncr->n_type) && md->md_mc->mc_intr) {		if (ncr->n_type == IS_3E) {			N_CTL->ivec2 = (md->md_mc->mc_intr->v_vec & 0xff);		} else {			N_CTL->iv_am = (md->md_mc->mc_intr->v_vec & 0xff) |				VME_SUPV_DATA_24;		}		*(md->md_mc->mc_intr->v_vptr) = (int) ncr;	}	/*	 * Now make ourselves known to the rest of the SCSI world	 */	scsi_config(&ncr->n_tran, md);}/* * map in 3/E dma buffer. This buffer resides in the * 64kb below the base address of the NCR 5380 registers. * * * XXX: We're cheating here because we know what address space * XXX: the 3/E board resides in, plus we know that the dma buffer * XXX: is on a page boundary. * XXX: * XXX: We need to do a better job than that on this! */static caddr_tncr_mapdmabuf(sbcreg)u_short *sbcreg;{	extern int getdevaddr();	extern struct seg kseg;	u_long addr, pageval;	u_short *reg;	long a;	addr =  getdevaddr((caddr_t) sbcreg) - (64 * 1024);	if (addr & MMU_PAGEOFFSET) {		return ((caddr_t) 0);	}#ifdef	sun3x	pageval = btop(VME24D16_BASE + (addr & VME24D16_MASK));#else	sun3x	pageval = PGT_VME_D16 | btop(VME24_BASE | (addr & VME24_MASK));#endif	sun3x	a = rmalloc(kernelmap, btoc(64 * 1024));	if (a == 0)		return ((caddr_t) 0);	reg = (u_short *) ((int) kmxtob(a));	segkmem_mapin(&kseg, (addr_t) reg, (u_int) (64 * 1024),		PROT_READ | PROT_WRITE, pageval, 0);	if (peek((short *)reg) < 0 || poke((short *)reg, (short) 0xa55e) ||	    peek((short *)reg) != 0xa55e) {		rmfree (kernelmap, btoc (64 * 1024), (u_long) a);		return ((caddr_t) 0);	}	return ((caddr_t) reg);}/* * External Interface Routines */static intncr_start(sp)register struct scsi_cmd *sp;{	register struct ncr *ncr;	register int s;	short slot;	/*	 * get scsi address based on the "cookie" in cmd_packet	 */	ncr = (struct ncr *)sp->cmd_pkt.pkt_address.a_cookie;	slot =	((Tgt(sp)*NLUNS_PER_TARGET) | Lun(sp));	s = splr(ncr->n_tran.tran_spl);	if (ncr->n_slots[slot] != (struct scsi_cmd *) 0) {		PRINTF3("ncr_start: queuing error\n");		(void) splx(s);		return (FALSE);	}	/*	 * reinitialize some fields in the 'cmd_pkt' that need it...	 * if upper level requests watchdog, set timeout_cnt and flag	 */	sp->cmd_pkt.pkt_resid = 0;	sp->cmd_pkt.pkt_reason = sp->cmd_pkt.pkt_state =		sp->cmd_pkt.pkt_statistics = 0;	sp->cmd_cdbp = (caddr_t) sp->cmd_pkt.pkt_cdbp;	sp->cmd_scbp = sp->cmd_pkt.pkt_scbp;	*sp->cmd_scbp = 0;		/* clear status byte array */	if (sp->cmd_timeout = sp->cmd_pkt.pkt_time)		sp->cmd_flags |= CFLAG_WATCH;	else		sp->cmd_flags &= ~CFLAG_WATCH;	sp->cmd_data = sp->cmd_saved_data = sp->cmd_mapping;	sp->cmd_subseg.d_base = sp->cmd_mapping;	sp->cmd_subseg.d_count = 0;	sp->cmd_subseg.d_next = (struct dataseg *) 0;	sp->cmd_cursubseg = &sp->cmd_subseg;	sp->cmd_flags &= ~(CFLAG_NEEDSEG|CFLAG_CMDDISC);	/*	 * If this is a non-interrupting command, don't allow disconnects	 */	if (NON_INTR(sp)) {		sp->cmd_pkt.pkt_flags |= FLAG_NODISCON;	}	/*	 * accept the command by setting the req job_ptr in appropriate slot	 */	ncr->n_ncmds++;	ncr->n_slots[slot] = sp;	if ((sp->cmd_pkt.pkt_flags & FLAG_NOINTR) == 0) {		if ((ncr->n_npolling == 0) && (ncr->n_state == STATE_FREE)) {			(void) ncr_ustart(ncr, slot);		}	} else  if (ncr->n_state == ACTS_ABORTING) {		printf("%s%d: unable to start non-intr cmd\n", CNAME, CNUM);		(void) splx(s);		return (FALSE);	} else {		/*		 * Wait till all current commands completed with STATE_FREE by		 * "ncr_dopoll()", then fire off the job, check if preempted		 * right away, try again; accept the command		 */		PRINTF3("ncr_start: poll cmd, state= %x\n", ncr->n_state);		ncr->n_npolling++;		while (ncr->n_npolling != 0) {			/*			 * drain any current active command(s)			 */			while (ncr->n_state != STATE_FREE) {				if (ncr_dopoll(ncr)) {					(void) splx(s);					return (FALSE);				}			}			/*			 * were we preempted by a reselect coming back in?			 * If so, 'round we go again....			 */			PRINTF3("ncr_start: ready to start cmd\n");			if (ncr_ustart(ncr, slot) == FALSE)				continue;			/*			 * Okay, now we're 'running' this command.

⌨️ 快捷键说明

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