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

📄 scsi.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1990, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Van Jacobson of Lawrence Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)scsi.c	8.2 (Berkeley) 1/12/94 */#ifndef DEBUG#define DEBUG#endif/* * HP9000/3xx 98658 SCSI host adaptor driver. */#include "scsi.h"#if NSCSI > 0#ifndef lintstatic char rcsid[] = "$Header: /usr/src/sys/hp300/dev/RCS/scsi.c,v 1.2 92/04/10 20:48:29 mike Exp $";#endif#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <hp/dev/device.h>#include <hp300/dev/scsivar.h>#include <hp300/dev/scsireg.h>#include <hp300/dev/dmavar.h>#include <machine/cpu.h>#include <hp300/hp300/isr.h>/* * SCSI delays * In u-seconds, primarily for state changes on the SPC. */#define	SCSI_CMD_WAIT	1000	/* wait per step of 'immediate' cmds */#define	SCSI_DATA_WAIT	1000	/* wait per data in/out step */#define	SCSI_INIT_WAIT	50000	/* wait per step (both) during init */extern void isrlink();extern void _insque();extern void _remque();int	scsiinit(), scsigo(), scsiintr(), scsixfer();void	scsistart(), scsidone(), scsifree(), scsireset();struct	driver scsidriver = {	scsiinit, "scsi", (int (*)())scsistart, scsigo, scsiintr,	(int (*)())scsidone,};struct	scsi_softc scsi_softc[NSCSI];struct	isr scsi_isr[NSCSI];int scsi_cmd_wait = SCSI_CMD_WAIT;int scsi_data_wait = SCSI_DATA_WAIT;int scsi_init_wait = SCSI_INIT_WAIT;int scsi_nosync = 1;		/* inhibit sync xfers if 1 */int scsi_pridma = 0;		/* use "priority" dma */#ifdef DEBUGint	scsi_debug = 0;#define WAITHIST#endif#ifdef WAITHIST#define MAXWAIT	1022u_int	ixstart_wait[MAXWAIT+2];u_int	ixin_wait[MAXWAIT+2];u_int	ixout_wait[MAXWAIT+2];u_int	mxin_wait[MAXWAIT+2];u_int	mxin2_wait[MAXWAIT+2];u_int	cxin_wait[MAXWAIT+2];u_int	fxfr_wait[MAXWAIT+2];u_int	sgo_wait[MAXWAIT+2];#define HIST(h,w) (++h[((w)>MAXWAIT? MAXWAIT : ((w) < 0 ? -1 : (w))) + 1]);#else#define HIST(h,w)#endif#define	b_cylin		b_residstatic voidscsiabort(hs, hd, where)	register struct scsi_softc *hs;	volatile register struct scsidevice *hd;	char *where;{	int len;	int maxtries;	/* XXX - kludge till I understand whats *supposed* to happen */	int startlen;	/* XXX - kludge till I understand whats *supposed* to happen */	u_char junk;	printf("scsi%d: abort from %s: phase=0x%x, ssts=0x%x, ints=0x%x\n",		hs->sc_hc->hp_unit, where, hd->scsi_psns, hd->scsi_ssts,		hd->scsi_ints);	hd->scsi_ints = hd->scsi_ints;	hd->scsi_csr = 0;	if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0)		/* no longer connected to scsi target */		return;	/* get the number of bytes remaining in current xfer + fudge */	len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl;	/* for that many bus cycles, try to send an abort msg */	for (startlen = (len += 1024); (hd->scsi_ssts & SSTS_INITIATOR) && --len >= 0; ) {		hd->scsi_scmd = SCMD_SET_ATN;		maxtries = 1000;		while ((hd->scsi_psns & PSNS_REQ) == 0) {			if (! (hd->scsi_ssts & SSTS_INITIATOR))				goto out;			DELAY(1);			if (--maxtries == 0) {				printf("-- scsiabort gave up after 1000 tries (startlen = %d len = %d)\n",					startlen, len);				goto out2;			}		}out2:		if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE)			hd->scsi_scmd = SCMD_RST_ATN;		hd->scsi_pctl = hd->scsi_psns & PHASE;		if (hd->scsi_psns & PHASE_IO) {			/* one of the input phases - read & discard a byte */			hd->scsi_scmd = SCMD_SET_ACK;			if (hd->scsi_tmod == 0)				while (hd->scsi_psns & PSNS_REQ)					DELAY(1);			junk = hd->scsi_temp;		} else {			/* one of the output phases - send an abort msg */			hd->scsi_temp = MSG_ABORT;			hd->scsi_scmd = SCMD_SET_ACK;			if (hd->scsi_tmod == 0)				while (hd->scsi_psns & PSNS_REQ)					DELAY(1);		}		hd->scsi_scmd = SCMD_RST_ACK;	}out:	/*	 * Either the abort was successful & the bus is disconnected or	 * the device didn't listen.  If the latter, announce the problem.	 * Either way, reset the card & the SPC.	 */	if (len < 0 && hs)		printf("scsi%d: abort failed.  phase=0x%x, ssts=0x%x\n",			hs->sc_hc->hp_unit, hd->scsi_psns, hd->scsi_ssts);	if (! ((junk = hd->scsi_ints) & INTS_RESEL)) {		hd->scsi_sctl |= SCTL_CTRLRST;		DELAY(1);		hd->scsi_sctl &=~ SCTL_CTRLRST;		hd->scsi_hconf = 0;		hd->scsi_ints = hd->scsi_ints;	}}/* * XXX Set/reset long delays. * * if delay == 0, reset default delays * if delay < 0,  set both delays to default long initialization values * if delay > 0,  set both delays to this value * * Used when a devices is expected to respond slowly (e.g. during * initialization). */voidscsi_delay(delay)	int delay;{	static int saved_cmd_wait, saved_data_wait;	if (delay) {		saved_cmd_wait = scsi_cmd_wait;		saved_data_wait = scsi_data_wait;		if (delay > 0)			scsi_cmd_wait = scsi_data_wait = delay;		else			scsi_cmd_wait = scsi_data_wait = scsi_init_wait;	} else {		scsi_cmd_wait = saved_cmd_wait;		scsi_data_wait = saved_data_wait;	}}intscsiinit(hc)	register struct hp_ctlr *hc;{	register struct scsi_softc *hs = &scsi_softc[hc->hp_unit];	register struct scsidevice *hd = (struct scsidevice *)hc->hp_addr;		if ((hd->scsi_id & ID_MASK) != SCSI_ID)		return(0);	hc->hp_ipl = SCSI_IPL(hd->scsi_csr);	hs->sc_hc = hc;	hs->sc_dq.dq_unit = hc->hp_unit;	hs->sc_dq.dq_driver = &scsidriver;	hs->sc_sq.dq_forw = hs->sc_sq.dq_back = &hs->sc_sq;	scsi_isr[hc->hp_unit].isr_intr = scsiintr;	scsi_isr[hc->hp_unit].isr_ipl = hc->hp_ipl;	scsi_isr[hc->hp_unit].isr_arg = hc->hp_unit;	isrlink(&scsi_isr[hc->hp_unit]);	scsireset(hc->hp_unit);	/*	 * XXX scale initialization wait according to CPU speed.	 * Should we do this for all wait?  Should we do this at all?	 */	scsi_init_wait *= cpuspeed;	return(1);}voidscsireset(unit)	register int unit;{	register struct scsi_softc *hs = &scsi_softc[unit];	volatile register struct scsidevice *hd =				(struct scsidevice *)hs->sc_hc->hp_addr;	u_int i;	if (hs->sc_flags & SCSI_ALIVE)		scsiabort(hs, hd, "reset");			printf("scsi%d: ", unit);	hd->scsi_id = 0xFF;	DELAY(100);	/*	 * Disable interrupts then reset the FUJI chip.	 */	hd->scsi_csr  = 0;	hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST;	hd->scsi_scmd = 0;	hd->scsi_tmod = 0;	hd->scsi_pctl = 0;	hd->scsi_temp = 0;	hd->scsi_tch  = 0;	hd->scsi_tcm  = 0;	hd->scsi_tcl  = 0;	hd->scsi_ints = 0;	if ((hd->scsi_id & ID_WORD_DMA) == 0) {		hs->sc_flags |= SCSI_DMA32;		printf("32 bit dma, ");	}	/* Determine Max Synchronous Transfer Rate */	if (scsi_nosync)		i = 3;	else		i = SCSI_SYNC_XFER(hd->scsi_hconf);	switch (i) {		case 0:			hs->sc_sync = TMOD_SYNC | 0x3e; /* 250 nsecs */			printf("250ns sync");			break;		case 1:			hs->sc_sync = TMOD_SYNC | 0x5e; /* 375 nsecs */			printf("375ns sync");			break;		case 2:			hs->sc_sync = TMOD_SYNC | 0x7d; /* 500 nsecs */			printf("500ns sync");			break;		case 3:			hs->sc_sync = 0;			printf("async");			break;		}	/*	 * Configure the FUJI chip with its SCSI address, all	 * interrupts enabled & appropriate parity.	 */	i = (~hd->scsi_hconf) & 0x7;	hs->sc_scsi_addr = 1 << i;	hd->scsi_bdid = i;	if (hd->scsi_hconf & HCONF_PARITY)		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |				SCTL_INTR_ENAB | SCTL_PARITY_ENAB;	else {		hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB |				SCTL_SEL_ENAB | SCTL_RESEL_ENAB |				SCTL_INTR_ENAB;		printf(", no parity");	}	hd->scsi_sctl &=~ SCTL_DISABLE;	printf(", scsi id %d\n", i);	hs->sc_flags |= SCSI_ALIVE;}static voidscsierror(hs, hd, ints)	register struct scsi_softc *hs;	volatile register struct scsidevice *hd;	u_char ints;{	int unit = hs->sc_hc->hp_unit;	char *sep = "";	printf("scsi%d: ", unit);	if (ints & INTS_RST) {		DELAY(100);		if (hd->scsi_hconf & HCONF_SD)			printf("spurious RST interrupt");		else			printf("hardware error - check fuse");		sep = ", ";	}	if ((ints & INTS_HARD_ERR) || hd->scsi_serr) {		if (hd->scsi_serr & SERR_SCSI_PAR) {			printf("%sparity err", sep);			sep = ", ";		}		if (hd->scsi_serr & SERR_SPC_PAR) {			printf("%sSPC parity err", sep);			sep = ", ";		}		if (hd->scsi_serr & SERR_TC_PAR) {			printf("%sTC parity err", sep);			sep = ", ";		}		if (hd->scsi_serr & SERR_PHASE_ERR) {			printf("%sphase err", sep);			sep = ", ";		}		if (hd->scsi_serr & SERR_SHORT_XFR) {			printf("%ssync short transfer err", sep);			sep = ", ";		}		if (hd->scsi_serr & SERR_OFFSET) {			printf("%ssync offset error", sep);			sep = ", ";		}	}	if (ints & INTS_TIMEOUT)		printf("%sSPC select timeout error", sep);	if (ints & INTS_SRV_REQ)		printf("%sspurious SRV_REQ interrupt", sep);	if (ints & INTS_CMD_DONE)		printf("%sspurious CMD_DONE interrupt", sep);	if (ints & INTS_DISCON)		printf("%sspurious disconnect interrupt", sep);	if (ints & INTS_RESEL)		printf("%sspurious reselect interrupt", sep);	if (ints & INTS_SEL)		printf("%sspurious select interrupt", sep);	printf("\n");}static intissue_select(hd, target, our_addr)	volatile register struct scsidevice *hd;	u_char target, our_addr;{	if (hd->scsi_ssts & (SSTS_INITIATOR|SSTS_TARGET|SSTS_BUSY))		return (1);	if (hd->scsi_ints & INTS_DISCON)		hd->scsi_ints = INTS_DISCON;	hd->scsi_pctl = 0;	hd->scsi_temp = (1 << target) | our_addr;	/* select timeout is hardcoded to 2ms */	hd->scsi_tch = 0;	hd->scsi_tcm = 32;	hd->scsi_tcl = 4;	hd->scsi_scmd = SCMD_SELECT;	return (0);}

⌨️ 快捷键说明

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