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

📄 kdb.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
			mp->mscp_addr = &ki->ki_ca.ca_rspdsc[i];			mp->mscp_msglen = MSCP_MSGLEN;		}		for (i = 0, mp = ki->ki_cmd; i < NCMD; i++, mp++) {			ki->ki_ca.ca_cmddsc[i] = MSCP_INT |				PHYS(long, &ki->ki_cmd[i].mscp_cmdref);			mp->mscp_addr = &ki->ki_ca.ca_cmddsc[i];			mp->mscp_msglen = MSCP_MSGLEN;		}		/*		 * Before we can get a command packet, we need some		 * credits.  Fake some up to keep mscp_getcp() happy,		 * get a packet, and cancel all credits (the right		 * number should come back in the response to the		 * SCC packet).		 */		ki->ki_mi.mi_credits = MSCP_MINCREDITS + 1;		mp = mscp_getcp(&ki->ki_mi, MSCP_DONTWAIT);		if (mp == NULL)	/* `cannot happen' */			panic("kdbintr");		ki->ki_mi.mi_credits = 0;		mp->mscp_opcode = M_OP_SETCTLRC;		mp->mscp_unit = 0;		mp->mscp_sccc.sccc_ctlrflags = M_CF_ATTN | M_CF_MISC |			M_CF_THIS;		*mp->mscp_addr |= MSCP_OWN | MSCP_INT;		i = kdbaddr->kdb_ip;		ki->ki_state = ST_SETCHAR;		return;	case ST_SETCHAR:	case ST_RUN:		/*		 * Handle Set Ctlr Characteristics responses and operational		 * responses (via mscp_dorsp).		 */		break;	default:		log(LOG_ERR, "kdb%d: driver bug, state %d\n", ctlr,			ki->ki_state);		return;	}	if (kdbaddr->kdb_sa & KDB_ERR) {/* ctlr fatal error */		kdbsaerror(ki);		return;	}	/*	 * Handle buffer purge requests.	 * KDB DOES NOT HAVE BDPs	 */	if (ki->ki_ca.ca_bdp) {		printf("kdb%d: purge bdp %d\n", ctlr, ki->ki_ca.ca_bdp);		panic("kdb purge");	}	/*	 * Check for response and command ring transitions.	 */	if (ki->ki_ca.ca_rspint) {		ki->ki_ca.ca_rspint = 0;		mscp_dorsp(&ki->ki_mi);	}	if (ki->ki_ca.ca_cmdint) {		ki->ki_ca.ca_cmdint = 0;		MSCP_DOCMD(&ki->ki_mi);	}	if (ki->ki_tab.b_actf != NULL)		kdbstart(ki);}/* * Handle an error datagram.  All we do now is decode it. */kdbdgram(mi, mp)	struct mscp_info *mi;	struct mscp *mp;{	mscp_decodeerror(mi->mi_md->md_mname, mi->mi_ctlr, mp);}/* * The Set Controller Characteristics command finished. * Record the new state of the controller. */kdbctlrdone(mi, mp)	struct mscp_info *mi;	struct mscp *mp;{	register struct kdbinfo *ki = &kdbinfo[mi->mi_ctlr];	if ((mp->mscp_status & M_ST_MASK) == M_ST_SUCCESS)		ki->ki_state = ST_RUN;	else {		printf("kdb%d: SETCTLRC failed, status 0x%x\n",			ki->ki_ctlr, mp->mscp_status);		ki->ki_state = ST_IDLE;	}	if (ki->ki_flags & KDB_DOWAKE) {		ki->ki_flags &= ~KDB_DOWAKE;		wakeup((caddr_t)&ki->ki_flags);	}}/* * Received a response from an as-yet unconfigured drive.  Configure it * in, if possible. */kdbunconf(mi, mp)	struct mscp_info *mi;	register struct mscp *mp;{	/*	 * If it is a slave response, copy it to kdbslavereply for	 * kdbslave() to look at.	 */	if (mp->mscp_opcode == (M_OP_GETUNITST | M_OP_END) &&	    (kdbinfo[mi->mi_ctlr].ki_flags & KDB_INSLAVE) != 0) {		kdbslavereply = *mp;		return (MSCP_DONE);	}	/*	 * Otherwise, it had better be an available attention response.	 */	if (mp->mscp_opcode != M_OP_AVAILATTN)		return (MSCP_FAILED);	/* do what autoconf does */	return (MSCP_FAILED);	/* not yet */}/* * A drive came on line.  Check its type and size.  Return DONE if * we think the drive is truly on line.  In any case, awaken anyone * sleeping on the drive on-line-ness. */kdbonline(ui, mp)	register struct uba_device *ui;	struct mscp *mp;{	register int type;	wakeup((caddr_t)&ui->ui_flags);	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {		printf("kdb%d: attempt to bring %s%d on line failed:",			ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit);		mscp_printevent(mp);		return (MSCP_FAILED);	}	type = mp->mscp_onle.onle_drivetype;	if (type >= NTYPES || kdbtypes[type].ut_name == 0) {		printf("kdb%d: %s%d: unknown type %d\n",			ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit, type);		return (MSCP_FAILED);	}	/*	 * Note any change of types.  Not sure if we should do	 * something special about them, or if so, what....	 */	if (type != ui->ui_type) {		printf("%s%d: changed types! was %s\n",			kdbdriver.ud_dname, ui->ui_unit,			kdbtypes[ui->ui_type].ut_name);		ui->ui_type = type;	}	ra_dsize[ui->ui_unit] = (daddr_t) mp->mscp_onle.onle_unitsize;	printf("%s%d: %s, size = %d sectors\n",		kdbdriver.ud_dname, ui->ui_unit,		kdbtypes[type].ut_name, ra_dsize[ui->ui_unit]);	return (MSCP_DONE);}/* * We got some (configured) unit's status.  Return DONE if it succeeded. */kdbgotstatus(ui, mp)	register struct uba_device *ui;	register struct mscp *mp;{	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {		printf("kdb%d: attempt to get status for %s%d failed:",			ui->ui_ctlr, kdbdriver.ud_dname, ui->ui_unit);		mscp_printevent(mp);		return (MSCP_FAILED);	}	/* need to record later for bad block forwarding - for now, print */	printf("\%s%d: unit %d, nspt %d, group %d, ngpc %d, rctsize %d, nrpt %d, nrct %d\n",		kdbdriver.ud_dname, ui->ui_unit, mp->mscp_unit,		mp->mscp_guse.guse_nspt, mp->mscp_guse.guse_group,		mp->mscp_guse.guse_ngpc, mp->mscp_guse.guse_rctsize,		mp->mscp_guse.guse_nrpt, mp->mscp_guse.guse_nrct);	return (MSCP_DONE);}/* * A transfer failed.  We get a chance to fix or restart it. * Need to write the bad block forwaring code first.... *//*ARGSUSED*/kdbioerror(ui, mp, bp)	register struct uba_device *ui;	register struct mscp *mp;	struct buf *bp;{	if (mp->mscp_flags & M_EF_BBLKR) {		/*		 * A bad block report.  Eventually we will		 * restart this transfer, but for now, just		 * log it and give up.		 */		log(LOG_ERR, "%s%d: bad block report: %d%s\n",			kdbdriver.ud_dname, ui->ui_unit, mp->mscp_seq.seq_lbn,			mp->mscp_flags & M_EF_BBLKU ? " + others" : "");	} else {		/*		 * What the heck IS a `serious exception' anyway?		 */		if (mp->mscp_flags & M_EF_SEREX)			log(LOG_ERR, "%s%d: serious exception reported\n",				kdbdriver.ud_dname, ui->ui_unit);	}	return (MSCP_FAILED);}#ifdef notyet/* * I/O controls.  Not yet! */kdbioctl(dev, cmd, flag, data)	dev_t dev;	int cmd, flag;	caddr_t data;{	int error = 0;	register int unit = kdbunit(dev);	if (unit >= NKRA || uddinfo[unit] == NULL)		return (ENXIO);	switch (cmd) {	case KDBIOCREPLACE:		/*		 * Initiate bad block replacement for the given LBN.		 * (Should we allow modifiers?)		 */		error = EOPNOTSUPP;		break;	case KDBIOCGMICRO:		/*		 * Return the microcode revision for the KDB50 running		 * this drive.		 */		*(int *)data = kdbinfo[kdbdinfo[unit]->ui_ctlr].ki_micro;		break;	case KDBIOCGSIZE:		/*		 * Return the size (in 512 byte blocks) of this		 * disk drive.		 */		*(daddr_t *)data = ra_dsize[unit];		break;	default:		error = EINVAL;		break;	}	return (error);}#endif#ifdef notyet/* * Reset a KDB50 (self test and all). * What if it fails? */kdbreset(ki)	register struct kdbinfo *ki;{	printf("reset kdb%d", ki->ki_ctlr);	bi_selftest(&ki->ki_kdb.kdb_bi);	ki->ki_state = ST_IDLE;	rminit(ki->ki_map, (long)KI_PTES, (long)1, "kdb", KI_MAPSIZ);	mscp_requeue(&ki->ki_mi);	if (kdbinit(ctlr))		printf(" (hung)");	printf("\n");}#endif/* * Watchdog timer:  If the controller is active, and no interrupts * have occurred for 30 seconds, assume it has gone away. */kdbwatch(){	register struct kdbinfo *ki;	register int i;	timeout(kdbwatch, (caddr_t)0, hz);	/* every second */	for (i = 0, ki = kdbinfo; i < NKDB; i++, ki++) {		if ((ki->ki_flags & KDB_ALIVE) == 0)			continue;		if (ki->ki_state == ST_IDLE)			continue;		if (ki->ki_state == ST_RUN && !ki->ki_tab.b_active)			ki->ki_wticks = 0;		else if (++ki->ki_wticks >= 30) {			ki->ki_wticks = 0;			printf("kdb%d: lost interrupt\n", i);			/* kdbreset(ki); */			panic("kdb lost interrupt");		}	}}/* * Do a panic dump. */#define	DBSIZE	32		/* dump 16K at a time */struct kdbdumpspace {	struct	kdb1ca kd_ca;	struct	mscp kd_rsp;	struct	mscp kd_cmd;} kdbdumpspace;kdbdump(dev)	dev_t dev;{	register struct kdbdumpspace *kd;	register struct kdb_regs *k;	register int i;	struct uba_device *ui;	char *start;	int num, blk, unit, maxsz, blkoff;	/*	 * Make sure the device is a reasonable place on which to dump.	 */	unit = kdbunit(dev);	if (unit >= NKRA)		return (ENXIO);	ui = PHYS(struct uba_device *, kdbdinfo[unit]);	if (ui == NULL || ui->ui_alive == 0)		return (ENXIO);	/*	 * Find and initialise the KDB; get the physical address of the	 * device registers, and of communications area and command and	 * response packet.	 */	k = PHYS(struct kdbinfo *, &kdbinfo[ui->ui_ctlr])->ki_physkdb;	kd = PHYS(struct kdbdumpspace *, &kdbdumpspace);	/*	 * Initialise the controller, with one command and one response	 * packet.	 */	bi_reset(&k->kdb_bi);	if (kdbdumpwait(k, KDB_STEP1))		return (EFAULT);	k->kdb_sw = KDB_ERR;	if (kdbdumpwait(k, KDB_STEP2))		return (EFAULT);	k->kdb_sw = (int)&kd->kd_ca.ca_rspdsc;	if (kdbdumpwait(k, KDB_STEP3))		return (EFAULT);	k->kdb_sw = ((int)&kd->kd_ca.ca_rspdsc) >> 16;	if (kdbdumpwait(k, KDB_STEP4))		return (EFAULT);	k->kdb_sw = KDB_GO;	/*	 * Set up the command and response descriptor, then set the	 * controller characteristics and bring the drive on line.	 * Note that all uninitialised locations in kd_cmd are zero.	 */	kd->kd_ca.ca_rspdsc = (long)&kd->kd_rsp.mscp_cmdref;	kd->kd_ca.ca_cmddsc = (long)&kd->kd_cmd.mscp_cmdref;	/* kd->kd_cmd.mscp_sccc.sccc_ctlrflags = 0; */	/* kd->kd_cmd.mscp_sccc.sccc_version = 0; */	if (kdbdumpcmd(M_OP_SETCTLRC, k, kd, ui->ui_ctlr))		return (EFAULT);	kd->kd_cmd.mscp_unit = ui->ui_slave;	if (kdbdumpcmd(M_OP_ONLINE, k, kd, ui->ui_ctlr))		return (EFAULT);	/*	 * Pick up the drive type from the on line end packet;	 * convert that to a dump area size and a disk offset.	 * Note that the assembler uses pc-relative addressing	 * to get at kdbtypes[], no need for PHYS().	 */	i = kd->kd_rsp.mscp_onle.onle_drivetype;	if (i >= NTYPES || kdbtypes[i].ut_name == 0) {		printf("disk type %d unknown\ndump ");		return (EINVAL);	}	printf("on %s ", kdbtypes[i].ut_name);	maxsz = kdbtypes[i].ut_sizes[kdbpart(dev)].nblocks;	blkoff = kdbtypes[i].ut_sizes[kdbpart(dev)].blkoff;	/*	 * Dump all of physical memory, or as much as will fit in the	 * space provided.	 */	start = 0;	num = maxfree;	if (dumplo < 0)		return (EINVAL);	if (dumplo + num >= maxsz)		num = maxsz - dumplo;	blkoff += dumplo;	/*	 * Write out memory, DBSIZE pages at a time.	 * N.B.: this code depends on the fact that the sector	 * size == the page size.	 */	while (num > 0) {		blk = num > DBSIZE ? DBSIZE : num;		kd->kd_cmd.mscp_unit = ui->ui_slave;		kd->kd_cmd.mscp_seq.seq_lbn = btop(start) + blkoff;		kd->kd_cmd.mscp_seq.seq_bytecount = blk << PGSHIFT;		kd->kd_cmd.mscp_seq.seq_buffer = (long)start | KDB_PHYS;		if (kdbdumpcmd(M_OP_WRITE, k, kd, ui->ui_ctlr))			return (EIO);		start += blk << PGSHIFT;		num -= blk;	}	return (0);		/* made it! */}/* * Wait for some of the bits in `bits' to come on.  If the error bit * comes on, or ten seconds pass without response, return true (error). */kdbdumpwait(k, bits)	register struct kdb_regs *k;	register int bits;{	register int timo = todr() + 1000;	while ((k->kdb_sa & bits) == 0) {		if (k->kdb_sa & KDB_ERR) {			printf("kdb_sa=%b\ndump ", k->kdb_sa, kdbsr_bits);			return (1);		}		if (todr() >= timo) {			printf("timeout\ndump ");			return (1);		}	}	return (0);}/* * Feed a command to the KDB50, wait for its response, and return * true iff something went wrong. */kdbdumpcmd(op, k, kd, ctlr)	int op;	register struct kdb_regs *k;	register struct kdbdumpspace *kd;	int ctlr;{	register int n;#define mp (&kd->kd_rsp)	kd->kd_cmd.mscp_opcode = op;	kd->kd_cmd.mscp_msglen = MSCP_MSGLEN;	kd->kd_rsp.mscp_msglen = MSCP_MSGLEN;	kd->kd_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT;	kd->kd_ca.ca_cmddsc |= MSCP_OWN | MSCP_INT;	if (k->kdb_sa & KDB_ERR) {		printf("kdb_sa=%b\ndump ", k->kdb_sa, kdbsr_bits);		return (1);	}	n = k->kdb_ip;	n = todr() + 1000;	for (;;) {		if (todr() > n) {			printf("timeout\ndump ");			return (1);		}		if (kd->kd_ca.ca_cmdint)			kd->kd_ca.ca_cmdint = 0;		if (kd->kd_ca.ca_rspint == 0)			continue;		kd->kd_ca.ca_rspint = 0;		if (mp->mscp_opcode == (op | M_OP_END))			break;		printf("\n");		switch (MSCP_MSGTYPE(mp->mscp_msgtc)) {		case MSCPT_SEQ:			printf("sequential");			break;		case MSCPT_DATAGRAM:			mscp_decodeerror("kdb", ctlr, mp);			printf("datagram");			break;		case MSCPT_CREDITS:			printf("credits");			break;		case MSCPT_MAINTENANCE:			printf("maintenance");			break;		default:			printf("unknown (type 0x%x)",				MSCP_MSGTYPE(mp->mscp_msgtc));			break;		}		printf(" ignored\ndump ");		kd->kd_ca.ca_rspdsc |= MSCP_OWN | MSCP_INT;	}	if ((mp->mscp_status & M_ST_MASK) != M_ST_SUCCESS) {		printf("error: op 0x%x => 0x%x status 0x%x\ndump ", op,			mp->mscp_opcode, mp->mscp_status);		return (1);	}	return (0);#undef mp}/* * Return the size of a partition, if known, or -1 if not. */kdbsize(dev)	dev_t dev;{	register int unit = kdbunit(dev);	register struct uba_device *ui;	register struct size *st;	if (unit >= NKRA || (ui = kdbdinfo[unit]) == NULL || ui->ui_alive == 0)		return (-1);	st = &kdbtypes[ui->ui_type].ut_sizes[kdbpart(dev)];	if (st->nblocks == -1) {		int s = spl5();		/*		 * We need to have the drive on line to find the size		 * of this particular partition.		 * IS IT OKAY TO GO TO SLEEP IN THIS ROUTINE?		 * (If not, better not page on one of these...)		 */		if ((ui->ui_flags & UNIT_ONLINE) == 0) {			if (kdb_bringonline(ui, 0)) {				splx(s);				return (-1);			}		}		splx(s);		if (st->blkoff > ra_dsize[unit])			return (-1);		return (ra_dsize[unit] - st->blkoff);	}	return (st->nblocks);}#endif NKDB > 0

⌨️ 快捷键说明

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