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

📄 kdb.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			return (-1);		}	}	if ((ka->kdb_sa & STEP0MASK) != KDB_STEP1) {		printf("kdb%d: init failed, sa=%b\n", ki->ki_ctlr,			ka->kdb_sa, kdbsr_bits);		return (-1);	}	/*	 * Success!  Record new state, and start step 1 initialisation.	 * The rest is done in the interrupt handler.	 */	ki->ki_state = ST_STEP1;	ka->kdb_bi.bi_intrdes = 1 << mastercpu;#ifdef unneeded /* is it? */	ka->kdb_bi.bi_csr = (ka->kdb_bi.bi_csr&~BICSR_ARB_MASK)|BICSR_ARB_???;#endif	ka->kdb_bi.bi_bcicsr |= BCI_STOPEN | BCI_IDENTEN | BCI_UINTEN |		BCI_INTEN;/* I THINK THIS IS WRONG *//* Mach uses 0x601d0, which includes IPL16, but 1d0 is IPL17, nexzvec...? */	ka->kdb_bi.bi_eintrcsr = BIEIC_IPL15 | ki->ki_vec;	/* ??? *//* END I THINK WRONG */	ka->kdb_bi.bi_uintrcsr = ki->ki_vec;	ka->kdb_sw = KDB_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | KDB_IE |		(ki->ki_vec >> 2);	return (0);}/* * Open a drive. *//*ARGSUSED*/kdbopen(dev, flag)	dev_t dev;	int flag;{	register int unit;	register struct uba_device *ui;	register struct kdbinfo *ki;	int s;	/*	 * Make sure this is a reasonable open request.	 */	unit = kdbunit(dev);	if (unit >= NKRA || (ui = kdbdinfo[unit]) == 0 || ui->ui_alive == 0)		return (ENXIO);	/*	 * Make sure the controller is running, by (re)initialising it if	 * necessary.	 */	ki = &kdbinfo[ui->ui_ctlr];	s = spl5();	if (ki->ki_state != ST_RUN) {		if (ki->ki_state == ST_IDLE && kdbinit(ki)) {			splx(s);			return (EIO);		}		/*		 * In case it does not come up, make sure we will be		 * restarted in 10 seconds.  This corresponds to the		 * 10 second timeouts in kdbprobe() and kdbslave().		 */		ki->ki_flags |= KDB_DOWAKE;		timeout(wakeup, (caddr_t)&ki->ki_flags, 10 * hz);		sleep((caddr_t)&ki->ki_flags, PRIBIO);		if (ki->ki_state != ST_RUN) {			splx(s);			printf("kdb%d: controller hung\n", ui->ui_ctlr);			return (EIO);		}		untimeout(wakeup, (caddr_t)&ki->ki_flags);	}	if ((ui->ui_flags & UNIT_ONLINE) == 0) {		/*		 * Bring the drive on line so we can find out how		 * big it is.  If it is not spun up, it will not		 * come on line; this cannot really be considered		 * an `error condition'.		 */		if (kdb_bringonline(ui, 0)) {			splx(s);			printf("%s%d: drive will not come on line\n",				kdbdriver.ud_dname, unit);			return (EIO);		}	}	splx(s);	return (0);}/* * Bring a drive on line.  In case it fails to respond, we set * a timeout on it.  The `nosleep' parameter should be set if * we are to spin-wait; otherwise this must be called at spl5(). */kdb_bringonline(ui, nosleep)	register struct uba_device *ui;	int nosleep;{	register struct kdbinfo *ki = &kdbinfo[ui->ui_ctlr];	register struct mscp *mp;	int i;	if (nosleep) {		mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT);		if (mp == NULL)			return (-1);	} else		mp = mscp_getcp(&ki->ki_mi, MSCP_WAIT);	mp->mscp_opcode = M_OP_ONLINE;	mp->mscp_unit = ui->ui_slave;	mp->mscp_cmdref = (long)&ui->ui_flags;	*mp->mscp_addr |= MSCP_OWN | MSCP_INT;	i = ki->ki_kdb->kdb_ip;	if (nosleep) {		i = todr() + 1000;		while ((ui->ui_flags & UNIT_ONLINE) == 0)			if (todr() > i)				return (-1);	} else {		timeout(wakeup, (caddr_t)&ui->ui_flags, 10 * hz);		sleep((caddr_t)&ui->ui_flags, PRIBIO);		if ((ui->ui_flags & UNIT_ONLINE) == 0)			return (-1);		untimeout(wakeup, (caddr_t)&ui->ui_flags);	}	return (0);	/* made it */}/* * Queue a transfer request, and if possible, hand it to the controller. * * This routine is broken into two so that the internal version * kdbstrat1() can be called by the (nonexistent, as yet) bad block * revectoring routine. */kdbstrategy(bp)	register struct buf *bp;{	register int unit;	register struct uba_device *ui;	register struct size *st;	daddr_t sz, maxsz;	/*	 * Make sure this is a reasonable drive to use.	 */	if ((unit = kdbunit(bp->b_dev)) >= NKRA ||	    (ui = kdbdinfo[unit]) == NULL || ui->ui_alive == 0) {		bp->b_error = ENXIO;		bp->b_flags |= B_ERROR;		biodone(bp);		return;	}	/*	 * Determine the size of the transfer, and make sure it is	 * within the boundaries of the drive.	 */	sz = (bp->b_bcount + 511) >> 9;	st = &kdbtypes[ui->ui_type].ut_sizes[kdbpart(bp->b_dev)];	if ((maxsz = st->nblocks) < 0)		maxsz = ra_dsize[unit] - st->blkoff;	if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz ||	    st->blkoff >= ra_dsize[unit]) {		/* if exactly at end of disk, return an EOF */		if (bp->b_blkno == maxsz)			bp->b_resid = bp->b_bcount;		else {			bp->b_error = EINVAL;			bp->b_flags |= B_ERROR;		}		biodone(bp);		return;	}	kdbstrat1(bp);}/* * Work routine for kdbstrategy. */kdbstrat1(bp)	register struct buf *bp;{	register int unit = kdbunit(bp->b_dev);	register struct buf *dp;	register struct kdbinfo *ki;	struct uba_device *ui;	int s;	/*	 * Append the buffer to the drive queue, and if it is not	 * already there, the drive to the controller queue.  (However,	 * if the drive queue is marked to be requeued, we must be	 * awaiting an on line or get unit status command; in this	 * case, leave it off the controller queue.)	 */	ui = kdbdinfo[unit];	ki = &kdbinfo[ui->ui_ctlr];	dp = &kdbutab[unit];	s = spl5();	APPEND(bp, dp, av_forw);	if (dp->b_active == 0 && (ui->ui_flags & UNIT_REQUEUE) == 0) {		APPEND(dp, &ki->ki_tab, b_forw);		dp->b_active++;	}	/*	 * Start activity on the controller.	 */	kdbstart(ki);	splx(s);}/* * Find the physical address of some contiguous PTEs that map the * transfer described in `bp', creating them (by copying) if * necessary.  Store the physical base address of the map through * mapbase, and the page offset through offset, and any resource * information in *info (or 0 if none). * * If we cannot allocate space, return a nonzero status. */intkdbmap(ki, bp, mapbase, offset, info)	struct kdbinfo *ki;	register struct buf *bp;	long *mapbase, *offset;	int *info;{	register struct pte *spte, *dpte;	register struct proc *rp;	register int i, a, o;	u_int v;	int npf;	o = (int)bp->b_un.b_addr & PGOFSET;	/* handle contiguous cases */	if ((bp->b_flags & B_PHYS) == 0) {		spte = kvtopte(bp->b_un.b_addr);		kdbstats.ks_sys++;		*mapbase = PHYS(long, spte);		*offset = o;		*info = 0;		return (0);	}	if (bp->b_flags & B_PAGET) {		spte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];if (spte->pg_v == 0) panic("kdbmap");		kdbstats.ks_paget++;		*mapbase = PHYS(long, spte);		*offset = o;		*info = 0;		return (0);	}	/* potentially discontiguous or invalid ptes */	v = btop(bp->b_un.b_addr);	rp = bp->b_flags & B_DIRTY ? &proc[2] : bp->b_proc;	if (bp->b_flags & B_UAREA)		spte = &rp->p_addr[v];	else		spte = vtopte(rp, v);	npf = btoc(bp->b_bcount + o);#ifdef notdef	/*	 * The current implementation of the VM system requires	 * that all of these be done with a copy.  Even if the	 * PTEs could be used now, they may be snatched out from	 * under us later.  It would be nice if we could stop that....	 */	/* check for invalid */	/* CONSIDER CHANGING VM TO VALIDATE PAGES EARLIER */	for (dpte = spte, i = npf; --i >= 0; dpte++)		if (dpte->pg_v == 0)			goto copy1;	/*	 * Check for discontiguous physical pte addresses.  It is	 * not necessary to check each pte, since they come in clumps	 * of pages.	 */	i = howmany(npf + (((int)spte & PGOFSET) / sizeof (*spte)), NPTEPG);	/* often i==1, and we can avoid work */	if (--i > 0) {		dpte = kvtopte(spte);		a = dpte->pg_pfnum;		while (--i >= 0)			if ((++dpte)->pg_pfnum != ++a)				goto copy2;	}	/* made it */	kdbstats.ks_contig++;	*mapbase = kvtophys(spte);	*offset = o;	*info = 0;	return (0);copy1:	kdbstats.ks_inval++;		/* temp */copy2:#endif /* notdef */	kdbstats.ks_copies++;	i = npf + 1;	if ((a = rmalloc(ki->ki_map, (long)i)) == 0) {		kdbstats.ks_mapwait++;		return (-1);	}	*info = (i << 16) | a;	a--;	/* if offset > PGOFSET, btop(offset) indexes mapbase */	*mapbase = ki->ki_ptephys;	*offset = (a << PGSHIFT) | o;	dpte = &ki->ki_pte[a];	while (--i > 0)		*(int *)dpte++ = PG_V | *(int *)spte++;	*(int *)dpte = 0;	return (0);}#define	KDBFREE(ki, info) if (info) \	rmfree((ki)->ki_map, (long)((info) >> 16), (long)((info) & 0xffff))/* * Start up whatever transfers we can find. * Note that kdbstart() must be called at spl5(). */kdbstart(ki)	register struct kdbinfo *ki;{	register struct buf *bp, *dp;	register struct mscp *mp;	register struct uba_device *ui;	long mapbase, offset;	int info, ncmd = 0;	/*	 * If it is not running, try (again and again...) to initialise	 * it.  If it is currently initialising just ignore it for now.	 */	if (ki->ki_state != ST_RUN) {		if (ki->ki_state == ST_IDLE && kdbinit(ki))			printf("kdb%d: still hung\n", ki->ki_ctlr);		return;	}loop:	/* if insufficient credit, avoid overhead */	if (ki->ki_mi.mi_credits <= MSCP_MINCREDITS)		goto out;	/*	 * Service the drive at the head of the queue.  It may not	 * need anything; eventually this will finish up the close	 * protocol, but that is yet to be implemented here.	 */	if ((dp = ki->ki_tab.b_actf) == NULL)		goto out;	if ((bp = dp->b_actf) == NULL) {		dp->b_active = 0;		ki->ki_tab.b_actf = dp->b_forw;		goto loop;	}	if (ki->ki_kdb->kdb_sa & KDB_ERR) {	/* ctlr fatal error */		kdbsaerror(ki);		goto out;	}	 /* find or create maps for this transfer */	 if (kdbmap(ki, bp, &mapbase, &offset, &info))		goto out;	/* effectively, resource wait */	/*	 * Get an MSCP packet, then figure out what to do.  If	 * we cannot get a command packet, the command ring may	 * be too small:  We should have at least as many command	 * packets as credits, for best performance.	 */	if ((mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT)) == NULL) {		if (ki->ki_mi.mi_credits > MSCP_MINCREDITS &&		    (ki->ki_flags & KDB_GRIPED) == 0) {			log(LOG_NOTICE, "kdb%d: command ring too small\n",				ki->ki_ctlr);			ki->ki_flags |= KDB_GRIPED;/* complain only once */		}		KDBFREE(ki, info);		goto out;	}	/*	 * Bring the drive on line if it is not already.  Get its status	 * if we do not already have it.  Otherwise just start the transfer.	 */	ui = kdbdinfo[kdbunit(bp->b_dev)];	if ((ui->ui_flags & UNIT_ONLINE) == 0) {		mp->mscp_opcode = M_OP_ONLINE;		goto common;	}	if ((ui->ui_flags & UNIT_HAVESTATUS) == 0) {		mp->mscp_opcode = M_OP_GETUNITST;common:if (ui->ui_flags & UNIT_REQUEUE) panic("kdbstart");		/*		 * Take the drive off the controller queue.  When the		 * command finishes, make sure the drive is requeued.		 * Give up any mapping (not needed now).  This last is		 * not efficient, but is rare.		 */		KDBFREE(ki, info);		ki->ki_tab.b_actf = dp->b_forw;		dp->b_active = 0;		ui->ui_flags |= UNIT_REQUEUE;		mp->mscp_unit = ui->ui_slave;		*mp->mscp_addr |= MSCP_OWN | MSCP_INT;		ncmd++;		goto loop;	}	mp->mscp_opcode = (bp->b_flags & B_READ) ? M_OP_READ : M_OP_WRITE;	mp->mscp_unit = ui->ui_slave;	mp->mscp_seq.seq_lbn = bp->b_blkno +		kdbtypes[ui->ui_type].ut_sizes[kdbpart(bp->b_dev)].blkoff;	mp->mscp_seq.seq_bytecount = bp->b_bcount;	mp->mscp_seq.seq_buffer = offset | KDB_MAP;	mp->mscp_seq.seq_mapbase = mapbase;	/* profile the drive */	if (ui->ui_dk >= 0) {		dk_busy |= 1 << ui->ui_dk;		dk_xfer[ui->ui_dk]++;		dk_wds[ui->ui_dk] += bp->b_bcount >> 6;	}	/*	 * Fill in the rest of the MSCP packet and move the buffer to the	 * I/O wait queue.	 */	mscp_go(&ki->ki_mi, mp, info);	ncmd++;			/* note the transfer */	ki->ki_tab.b_active++;	/* another one going */	goto loop;out:	if (ncmd >= KS_MAXC)		ncmd = KS_MAXC - 1;	kdbstats.ks_cmd[ncmd]++;	if (ncmd)		/* start some transfers */		ncmd = ki->ki_kdb->kdb_ip;}/* ARGSUSED */kdbiodone(mi, bp, info)	struct mscp_info *mi;	struct buf *bp;	int info;{	register struct kdbinfo *ki = &kdbinfo[mi->mi_ctlr];	KDBFREE(ki, info);	biodone(bp);	ki->ki_tab.b_active--;	/* another one done */}/* * The error bit was set in the controller status register.  Gripe, * reset the controller, requeue pending transfers. */kdbsaerror(ki)	register struct kdbinfo *ki;{	printf("kdb%d: controller error, sa=%b\n", ki->ki_ctlr,		ki->ki_kdb->kdb_sa, kdbsr_bits);	mscp_requeue(&ki->ki_mi);	(void) kdbinit(ki);}/* * Interrupt routine.  Depending on the state of the controller, * continue initialisation, or acknowledge command and response * interrupts, and process responses. */kdbintr(ctlr)	int ctlr;{	register struct kdbinfo *ki = &kdbinfo[ctlr];	register struct kdb_regs *kdbaddr = ki->ki_kdb;	register struct mscp *mp;	register int i;	ki->ki_wticks = 0;	/* reset interrupt watchdog */	/*	 * Combinations during steps 1, 2, and 3: STEPnMASK	 * corresponds to which bits should be tested;	 * STEPnGOOD corresponds to the pattern that should	 * appear after the interrupt from STEPn initialisation.	 * All steps test the bits in ALLSTEPS.	 */#define	ALLSTEPS	(KDB_ERR|KDB_STEP4|KDB_STEP3|KDB_STEP2|KDB_STEP1)#define	STEP1MASK	(ALLSTEPS | KDB_IE | KDB_NCNRMASK)#define	STEP1GOOD	(KDB_STEP2 | KDB_IE | (NCMDL2 << 3) | NRSPL2)#define	STEP2MASK	(ALLSTEPS | KDB_IE | KDB_IVECMASK)#define	STEP2GOOD	(KDB_STEP3 | KDB_IE | (ki->ki_vec >> 2))#define	STEP3MASK	ALLSTEPS#define	STEP3GOOD	KDB_STEP4	switch (ki->ki_state) {	case ST_IDLE:		/*		 * Ignore unsolicited interrupts.		 */		log(LOG_WARNING, "kdb%d: stray intr\n", ctlr);		return;	case ST_STEP1:		/*		 * Begin step two initialisation.		 */		if ((kdbaddr->kdb_sa & STEP1MASK) != STEP1GOOD) {			i = 1;initfailed:			printf("kdb%d: init step %d failed, sa=%b\n",				ctlr, i, kdbaddr->kdb_sa, kdbsr_bits);			ki->ki_state = ST_IDLE;			if (ki->ki_flags & KDB_DOWAKE) {				ki->ki_flags &= ~KDB_DOWAKE;				wakeup((caddr_t)&ki->ki_flags);			}			return;		}		kdbaddr->kdb_sw = PHYS(int, &ki->ki_ca.ca_rspdsc[0]);		ki->ki_state = ST_STEP2;		return;	case ST_STEP2:		/*		 * Begin step 3 initialisation.		 */		if ((kdbaddr->kdb_sa & STEP2MASK) != STEP2GOOD) {			i = 2;			goto initfailed;		}		kdbaddr->kdb_sw = PHYS(int, &ki->ki_ca.ca_rspdsc[0]) >> 16;		ki->ki_state = ST_STEP3;		return;	case ST_STEP3:		/*		 * Set controller characteristics (finish initialisation).		 */		if ((kdbaddr->kdb_sa & STEP3MASK) != STEP3GOOD) {			i = 3;			goto initfailed;		}		i = kdbaddr->kdb_sa & 0xff;		if (i != ki->ki_micro) {			ki->ki_micro = i;			printf("kdb%d: version %d model %d\n",				ctlr, i & 0xf, i >> 4);		}		kdbaddr->kdb_sw = KDB_GO;		/* initialise hardware data structures */		for (i = 0, mp = ki->ki_rsp; i < NRSP; i++, mp++) {			ki->ki_ca.ca_rspdsc[i] = MSCP_OWN | MSCP_INT |				PHYS(long, &ki->ki_rsp[i].mscp_cmdref);

⌨️ 快捷键说明

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