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

📄 wdc.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 3 页
字号:
	ctrl_flags = chp->wdc->sc_dev.dv_cfdata->cf_flags;	channel_flags = (ctrl_flags >> (NBBY * chp->channel)) & 0xff;	WDCDEBUG_PRINT(("wdcattach: ch_drive_flags 0x%x 0x%x\n",	    chp->ch_drive[0].drive_flags, chp->ch_drive[1].drive_flags),	    DEBUG_PROBE);	/* If no drives, abort here */	if ((chp->ch_drive[0].drive_flags & DRIVE) == 0 &&	    (chp->ch_drive[1].drive_flags & DRIVE) == 0)		return;	/*	 * Attach an ATAPI bus, if needed.	 */	if ((chp->ch_drive[0].drive_flags & DRIVE_ATAPI) ||	    (chp->ch_drive[1].drive_flags & DRIVE_ATAPI)) {#if NATAPISCSI > 0		wdc_atapibus_attach(chp);#else		/*		 * Fills in a fake aa_link and call config_found, so that		 * the config machinery will print		 * "atapibus at xxx not configured"		 */		bzero(&aa_link, sizeof(struct ata_atapi_attach));		aa_link.aa_type = T_ATAPI;		aa_link.aa_channel = chp->channel;		aa_link.aa_openings = 1;		aa_link.aa_drv_data = 0;		aa_link.aa_bus_private = NULL;		(void)config_found(&chp->wdc->sc_dev, (void *)&aa_link,		    atapi_print);#endif	}	for (i = 0; i < 2; i++) {		if ((chp->ch_drive[i].drive_flags &		    (DRIVE_ATA | DRIVE_OLD)) == 0) {			continue;		}		bzero(&aa_link, sizeof(struct ata_atapi_attach));		aa_link.aa_type = T_ATA;		aa_link.aa_channel = chp->channel;		aa_link.aa_openings = 1;		aa_link.aa_drv_data = &chp->ch_drive[i];		config_found(&chp->wdc->sc_dev, (void *)&aa_link, wdprint);	}	/*	 * reset drive_flags for unnatached devices, reset state for attached	 *  ones	 */	for (i = 0; i < 2; i++) {		if (chp->ch_drive[i].drive_name[0] == 0)			chp->ch_drive[i].drive_flags = 0;		else			chp->ch_drive[i].state = 0;	}	/*	 * Reset channel. The probe, with some combinations of ATA/ATAPI	 * devices keep it in a mostly working, but strange state (with busy	 * led on)	 */	if ((chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {		wdcreset(chp, VERBOSE);		/*		 * Read status registers to avoid spurious interrupts.		 */		for (i = 1; i >= 0; i--) {			if (chp->ch_drive[i].drive_flags & DRIVE) {				CHP_WRITE_REG(chp,				    wdr_sdh, WDSD_IBM | (i << 4));				if (wait_for_unbusy(chp, 10000) < 0)					printf("%s:%d:%d: device busy\n",					    chp->wdc->sc_dev.dv_xname,					    chp->channel, i);			}		}	}#ifndef __OpenBSD__	wdc_delref(chp);#endif}/* * Start I/O on a controller, for the given channel. * The first xfer may be not for our channel if the channel queues * are shared. */voidwdcstart(chp)	struct channel_softc *chp;{	struct wdc_xfer *xfer;#ifdef WDC_DIAGNOSTIC	int spl1, spl2;	spl1 = splbio();	spl2 = splbio();	if (spl2 != spl1) {		printf("wdcstart: not at splbio()\n");		panic("wdcstart");	}	splx(spl2);	splx(spl1);#endif /* WDC_DIAGNOSTIC */	/* is there a xfer ? */	if ((xfer = chp->ch_queue->sc_xfer.tqh_first) == NULL) {		return;	}	/* adjust chp, in case we have a shared queue */	chp = xfer->chp;	if ((chp->ch_flags & WDCF_ACTIVE) != 0 ) {		return; /* channel already active */	}#ifdef DIAGNOSTIC	if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0)		panic("wdcstart: channel waiting for irq\n");#endif	if (chp->wdc->cap & WDC_CAPABILITY_HWLOCK)		if (!(chp->wdc->claim_hw)(chp, 0))			return;	WDCDEBUG_PRINT(("wdcstart: xfer %p channel %d drive %d\n", xfer,	    chp->channel, xfer->drive), DEBUG_XFERS);	chp->ch_flags |= WDCF_ACTIVE;	if (chp->ch_drive[xfer->drive].drive_flags & DRIVE_RESET) {		chp->ch_drive[xfer->drive].drive_flags &= ~DRIVE_RESET;		chp->ch_drive[xfer->drive].state = 0;	}	xfer->c_start(chp, xfer);}#ifndef PMONintwdcdetach(chp, flags)	struct channel_softc *chp;	int flags;{	int s, rv;	s = splbio();	wdc_kill_pending(chp);	rv = config_detach_children((struct device *)chp->wdc, flags);	splx(s);	return (rv);}#endif/* restart an interrupted I/O */voidwdcrestart(v)	void *v;{	struct channel_softc *chp = v;	int s;	s = splbio();	wdcstart(chp);	splx(s);}	/* * Interrupt routine for the controller.  Acknowledge the interrupt, check for * errors on the current operation, mark it done if necessary, and start the * next request.  Also check for a partially done transfer, and continue with * the next chunk if so. */intwdcintr(arg)	void *arg;{#ifndef PMON	struct channel_softc *chp = arg;	struct wdc_xfer *xfer;	int ret;	if ((chp->ch_flags & WDCF_IRQ_WAIT) == 0) {		WDCDEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR);		return 0;	}	WDCDEBUG_PRINT(("wdcintr\n"), DEBUG_INTR);	untimeout(wdctimeout, chp);	chp->ch_flags &= ~WDCF_IRQ_WAIT;	xfer = chp->ch_queue->sc_xfer.tqh_first;        ret = xfer->c_intr(chp, xfer, 1);#if notyet	if (ret == 0)		chp->ch_flags |= WDCF_IRQ_WAIT;#endif	return (ret);#else	return 0;#endif}/* Put all disk in RESET state */void wdc_reset_channel(drvp)	struct ata_drive_datas *drvp;{	struct channel_softc *chp = drvp->chnl_softc;	int drive;	WDCDEBUG_PRINT(("ata_reset_channel %s:%d for drive %d\n",	    chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),	    DEBUG_FUNCS);	(void) wdcreset(chp, VERBOSE);	for (drive = 0; drive < 2; drive++) {		chp->ch_drive[drive].state = 0;	}}intwdcreset(chp, verb)	struct channel_softc *chp;	int verb;{	int drv_mask1, drv_mask2;	if (!chp->_vtbl)		chp->_vtbl = &wdc_default_vtbl;	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_RST | WDCTL_IDS);	delay(1000);	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_IDS);	delay(2000);	(void) CHP_READ_REG(chp,wdr_error);	CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_4BIT);	drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;	drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;	drv_mask2 = __wdcwait_reset(chp, drv_mask1);	if (verb && drv_mask2 != drv_mask1) {		printf("%s channel %d: reset failed for",		    chp->wdc->sc_dev.dv_xname, chp->channel);		if ((drv_mask1 & 0x01) != 0 && (drv_mask2 & 0x01) == 0)			printf(" drive 0");		if ((drv_mask1 & 0x02) != 0 && (drv_mask2 & 0x02) == 0)			printf(" drive 1");		printf("\n");	}	return  (drv_mask1 != drv_mask2) ? 1 : 0;}static int__wdcwait_reset(chp, drv_mask)	struct channel_softc *chp;	int drv_mask;{	int timeout;	u_int8_t st0, st1;	/* Wait 50ms for drive firmware to settle */	delay(50000);	/* wait for BSY to deassert */	for (timeout = 0; timeout < WDCNDELAY_RST;timeout++) {		CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */		delay(10);		st0 = CHP_READ_REG(chp, wdr_status);		CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10); /* slave */		delay(10);		st1 = CHP_READ_REG(chp, wdr_status);		if ((drv_mask & 0x01) == 0) {			/* no master */			if ((drv_mask & 0x02) != 0 && (st1 & WDCS_BSY) == 0) {				/* No master, slave is ready, it's done */				goto end;			}		} else if ((drv_mask & 0x02) == 0) {			/* no slave */			if ((drv_mask & 0x01) != 0 && (st0 & WDCS_BSY) == 0) {				/* No slave, master is ready, it's done */				goto end;			}		} else {			/* Wait for both master and slave to be ready */			if ((st0 & WDCS_BSY) == 0 && (st1 & WDCS_BSY) == 0) {				goto end;			}		}		delay(WDCDELAY);	}	/* Reset timed out. Maybe it's because drv_mask was not rigth */	if (st0 & WDCS_BSY)		drv_mask &= ~0x01;	if (st1 & WDCS_BSY)		drv_mask &= ~0x02;end:	WDCDEBUG_PRINT(("%s:%d: wdcwait_reset() end, st0=0x%x, st1=0x%x\n",	    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,	    st0, st1), DEBUG_PROBE);	return drv_mask;}/* * Wait for a drive to be !BSY, and have mask in its status register. * return -1 for a timeout after "timeout" ms. */intwdcwait(chp, mask, bits, timeout)	struct channel_softc *chp;	int mask, bits, timeout;{	u_char status;	int time = 0;#ifndef PMON#ifdef WDCNDELAY_DEBUG	extern int cold;#endif#endif	WDCDEBUG_PRINT(("wdcwait %s:%d\n", chp->wdc ?chp->wdc->sc_dev.dv_xname	    :"none", chp->channel), DEBUG_STATUS);	chp->ch_error = 0;	timeout = timeout * 1000 / WDCDELAY; /* delay uses microseconds */	for (;;) {#ifdef TEST_ALTSTS		chp->ch_status = status = CHP_READ_REG(chp, wdr_altsts);#else		chp->ch_status = status = CHP_READ_REG(chp, wdr_status);#endif		if (status == 0xff && (chp->ch_flags & WDCF_ONESLAVE)) {			CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | 0x10);#ifdef TEST_ALTSTS			chp->ch_status = status = 			    CHP_READ_REG(chp, wdr_altsts);#else			chp->ch_status = status = 			    CHP_READ_REG(chp, wdr_status);#endif		}		if ((status & WDCS_BSY) == 0 && (status & mask) == bits) 			break;		if (++time > timeout) {			WDCDEBUG_PRINT(("wdcwait: timeout, status %x "			    "error %x\n", status,			    CHP_READ_REG(chp, wdr_error)),			    DEBUG_STATUSX | DEBUG_STATUS); 			return -1;		}		delay(WDCDELAY);	}#ifdef TEST_ALTSTS	/* Acknowledge any pending interrupts */	CHP_READ_REG(chp, wdr_status);#endif	if (status & WDCS_ERR) {		chp->ch_error = CHP_READ_REG(chp, wdr_error);		WDCDEBUG_PRINT(("wdcwait: error %x\n", chp->ch_error),			       DEBUG_STATUSX | DEBUG_STATUS);	}#ifndef PMON#ifdef WDCNDELAY_DEBUG	/* After autoconfig, there should be no long delays. */	if (!cold && time > WDCNDELAY_DEBUG) {		struct wdc_xfer *xfer = chp->ch_queue->sc_xfer.tqh_first;		if (xfer == NULL)			printf("%s channel %d: warning: busy-wait took %dus\n",			    chp->wdc->sc_dev.dv_xname, chp->channel,			    WDCDELAY * time);		else 			printf("%s:%d:%d: warning: busy-wait took %dus\n",			    chp->wdc->sc_dev.dv_xname, chp->channel,			    xfer->drive,			    WDCDELAY * time);	}#endif#endif	return 0;}#ifndef PMONvoidwdctimeout(arg)	void *arg;{	struct channel_softc *chp = (struct channel_softc *)arg;	struct wdc_xfer *xfer = chp->ch_queue->sc_xfer.tqh_first;	int s;	WDCDEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS);	s = splbio();	if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0) {		__wdcerror(chp, "timeout");		printf("\ttype: %s\n", (xfer->c_flags & C_ATAPI) ?		    "atapi":"ata");		printf("\tc_bcount: %d\n", xfer->c_bcount);		printf("\tc_skip: %d\n", xfer->c_skip);		/*		 * Call the interrupt routine. If we just missed and interrupt,		 * it will do what's needed. Else, it will take the needed		 * action (reset the device).		 */		xfer->c_flags |= C_TIMEOU;		chp->ch_flags &= ~WDCF_IRQ_WAIT;		xfer->c_intr(chp, xfer, 1);	} else		__wdcerror(chp, "missing untimeout");	splx(s);}#endif /*PMON*//* * Probe drive's capabilites, for use by the controller later * Assumes drvp points to an existing drive.  * XXX this should be a controller-indep function */voidwdc_probe_caps(drvp, params)	struct ata_drive_datas *drvp;	struct ataparams *params;{	struct channel_softc *chp = drvp->chnl_softc;	struct wdc_softc *wdc = chp->wdc;	int i, printed;	int cf_flags = drvp->cf_flags;	if ((wdc->cap & (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) ==	    (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) {		struct ataparams params2;		/*		 * Controller claims 16 and 32 bit transfers.		 * Re-do an IDENTIFY with 32-bit transfers,		 * and compare results.		 */		drvp->drive_flags |= DRIVE_CAP32;		ata_get_params(drvp, at_poll, &params2);		if (bcmp(params, &params2, sizeof(struct ataparams)) != 0) {			/* Not good. fall back to 16bits */			drvp->drive_flags &= ~DRIVE_CAP32;		}	}#if 0 /* Some ultra-DMA drives claims to only support ATA-3. sigh */	if (params->atap_ata_major > 0x01 && 	    params->atap_ata_major != 0xffff) {		for (i = 14; i > 0; i--) {			if (params->atap_ata_major & (1 << i)) {				printf("%sATA version %d\n", sep, i);				drvp->ata_vers = i;				break;			}		}	} else #endif	/* An ATAPI device is at last PIO mode 3 */	if (drvp->drive_flags & DRIVE_ATAPI)		drvp->PIO_mode = 3;	/*	 * It's not in the specs, but it seems that some drive 	 * returns 0xffff in atap_extensions when this field is invalid	 */	if (params->atap_extensions != 0xffff &&	    (params->atap_extensions & WDC_EXT_MODES)) {		printed = 0;		/*		 * XXX some drives report something wrong here (they claim to		 * support PIO mode 8 !). As mode is coded on 3 bits in		 * SET FEATURE, limit it to 7 (so limit i to 4).		 * If higther mode than 7 is found, abort.		 */		for (i = 7; i >= 0; i--) {			if ((params->atap_piomode_supp & (1 << i)) == 0)				continue;			if (i > 4) {				return;			}			/*			 * See if mode is accepted.			 * If the controller can't set its PIO mode,			 * assume the defaults are good, so don't try			 * to set it			 */			if ((wdc->cap & WDC_CAPABILITY_MODE) != 0)				if (ata_set_mode(drvp, 0x08 | (i + 3),				   at_poll) != CMD_OK)					continue;			if (!printed) { 				printed = 1;			}			/*			 * If controller's driver can't set its PIO mode,			 * get the highter one for the drive.			 */			if ((wdc->cap & WDC_CAPABILITY_MODE) == 0 ||			    wdc->PIO_cap >= i + 3) {				drvp->PIO_mode = i + 3;				drvp->PIO_cap = i + 3;				break;			}		}		if (!printed) {			/* 			 * We didn't find a valid PIO mode.			 * Assume the values returned for DMA are buggy too			 */			return;		}		drvp->drive_flags |= DRIVE_MODE;		printed = 0;		for (i = 7; i >= 0; i--) {			if ((params->atap_dmamode_supp & (1 << i)) == 0)				continue;			if ((wdc->cap & WDC_CAPABILITY_DMA) &&			    (wdc->cap & WDC_CAPABILITY_MODE))				if (ata_set_mode(drvp, 0x20 | i, at_poll)				    != CMD_OK)					continue;			if (!printed) {				printed = 1;			}			if (wdc->cap & WDC_CAPABILITY_DMA) {				if ((wdc->cap & WDC_CAPABILITY_MODE) &&				    wdc->DMA_cap < i)					continue;				drvp->DMA_mode = i;				drvp->DMA_cap = i;				drvp->drive_flags |= DRIVE_DMA;			}			break;		}		if (params->atap_extensions & WDC_EXT_UDMA_MODES) {			for (i = 7; i >= 0; i--) {				if ((params->atap_udmamode_supp & (1 << i))				    == 0)					continue;				if ((wdc->cap & WDC_CAPABILITY_MODE) &&				    (wdc->cap & WDC_CAPABILITY_UDMA))					if (ata_set_mode(drvp, 0x40 | i,					    at_poll) != CMD_OK)						continue;				if (wdc->cap & WDC_CAPABILITY_UDMA) {					if ((wdc->cap & WDC_CAPABILITY_MODE) &&					    wdc->UDMA_cap < i)						continue;					drvp->UDMA_mode = i;					drvp->UDMA_cap = i;					drvp->drive_flags |= DRIVE_UDMA;				}				break;			}		}	}	/* Try to guess ATA version here, if it didn't get reported */	if (drvp->ata_vers == 0) {		if (drvp->drive_flags & DRIVE_UDMA)			drvp->ata_vers = 4; /* should be at last ATA-4 */		else if (drvp->PIO_cap > 2)			drvp->ata_vers = 2; /* should be at last ATA-2 */	}	if (cf_flags & ATA_CONFIG_PIO_SET) {		drvp->PIO_mode =		    (cf_flags & ATA_CONFIG_PIO_MODES) >> ATA_CONFIG_PIO_OFF;		drvp->drive_flags |= DRIVE_MODE;	}	if ((wdc->cap & WDC_CAPABILITY_DMA) == 0) {		/* don't care about DMA modes */		return;	}	if (cf_flags & ATA_CONFIG_DMA_SET) {

⌨️ 快捷键说明

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