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

📄 tz.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * 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. * *	@(#)tz.c	8.4 (Berkeley) 1/11/94 * * from: $Header: /sprite/src/kernel/dev/RCS/devSCSITape.c, *	v 8.14 89/07/31 17:26:13 mendel Exp $ SPRITE (Berkeley) *//* * SCSI CCS (Command Command Set) tape driver. */#include "tz.h"#if NTZ > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/buf.h>#include <sys/errno.h>#include <sys/file.h>#include <sys/ioctl.h>#include <sys/mtio.h>#include <sys/syslog.h>#include <sys/tprintf.h>#include <pmax/dev/device.h>#include <pmax/dev/scsi.h>int	tzprobe();void	tzstart(), tzdone();struct	driver tzdriver = {	"tz", tzprobe, tzstart, tzdone,};struct	tz_softc {	struct	scsi_device *sc_sd;	/* physical unit info */	int	sc_flags;		/* see below */	int	sc_tapeid;		/* tape drive id */	int	sc_blklen;		/* 0 = variable len records */	long	sc_numblks;		/* number of blocks on tape */	tpr_t	sc_ctty;		/* terminal for error messages */	struct	buf sc_tab;		/* queue of pending operations */	struct	buf sc_buf;		/* buf for doing I/O */	struct	buf sc_errbuf;		/* buf for doing REQUEST_SENSE */	struct	ScsiCmd sc_cmd;		/* command for controller */	ScsiGroup0Cmd sc_rwcmd;		/* SCSI cmd for read/write */	struct	scsi_fmt_cdb sc_cdb;	/* SCSI cmd if not read/write */	struct	scsi_fmt_sense sc_sense;	/* sense data from last cmd */	struct	ScsiTapeModeSelectHdr sc_mode;	/* SCSI_MODE_SENSE data */	char	sc_modelen;		/* SCSI_MODE_SENSE data length */} tz_softc[NTZ];/* sc_flags values */#define	TZF_ALIVE		0x01	/* drive found and ready */#define	TZF_SENSEINPROGRESS	0x02	/* REQUEST_SENSE command in progress */#define	TZF_ALTCMD		0x04	/* alternate command in progress */#define	TZF_WRITTEN		0x08	/* tape has been written to */#define	TZF_OPEN		0x10	/* device is open */#define	TZF_WAIT		0x20	/* waiting for sc_tab to drain */#define TZF_SEENEOF		0x40	/* seen file mark on read *//* bits in minor device */#define	tzunit(x)	(minor(x) >> 4)	/* tz%d unit number */#define TZ_NOREWIND	0x01		/* don't rewind on close */#define TZ_HIDENSITY	0x02#define TZ_EXSFMK	0x04#define TZ_FIXEDBLK	0x08#ifdef DEBUGint	tzdebug = 0;#endif/* * Test to see if device is present. * Return true if found and initialized ok. */tzprobe(sd)	struct scsi_device *sd;{	register struct tz_softc *sc = &tz_softc[sd->sd_unit];	register int i;	ScsiInquiryData inqbuf;	ScsiClass7Sense *sp;	/* init some parameters that don't change */	sc->sc_sd = sd;	sc->sc_cmd.sd = sd;	sc->sc_cmd.unit = sd->sd_unit;	sc->sc_cmd.flags = 0;	sc->sc_rwcmd.unitNumber = sd->sd_slave;	/* try to find out what type of device this is */	sc->sc_flags = TZF_ALTCMD;	/* force use of sc_cdb */	sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);	scsiGroup0Cmd(SCSI_INQUIRY, sd->sd_slave, 0, sizeof(inqbuf),		(ScsiGroup0Cmd *)sc->sc_cdb.cdb);	sc->sc_buf.b_flags = B_BUSY | B_READ;	sc->sc_buf.b_bcount = sizeof(inqbuf);	sc->sc_buf.b_un.b_addr = (caddr_t)&inqbuf;	sc->sc_buf.b_actf = (struct buf *)0;	sc->sc_buf.b_actb = &sc->sc_tab.b_actf;	sc->sc_tab.b_actf = &sc->sc_buf;	sc->sc_tab.b_actb = &sc->sc_buf.b_actf;	tzstart(sd->sd_unit);	if (biowait(&sc->sc_buf) ||	    (i = sizeof(inqbuf) - sc->sc_buf.b_resid) < 5)		goto bad;	if (inqbuf.type != SCSI_TAPE_TYPE || !inqbuf.rmb)		goto bad;	/* check for device ready to clear UNIT_ATTN */	sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);	scsiGroup0Cmd(SCSI_TEST_UNIT_READY, sd->sd_slave, 0, 0,		(ScsiGroup0Cmd *)sc->sc_cdb.cdb);	sc->sc_buf.b_flags = B_BUSY | B_READ;	sc->sc_buf.b_bcount = 0;	sc->sc_buf.b_un.b_addr = (caddr_t)0;	sc->sc_buf.b_actf = (struct buf *)0;	sc->sc_buf.b_actb = &sc->sc_tab.b_actf;	sc->sc_tab.b_actf = &sc->sc_buf;	sc->sc_tab.b_actb = &sc->sc_buf.b_actf;	tzstart(sd->sd_unit);	(void) biowait(&sc->sc_buf);	sc->sc_flags = TZF_ALIVE;	sc->sc_modelen = 12;	sc->sc_buf.b_flags = 0;	printf("tz%d at %s%d drive %d slave %d", sd->sd_unit,		sd->sd_cdriver->d_name, sd->sd_ctlr, sd->sd_drive,		sd->sd_slave);	if (i == 5 && inqbuf.version == 1 && inqbuf.qualifier == 0x50) {		printf(" TK50\n");		sc->sc_tapeid = MT_ISTK50;	} else if (i >= 5 && inqbuf.version == 1 && inqbuf.qualifier == 0 &&	    inqbuf.length == 0) {		/* assume Emultex MT02 controller */		printf(" MT02\n");		sc->sc_tapeid = MT_ISMT02;	} else if (inqbuf.version > 2 || i < 36) {		printf(" GENERIC SCSI tape device: qual 0x%x, ver %d\n",			inqbuf.qualifier, inqbuf.version);		sc->sc_tapeid = 0;	} else {		char vid[9], pid[17], revl[5];		bcopy((caddr_t)inqbuf.vendorID, (caddr_t)vid, 8);		bcopy((caddr_t)inqbuf.productID, (caddr_t)pid, 16);		bcopy((caddr_t)inqbuf.revLevel, (caddr_t)revl, 4);		for (i = 8; --i > 0; )			if (vid[i] != ' ')				break;		vid[i+1] = 0;		for (i = 16; --i > 0; )			if (pid[i] != ' ')				break;		pid[i+1] = 0;		for (i = 4; --i > 0; )			if (revl[i] != ' ')				break;		revl[i+1] = 0;		printf(" %s %s rev %s\n", vid, pid, revl);		if (bcmp("EXB-8200", pid, 8) == 0) {			sc->sc_tapeid = MT_ISEXABYTE;			sc->sc_modelen = 17;		} else if (bcmp("VIPER 150", pid, 9) == 0) {			sc->sc_tapeid = MT_ISVIPER1;		} else if (bcmp("Python 25501", pid, 12) == 0) {			sc->sc_tapeid = MT_ISPYTHON;		} else if (bcmp("HP35450A", pid, 8) == 0) {#if 0			/* XXX "extra" stat makes the HP drive happy at boot time */			stat = scsi_test_unit_rdy(ctlr, slave, unit);#endif			sc->sc_tapeid = MT_ISHPDAT;		} else if (bcmp("123107 SCSI", pid, 11) == 0) {			sc->sc_tapeid = MT_ISMFOUR;		} else {			printf("tz%d: assuming GENERIC SCSI tape device\n",				sd->sd_unit,				inqbuf.type, inqbuf.qualifier, inqbuf.version);			sc->sc_tapeid = 0;		}	}	return (1);bad:	/* doesn't exist or not a CCS device */	sc->sc_flags = 0;	sc->sc_buf.b_flags = 0;	return (0);}/* * Perform a special tape command on a SCSI Tape drive. */tzcommand(dev, command, code, count, data)	dev_t dev;	int command;	int code;	int count;	caddr_t data;{	register struct tz_softc *sc = &tz_softc[tzunit(dev)];	register ScsiGroup0Cmd *c;	int s, error;	s = splbio();	/* wait for pending operations to finish */	while (sc->sc_tab.b_actf) {		sc->sc_flags |= TZF_WAIT;		sleep(&sc->sc_flags, PZERO);	}	sc->sc_flags |= TZF_ALTCMD;	/* force use of sc_cdb */	sc->sc_cdb.len = sizeof(ScsiGroup0Cmd);	c = (ScsiGroup0Cmd *)sc->sc_cdb.cdb;	c->command = command;	c->unitNumber = sc->sc_sd->sd_slave;	c->highAddr = code;	c->midAddr = count >> 16;	c->lowAddr = count >> 8;	c->blockCount = count;	c->control = 0;	if (command == SCSI_MODE_SELECT)		sc->sc_buf.b_flags = B_BUSY;	else {		sc->sc_buf.b_flags = B_BUSY | B_READ;#if 0		/* this seems to work but doesn't give us a speed advantage */		if (command == SCSI_TEST_UNIT_READY)			sc->sc_cmd.flags |= SCSICMD_USE_SYNC;#endif	}	sc->sc_buf.b_bcount = data ? count : 0;	sc->sc_buf.b_un.b_addr = data;	sc->sc_buf.b_actf = (struct buf *)0;	sc->sc_buf.b_actb = &sc->sc_tab.b_actf;	sc->sc_tab.b_actf = &sc->sc_buf;	sc->sc_tab.b_actb = &sc->sc_buf.b_actf;	tzstart(sc->sc_sd->sd_unit);	error = biowait(&sc->sc_buf);	sc->sc_flags &= ~TZF_ALTCMD;	/* force use of sc_cdb */	sc->sc_buf.b_flags = 0;	sc->sc_cmd.flags = 0;	if (sc->sc_buf.b_resid)		printf("tzcommand: resid %d\n", sc->sc_buf.b_resid); /* XXX */	if (error == 0)		switch (command) {		case SCSI_SPACE:		case SCSI_WRITE_EOF:		case SCSI_REWIND:			sc->sc_flags &= ~TZF_SEENEOF;		}	splx(s);	return (error);}voidtzstart(unit)	int unit;{	register struct tz_softc *sc = &tz_softc[unit];	register struct buf *bp = sc->sc_tab.b_actf;	register int n;	sc->sc_cmd.buf = bp->b_un.b_addr;	sc->sc_cmd.buflen = bp->b_bcount;	if (sc->sc_flags & (TZF_SENSEINPROGRESS | TZF_ALTCMD)) {		if (bp->b_flags & B_READ)			sc->sc_cmd.flags &= ~SCSICMD_DATA_TO_DEVICE;		else			sc->sc_cmd.flags |= SCSICMD_DATA_TO_DEVICE;		sc->sc_cmd.cmd = sc->sc_cdb.cdb;		sc->sc_cmd.cmdlen = sc->sc_cdb.len;	} else {		if (bp->b_flags & B_READ) {			sc->sc_cmd.flags = 0;			sc->sc_rwcmd.command = SCSI_READ;			sc->sc_flags &= ~TZF_WRITTEN;		} else {			sc->sc_cmd.flags = SCSICMD_DATA_TO_DEVICE;			sc->sc_rwcmd.command = SCSI_WRITE;			sc->sc_flags |= TZF_WRITTEN;		}		sc->sc_cmd.cmd = (u_char *)&sc->sc_rwcmd;		sc->sc_cmd.cmdlen = sizeof(sc->sc_rwcmd);		if (sc->sc_blklen) {			/* fixed sized records */			n = bp->b_bcount / sc->sc_blklen;			if (bp->b_bcount % sc->sc_blklen) {				tprintf(sc->sc_ctty,					"tz%d: I/O not block aligned %d/%ld\n",					unit, sc->sc_blklen, bp->b_bcount);				tzdone(unit, EIO, bp->b_bcount, 0);			}			sc->sc_rwcmd.highAddr = 1;		} else {			/* variable sized records */			n = bp->b_bcount;			sc->sc_rwcmd.highAddr = 0;		}		sc->sc_rwcmd.midAddr = n >> 16;		sc->sc_rwcmd.lowAddr = n >> 8;		sc->sc_rwcmd.blockCount = n;	}	/* tell controller to start this command */	(*sc->sc_sd->sd_cdriver->d_start)(&sc->sc_cmd);}/* * This is called by the controller driver when the command is done. */voidtzdone(unit, error, resid, status)	int unit;	int error;		/* error number from errno.h */	int resid;		/* amount not transfered */	int status;		/* SCSI status byte */{	register struct tz_softc *sc = &tz_softc[unit];	register struct buf *bp = sc->sc_tab.b_actf;	register struct buf *dp;	extern int cold;	if (bp == NULL) {		printf("tz%d: bp == NULL\n", unit);		return;	}	if (sc->sc_flags & TZF_SENSEINPROGRESS) {		sc->sc_flags &= ~TZF_SENSEINPROGRESS;		*bp->b_actb = dp = bp->b_actf;	/* remove sc_errbuf */#ifdef DIAGNOSTIC		if (!dp)			panic("tzdone");#endif		dp->b_actb = bp->b_actb;		bp = dp;		if (error || (status & SCSI_STATUS_CHECKCOND)) {			printf("tz%d: error reading sense data: error %d scsi status 0x%x\n",				unit, error, status);			/*			 * We got an error during the REQUEST_SENSE,			 * fill in no sense for data.			 */			sc->sc_sense.sense[0] = 0x70;			sc->sc_sense.sense[2] = SCSI_CLASS7_NO_SENSE;		} else if (!cold) {			ScsiClass7Sense *sp;			long resid;			sp = (ScsiClass7Sense *)sc->sc_sense.sense;			if (sp->error7 != 0x70)				goto prerr;			if (sp->valid) {				resid = (sp->info1 << 24) | (sp->info2 << 16) |					(sp->info3 << 8) | sp->info4;				if (sc->sc_blklen)					resid *= sc->sc_blklen;			} else				resid = 0;			switch (sp->key) {			case SCSI_CLASS7_NO_SENSE:				/*				 * Hit a filemark, end of media, or

⌨️ 快捷键说明

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