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

📄 wdc.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 3 页
字号:
		if ((cf_flags & ATA_CONFIG_DMA_MODES) ==		    ATA_CONFIG_DMA_DISABLE) {			drvp->drive_flags &= ~DRIVE_DMA;		} else {			drvp->DMA_mode = (cf_flags & ATA_CONFIG_DMA_MODES) >>			    ATA_CONFIG_DMA_OFF;			drvp->drive_flags |= DRIVE_DMA | DRIVE_MODE;		}	}	if (cf_flags & ATA_CONFIG_UDMA_SET) {		if ((cf_flags & ATA_CONFIG_UDMA_MODES) ==		    ATA_CONFIG_UDMA_DISABLE) {			drvp->drive_flags &= ~DRIVE_UDMA;		} else {			drvp->UDMA_mode = (cf_flags & ATA_CONFIG_UDMA_MODES) >>			    ATA_CONFIG_UDMA_OFF;			drvp->drive_flags |= DRIVE_UDMA | DRIVE_MODE;		}	}}voidwdc_output_bytes(drvp, bytes, buflen)	struct ata_drive_datas *drvp;	void *bytes;	unsigned int buflen;{	struct channel_softc *chp = drvp->chnl_softc;	unsigned int off = 0;	unsigned int len = buflen, roundlen;		if (drvp->drive_flags & DRIVE_CAP32) {		roundlen = len & ~3;		CHP_WRITE_RAW_MULTI_4(chp, 		    (void *)((u_int8_t *)bytes + off), roundlen);		off += roundlen;		len -= roundlen;	}	if (len > 0) {		roundlen = (len + 1) & ~0x1;	        CHP_WRITE_RAW_MULTI_2(chp,		    (void *)((u_int8_t *)bytes + off), roundlen);	}	return;}voidwdc_input_bytes(drvp, bytes, buflen)	struct ata_drive_datas *drvp;	void *bytes;	unsigned int buflen;{	struct channel_softc *chp = drvp->chnl_softc;	unsigned int off = 0;	unsigned int len = buflen, roundlen;	if (drvp->drive_flags & DRIVE_CAP32) {		roundlen = len & ~3;		CHP_READ_RAW_MULTI_4(chp,		    (void *)((u_int8_t *)bytes + off), roundlen);		off += roundlen;		len -= roundlen;	}	if (len > 0) {		roundlen = (len + 1) & ~0x1;		CHP_READ_RAW_MULTI_2(chp,		    (void *)((u_int8_t *)bytes + off), roundlen);	}	return;}voidwdc_print_caps(drvp)	struct ata_drive_datas *drvp;{ 	printf("%s: can use ", drvp->drive_name);	if (drvp->drive_flags & DRIVE_CAP32) {		printf("32-bit");	} else 		printf("16-bit");	printf(", PIO mode %d", drvp->PIO_cap);	if (drvp->drive_flags & DRIVE_DMA) {		printf(", DMA mode %d", drvp->DMA_cap);	}	if (drvp->drive_flags & DRIVE_UDMA) {		printf(", Ultra-DMA mode %d", drvp->UDMA_cap);	}				printf("\n");}/* * downgrade the transfer mode of a drive after an error. return 1 if * downgrade was possible, 0 otherwise. */intwdc_downgrade_mode(drvp)	struct ata_drive_datas *drvp;{#ifndef PMON	struct channel_softc *chp = drvp->chnl_softc;	struct wdc_softc *wdc = chp->wdc;	int cf_flags = drvp->cf_flags;	/* if drive or controller don't know its mode, we can't do much */	if ((drvp->drive_flags & DRIVE_MODE) == 0 ||	    (wdc->cap & WDC_CAPABILITY_MODE) == 0)		return 0;	/* current drive mode was set by a config flag, let it this way */	if ((cf_flags & ATA_CONFIG_PIO_SET) ||	    (cf_flags & ATA_CONFIG_DMA_SET) ||	    (cf_flags & ATA_CONFIG_UDMA_SET))		return 0;	/*	 * If we were using Ultra-DMA mode > 2, downgrade to mode 2 first.	 * Maybe we didn't properly notice the cable type	 */	if ((drvp->drive_flags & DRIVE_UDMA) && drvp->UDMA_mode >= 2) {		drvp->UDMA_mode = (drvp->UDMA_mode == 2) ? 1 : 2;		printf("%s: transfer error, downgrading to Ultra-DMA mode %d\n",		    drvp->drive_name, drvp->UDMA_mode);	} else 	if ((drvp->drive_flags & DRIVE_UDMA) &&	    (drvp->drive_flags & DRIVE_DMAERR) == 0) {		/* 		 * If we were using ultra-DMA, don't downgrade to		 * multiword DMA if we noticed a CRC error. It has		 * been noticed that CRC errors in ultra-DMA lead to		 * silent data corruption in multiword DMA.  Data		 * corruption is less likely to occur in PIO mode.  		 */		drvp->drive_flags &= ~DRIVE_UDMA;		drvp->drive_flags |= DRIVE_DMA;		drvp->DMA_mode = drvp->DMA_cap;		printf("%s: transfer error, downgrading to DMA mode %d\n",		    drvp->drive_name, drvp->DMA_mode);	} else if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) {		drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);		drvp->PIO_mode = drvp->PIO_cap;		printf("%s: transfer error, downgrading to PIO mode %d\n",		    drvp->drive_name, drvp->PIO_mode);	} else /* already using PIO, can't downgrade */		return 0;	wdc->set_modes(chp);	/* reset the channel, which will schedule all drives for setup */	wdc_reset_channel(drvp);	return 1;#else	return 0;#endif}intwdc_exec_command(drvp, wdc_c)	struct ata_drive_datas *drvp;	struct wdc_command *wdc_c;{	struct channel_softc *chp = drvp->chnl_softc;	struct wdc_xfer *xfer;	int s, ret;	WDCDEBUG_PRINT(("wdc_exec_command %s:%d:%d\n",	    chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),	    DEBUG_FUNCS);	/* set up an xfer and queue. Wait for completion */	xfer = wdc_get_xfer(wdc_c->flags & AT_WAIT ? WDC_CANSLEEP :	    WDC_NOSLEEP);	if (xfer == NULL) {		return WDC_TRY_AGAIN;	 }	if (wdc_c->flags & AT_POLL)		xfer->c_flags |= C_POLL;	xfer->drive = drvp->drive;	xfer->databuf = wdc_c->data;	xfer->c_bcount = wdc_c->bcount;	xfer->cmd = wdc_c;	xfer->c_start = __wdccommand_start;	xfer->c_intr = __wdccommand_intr;	xfer->c_kill_xfer = __wdccommand_done;	s = splbio();	wdc_exec_xfer(chp, xfer);#ifdef DIAGNOSTIC	if ((wdc_c->flags & AT_POLL) != 0 &&	    (wdc_c->flags & AT_DONE) == 0)		panic("wdc_exec_command: polled command not done\n");#endif	if (wdc_c->flags & AT_DONE) {		ret = WDC_COMPLETE;	} else {		if (wdc_c->flags & AT_WAIT) {			WDCDEBUG_PRINT(("wdc_exec_command sleeping"),				       DEBUG_FUNCS);			while (!(wdc_c->flags & AT_DONE)) {				int error;				error = tsleep(wdc_c, PRIBIO, "wdccmd", 0);				if (error) {					printf ("tsleep error: %d\n", error);				}			}			WDCDEBUG_PRINT(("wdc_exec_command waking"),				       DEBUG_FUNCS);			ret = WDC_COMPLETE;		} else {			ret = WDC_QUEUED;		}	}	splx(s);	return ret;}void__wdccommand_start(chp, xfer)	struct channel_softc *chp;	struct wdc_xfer *xfer;{   	int drive = xfer->drive;	struct wdc_command *wdc_c = xfer->cmd;	WDCDEBUG_PRINT(("__wdccommand_start %s:%d:%d\n",	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),	    DEBUG_FUNCS);	/*	 * Disable interrupts if we're polling	 */	if (xfer->c_flags & C_POLL) {		wdc_disable_intr(chp);	}	/*	 * For resets, we don't really care to make sure that	 * the bus is free	 */	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));	if (wdc_c->r_command != ATAPI_SOFT_RESET) {		if (wdcwait(chp, wdc_c->r_st_bmask, wdc_c->r_st_bmask,		    wdc_c->timeout) != 0) {			wdc_c->flags |= AT_TIMEOU;			__wdccommand_done(chp, xfer);			return;		}	} else		DELAY(10);	wdccommand(chp, drive, wdc_c->r_command, wdc_c->r_cyl, wdc_c->r_head,	    wdc_c->r_sector, wdc_c->r_count, wdc_c->r_precomp);#ifndef PMON	if ((wdc_c->flags & AT_POLL) == 0) {		chp->ch_flags |= WDCF_IRQ_WAIT; /* wait for interrupt */		timeout(wdctimeout, chp, wdc_c->timeout / 1000 * hz);		return;	}#endif	/*	 * Polled command. Wait for drive ready or drq. Done in intr().	 * Wait for at last 400ns for status bit to be valid.	 */	delay(10);	__wdccommand_intr(chp, xfer, 0);}int__wdccommand_intr(chp, xfer, irq)	struct channel_softc *chp;	struct wdc_xfer *xfer;	int irq;{	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];	struct wdc_command *wdc_c = xfer->cmd;	int bcount = wdc_c->bcount;	char *data = wdc_c->data;	WDCDEBUG_PRINT(("__wdccommand_intr %s:%d:%d\n",	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_INTR);	if (wdcwait(chp, wdc_c->r_st_pmask, wdc_c->r_st_pmask,	     (irq == 0)  ? wdc_c->timeout : 0)) {		if (irq && (xfer->c_flags & C_TIMEOU) == 0) 			return 0; /* IRQ was not for us */		wdc_c->flags |= AT_TIMEOU;		__wdccommand_done(chp, xfer);		WDCDEBUG_PRINT(("__wdccommand_intr returned\n"), DEBUG_INTR);		return 1;	}	if (wdc_c->flags & AT_READ) {		wdc_input_bytes(drvp, data, bcount);	} else if (wdc_c->flags & AT_WRITE) {		wdc_output_bytes(drvp, data, bcount);	}	__wdccommand_done(chp, xfer);	WDCDEBUG_PRINT(("__wdccommand_intr returned\n"), DEBUG_INTR);	return 1;}void__wdccommand_done(chp, xfer)	struct channel_softc *chp;	struct wdc_xfer *xfer;{	struct wdc_command *wdc_c = xfer->cmd;	WDCDEBUG_PRINT(("__wdccommand_done %s:%d:%d\n",	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_FUNCS);	if (chp->ch_status & WDCS_DWF)		wdc_c->flags |= AT_DF;	if (chp->ch_status & WDCS_ERR) {		wdc_c->flags |= AT_ERROR;		wdc_c->r_error = chp->ch_error;	}	wdc_c->flags |= AT_DONE;	if (wdc_c->flags & AT_READREG && (wdc_c->flags & (AT_ERROR | AT_DF))								== 0) {		wdc_c->r_head = CHP_READ_REG(chp, wdr_sdh);		wdc_c->r_cyl = CHP_READ_REG(chp, wdr_cyl_hi) << 8;		wdc_c->r_cyl |= CHP_READ_REG(chp, wdr_cyl_lo);		wdc_c->r_sector = CHP_READ_REG(chp, wdr_sector);		wdc_c->r_count = CHP_READ_REG(chp, wdr_seccnt);		wdc_c->r_error = CHP_READ_REG(chp, wdr_error);		wdc_c->r_precomp = wdc_c->r_error; 		/* XXX CHP_READ_REG(chp, wdr_precomp); - precomp		   isn't a readable register */	}	if (xfer->c_flags & C_POLL) {		wdc_enable_intr(chp);	}	wdc_free_xfer(chp, xfer);	WDCDEBUG_PRINT(("__wdccommand_done before callback\n"), DEBUG_INTR);	if (wdc_c->flags & AT_WAIT)		wakeup(wdc_c);	else		if (wdc_c->callback)			wdc_c->callback(wdc_c->callback_arg);	wdcstart(chp);	WDCDEBUG_PRINT(("__wdccommand_done returned\n"), DEBUG_INTR);	return;}/* * Send a command. The drive should be ready. * Assumes interrupts are blocked. */voidwdccommand(chp, drive, command, cylin, head, sector, count, precomp)	struct channel_softc *chp;	u_int8_t drive;	u_int8_t command;	u_int16_t cylin;	u_int8_t head, sector, count, precomp;{	WDCDEBUG_PRINT(("wdccommand %s:%d:%d: command=0x%x cylin=%d head=%d "	    "sector=%d count=%d precomp=%d\n", chp->wdc->sc_dev.dv_xname,	    chp->channel, drive, command, cylin, head, sector, count, precomp),	    DEBUG_FUNCS);	/* Select drive, head, and addressing mode. */	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4) | head);	/* Load parameters. wdr_features(ATA/ATAPI) = wdr_precomp(ST506) */	CHP_WRITE_REG(chp, wdr_precomp, precomp);	CHP_WRITE_REG(chp, wdr_cyl_lo, cylin);	CHP_WRITE_REG(chp, wdr_cyl_hi, cylin >> 8);	CHP_WRITE_REG(chp, wdr_sector, sector);	CHP_WRITE_REG(chp, wdr_seccnt, count);	/* Send command. */	CHP_WRITE_REG(chp, wdr_command, command);	return;}/* * Simplified version of wdccommand().  Unbusy/ready/drq must be * tested by the caller. */voidwdccommandshort(chp, drive, command)	struct channel_softc *chp;	int drive;	int command;{	WDCDEBUG_PRINT(("wdccommandshort %s:%d:%d command 0x%x\n",	    chp->wdc->sc_dev.dv_xname, chp->channel, drive, command),	    DEBUG_FUNCS);	/* Select drive. */	CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (drive << 4));	CHP_WRITE_REG(chp, wdr_command, command);}/* Add a command to the queue and start controller. Must be called at splbio */voidwdc_exec_xfer(chp, xfer)	struct channel_softc *chp;	struct wdc_xfer *xfer;{	WDCDEBUG_PRINT(("wdc_exec_xfer %p channel %d drive %d\n", xfer,	    chp->channel, xfer->drive), DEBUG_XFERS);	/* complete xfer setup */	xfer->chp = chp;	/*	 * If we are a polled command, and the list is not empty,	 * we are doing a dump. Drop the list to allow the polled command	 * to complete, we're going to reboot soon anyway.	 */	if ((xfer->c_flags & C_POLL) != 0 &&	    chp->ch_queue->sc_xfer.tqh_first != NULL) {		TAILQ_INIT(&chp->ch_queue->sc_xfer);	}	/* insert at the end of command list */	TAILQ_INSERT_TAIL(&chp->ch_queue->sc_xfer,xfer , c_xferchain);	WDCDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n",	    chp->ch_flags), DEBUG_XFERS);	wdcstart(chp);}struct wdc_xfer *wdc_get_xfer(flags)	int flags;{	struct wdc_xfer *xfer;	int s;	s = splbio();	if ((xfer = xfer_free_list.lh_first) != NULL) {		LIST_REMOVE(xfer, free_list);		splx(s);#ifdef DIAGNOSTIC		if ((xfer->c_flags & C_INUSE) != 0)			panic("wdc_get_xfer: xfer already in use\n");#endif	} else {		splx(s);		WDCDEBUG_PRINT(("wdc:making xfer %d\n",wdc_nxfer), DEBUG_XFERS);		xfer = malloc(sizeof(*xfer), M_DEVBUF,		    ((flags & WDC_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));		if (xfer == NULL)			return 0;#ifdef DIAGNOSTIC		xfer->c_flags &= ~C_INUSE;#endif#ifdef WDCDEBUG		wdc_nxfer++;#endif	}#ifdef DIAGNOSTIC	if ((xfer->c_flags & C_INUSE) != 0)		panic("wdc_get_xfer: xfer already in use\n");#endif	bzero(xfer, sizeof(struct wdc_xfer));	xfer->c_flags = C_INUSE;	return xfer;}voidwdc_free_xfer(chp, xfer)	struct channel_softc *chp;	struct wdc_xfer *xfer;{	struct wdc_softc *wdc = chp->wdc;	int s;	if (wdc->cap & WDC_CAPABILITY_HWLOCK)		(*wdc->free_hw)(chp);	s = splbio();	chp->ch_flags &= ~WDCF_ACTIVE;	TAILQ_REMOVE(&chp->ch_queue->sc_xfer, xfer, c_xferchain);	xfer->c_flags &= ~C_INUSE;	LIST_INSERT_HEAD(&xfer_free_list, xfer, free_list);	splx(s);}/* * Kill off all pending xfers for a channel_softc. * * Must be called at splbio(). */voidwdc_kill_pending(chp)	struct channel_softc *chp;{	struct wdc_xfer *xfer;	while ((xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer)) != NULL) {		chp = xfer->chp;		(*xfer->c_kill_xfer)(chp, xfer);	}}#ifndef PMONstatic void__wdcerror(chp, msg) 	struct channel_softc *chp;	char *msg;{	struct wdc_xfer *xfer = chp->ch_queue->sc_xfer.tqh_first;	if (xfer == NULL)		printf("%s:%d: %s\n", chp->wdc->sc_dev.dv_xname, chp->channel,		    msg);	else 		printf("%s(%s:%d:%d): %s\n", 		    chp->ch_drive[xfer->drive].drive_name,		    chp->wdc->sc_dev.dv_xname,		    chp->channel, xfer->drive, msg);}#endif /*PMON*//*  * the bit bucket */voidwdcbit_bucket(chp, size)	struct channel_softc *chp; 	int size;{	CHP_READ_RAW_MULTI_2(chp, NULL, size);}#ifndef __OpenBSD__intwdc_addref(chp)	struct channel_softc *chp;{	struct wdc_softc *wdc = chp->wdc; 	struct scsipi_adapter *adapter = &wdc->sc_atapi_adapter;	int s, error = 0;	s = splbio();	if (adapter->scsipi_refcnt++ == 0 &&	    adapter->scsipi_enable != NULL) {		error = (*adapter->scsipi_enable)(wdc, 1);		if (error)			adapter->scsipi_refcnt--;	}	splx(s);	return (error);}voidwdc_delref(chp)	struct channel_softc *chp;{	struct wdc_softc *wdc = chp->wdc;	struct scsipi_adapter *adapter = &wdc->sc_atapi_adapter;	int s;	s = splbio();	if (adapter->scsipi_refcnt-- == 1 &&	    adapter->scsipi_enable != NULL)		(void) (*adapter->scsipi_enable)(wdc, 0);	splx(s);}#endif

⌨️ 快捷键说明

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