File:  [Research Unix] / researchv9 / sys / boot / stand / sd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:59 2018 UTC (8 years, 3 months ago) by root
Branches: belllabs, MAIN
CVS tags: researchv9-SUN3_old, researchv9-SUN3, HEAD
researchv9-SUN3(old)

/*
 * @(#)sd.c 1.1 86/02/03 Copyright (c) 1985 by Sun Microsystems, Inc.
 */
#include <sys/param.h>
#include <sys/inode.h>
#include <sun/dklabel.h>
#include <sun/dkio.h>
#include <sys/buf.h>
#include <sundev/screg.h>
#include <sundev/sireg.h>
#include <sundev/scsi.h>
#include <machine/sunromvec.h>
#include <machine/idprom.h>
#include "saio.h"
#include "param.h"

/* For RAM-based code, print detailed error messages */
#if !defined(SDBOOT) && !defined(BOOTBLOCK)
#define SDERRORS
#endif

/*
 * Scsi disk parameter block
 */
struct sdparam {
	int	sd_target;
	int	sd_unit;
	int	sd_boff;
#ifdef SUN3
	int	sd_ha_type;
#endif
	struct saioreq subsip[1];	/* Sip for host adapter */
};

/*
 * Record an error message from scsi
 */
#define DEBUG FIXME

#if (!defined(SDBOOT)) & !defined(STBOOT) & !defined(DEBUG)

#define	sc_error(msg)	scerrmsg = msg
#define DEFERRED_ERRORS
extern char *scerrmsg;

#else

extern sc_error();	/* It's in sc.c */
#undef DEFERRED_ERRORS

#endif

/*
 * Our DMA space
 */
struct sddma {
	char	buffer[MAXBSIZE];
	struct dk_label xlabel[1];
};

#define SDBUF		(((struct sddma *)sip->si_dmaaddr)->buffer)
#define label		(((struct sddma *)sip->si_dmaaddr)->xlabel)

/*
 * What resources we need to run
 */
struct devinfo sdinfo = {
	0,				/* No device to map in */
	sizeof (struct sddma),
	sizeof (struct sdparam),
	0,				/* Dummy devices */
	0,				/* Dummy devices */
	MAP_MAINMEM,
	MAXBSIZE,			/* transfer size */
};

/*
 * The interfaces we export
 */
extern int xxprobe(), xxboot();
int sdopen(), sdclose(), sdstrategy();

struct boottab sddriver = {
	"sd",	xxprobe, xxboot,
	 sdopen, sdclose, sdstrategy,
	"sd: Adaptec SCSI disk", &sdinfo
};

#ifndef BOOTBLOCK

/*
 * Test routine for isspinning() to see if SCSI disk is running.
 */
sdspin(sip, dummy)
	struct saioreq *sip;
	int dummy;
{

#ifdef lint
	dummy = dummy;
#endif lint
	sip->si_bn = 0;
	sip->si_cc = 0;
	sip->si_ma = 0;
	return (sdcmd (SC_TEST_UNIT_READY, sip, 0));
}
#endif

#ifdef SUN3
/*
 * Determine type of host adaptor interface, si or sc.
 * Returns 1 if si host adaptor and 0 if sc host adaptor.
 */
sd_probe(sip)
	struct saioreq *sip;
{
	if (siprobe(sip)) {
		return (1);
	} else {
		return (0);
	}
}
#endif

/*
 * Open the SCSI Disk controller
 */
sdopen(sip)
	register struct saioreq *sip;
{
	register struct sdparam *sdp;
	register short *sp, sum;
	register int count, r;

	sdp = (struct sdparam *)sip->si_devdata;
	bzero( (char *)sdp, (sizeof (struct sdparam)));

	/*
	 * Open the host adapter
	 */
	*sdp->subsip = *sip;		/* Initialize sub-sip */
#ifdef SUN3
	{
		extern struct boottab scdriver;
		extern struct boottab sidriver;

		/* FIXME, find out which scsi interface to use */
		if (sd_probe(sip)) {
			sdp->sd_ha_type = 1;

			/* FIXME, must vector thru table */
			sdp->subsip->si_boottab = &sidriver;	
		} else {
			sdp->sd_ha_type = 0;

			/* FIXME, must vector thru table */
			sdp->subsip->si_boottab = &scdriver;	
		}

	}
#endif
#ifdef SUN2
	{
		extern struct boottab scdriver;

		sdp->subsip->si_boottab = &scdriver;	
	}
#endif
	sdp->subsip->si_unit = sip->si_unit >> 2;	/* Target number */
	r = devopen(sdp->subsip);
	if (r < 0) return r;

	sdp->sd_unit = sip->si_unit & 0x03;	/* Logical unit number */

#ifndef BOOTBLOCK
	/*
	 * Check that the disk is up and running...
	 */
	switch (isspinning(sdspin, (char *)sip, 0)) {

	default:	/* Error from sdspin */
	case 0:		/* Disk still not ready */
		/* isspinning has already printed "Giving up..." */
		return (-1);

	case 1:
		break;

	case 2:
		DELAY(1000000);  /* one second delay after spinup */
		break;
	}
#endif

	/*
	 * Actually read the label
	 */
	label->dkl_magic = 0;
	sip->si_ma = (char *)label;
	sip->si_cc = SECSIZE;
	sip->si_bn = 0;		/* Read block #0 */
	if (sdcmd(SC_READ, sip, 1) <= 0) {
		return (-1);
	}
	if (chklabel(label))
		return -1;
	sdp->sd_boff = (unsigned short)(label->dkl_map[sip->si_boff].dkl_cylno)
	    * (unsigned short)(label->dkl_nhead * label->dkl_nsect);
	return (0);
}

/*
 * Execute reads or writes for the outside world.
 */
sdstrategy(sip, rw)
	struct saioreq *sip;
	register int rw;
{
	rw = sdcmd(rw == WRITE ? SC_WRITE : SC_READ, sip, 1);
	if (rw < 0)
		rw = 0;
	return rw;
}

/*
 * Internal interface to the disk command set
 *
 * Returns the character count read (or 1 if count==0) for success,
 * returns 0 for failure, or -1 for severe unretryable failure.
 */
int
sdcmd(cmd, sip, errprint)
	int cmd;
	register struct saioreq *sip;
	int errprint;
{
	int blkno, acount;
	register char *buf;
	register struct sdparam *sdp;
	struct scsi_cdb cdb, scdb;
	struct scsi_scb scb, sscb;
	register int retry, r, i, count;

	blkno = sip->si_bn;
	acount = sip->si_cc;
	buf = sip->si_ma;
	sdp = (struct sdparam *)sip->si_devdata;

	if (cmd == SC_WRITE)
		bcopy(buf, SDBUF, (unsigned)acount);

	/* set up cdb */
	bzero((char *) &cdb, sizeof cdb);
	cdb.cmd = cmd;
	cdb.lun = sdp->sd_unit;
	blkno += sdp->sd_boff;
	cdbaddr(&cdb, blkno);
	count = (acount + SECSIZE -1) & ~(SECSIZE-1);
	cdb.count = count / SECSIZE;
	retry = 0;
	do {
		sdp->subsip->si_cc = count;
		sdp->subsip->si_ma = SDBUF;
#ifdef SUN3
		if (sdp->sd_ha_type)
			r = sidoit(&cdb, &scb, sdp->subsip);
		else
#endif
			r = scdoit(&cdb, &scb, sdp->subsip);
		if (r < 0) 
			return -1; /* Major SCSI bus error, already printed */
		if (scb.chk) {
			bzero((char *) &scdb, sizeof scdb);
			scdb.cmd = SC_REQUEST_SENSE;
			scdb.lun = sdp->sd_unit;
			scdb.count = sizeof (struct scsi_sense);
			sdp->subsip->si_cc = scdb.count;
			sdp->subsip->si_ma = SDBUF;
#ifdef SUN3
			if (sdp->sd_ha_type)
				i = sidoit(&scdb, &sscb, sdp->subsip);
			else
#endif
				i = scdoit(&scdb, &sscb, sdp->subsip);
			if (i >= 4) {	/* all the sense Adaptec gives us */
#ifndef DEFERRED_ERRORS
				if (errprint) sd_pr_sense(SDBUF, i);
#endif
				continue;
			} else {	/* can't get sense, give up */
				if (errprint) {
					printf("sd: scsi %s\n",
#ifdef DEFERRED_ERRORS
					scerrmsg ? scerrmsg :
#endif
					"sense failed");
				}
				return (0);
			}
		} else if (scb.busy) {
			sc_error("disk busy");
			DELAY(100000);
			continue;
		}
		if (r != count) {
#ifndef DEFERRED_ERRORS
			if (errprint)
				printf("sd: dma count is %d wanted %d\n",
				    r, count);
#endif
			continue;
		}
		if (cmd == SC_READ)
			bcopy(SDBUF, buf, (unsigned)acount);
#ifdef DEFERRED_ERRORS
		scerrmsg = 0;
#endif
		return (count ? count : 1);
	} while (retry++ < 16);
#ifdef DEFERRED_ERRORS
	if (errprint) {
		if (scb.chk) {
			sd_pr_sense(SDBUF, i);
		} else if (scerrmsg) {
			printf("sd: scsi %s\n", scerrmsg);
		} else if (r != count) {
			printf("sd: dma count is %d wanted %d\n", r, count);
		} else {
			/* we should never get this far */
			printf("sd: retry count exceeded\n");
		}
	}
#endif
	return (0);
}

#ifdef SDERRORS
char	*class_00_errors[] = {
	"No sense",
	"No index signal",
	"No seek complete",
	"Write fault",
	"Drive not ready",
	"Drive not selected",
	"No track 00",
	"Multiple drives selected",
	"No address acknowledged",
	"Media not loaded",
	"Insufficient capacity",
};

char	*class_01_errors[] = {
	"I.D. CRC error",
	"Unrecoverable data error",
	"I.D. address mark not found",
	"Data address mark not found",
	"Record not found",
	"Seek error",
	"DMA timeout error",
	"Write protected",
	"Correctable data check",
	"Bad block found",
	"Interleave error",
	"Data transfer incomplete",
	"Unformatted or bad format on drive",
	"Self test failed",
	"Defective track (media errors)",
};

char	*class_02_errors[] = {
	"Invalid command",
	"Illegal block address",
	"Aborted",
	"Volume overflow",
};

char	**sc_errors[] = {
	class_00_errors,
	class_01_errors,
	class_02_errors,
	0, 0, 0, 0,
};

int	sc_errct[] = {
	sizeof class_00_errors / sizeof (char *),
	sizeof class_01_errors / sizeof (char *),
	sizeof class_02_errors / sizeof (char *),
	0, 0, 0, 0,
};

char	*sc_sense7_keys [] = {
	"No sense",
	"Recoverable error",
	"Not ready",
	"Media error",
	"Hardware error",
	"Illegal request",
	"Media change",
	"Write protect",
	"Diagnostic unique",
	"Vendor unique",
	"Power up failed",
	"Aborted command",
	"Equal",
	"Volume overflow",
};
#endif SDERRORS

/*
 * Print out sense info.
 */
sd_pr_sense(sp, len)
	register unsigned char *sp;
	register int len;
{

#ifndef SDERRORS
	printf("sd: error");
	while (--len >= 0) {
		printf(" %x", *sp++);
	}
	printf("\n");
#else  SDERRORS
#ifdef lint
	len = len;	/* Avoid spurious "len unused" messages */
#endif lint
	printf("sd: ");
	if (((struct scsi_sense *)sp)->class <= 6) {
		register struct scsi_sense *sense;

		sense = (struct scsi_sense *) sp;
		if (sense->code < sc_errct[sense->class]) {
			printf("%s", sc_errors[sense->class][sense->code]);
		} else {
			printf("error %x", *sp);
		}
		if (sense->adr_val) {
			printf("- block no. %d", (sense->high_addr << 16) |
			    (sense->mid_addr << 8) | sense->low_addr);
		}
	} else {	/* Sense class 7: the standardized one */
		register struct scsi_ext_sense *sense7;

		sense7 = (struct scsi_ext_sense *) sp;
		if (sense7->fil_mk) {
			printf("file mark ");
		}
		if (sense7->eom) {
			printf("end of medium ");
		}
		if (sense7->key 
		    < sizeof (sc_sense7_keys) / sizeof (sc_sense7_keys[0])) {
			printf("%s", sc_sense7_keys[sense7->key]);
		} else {
			printf("sense key %x", sense7->key);
		}
		printf(" block no. %x", (sense7->info_1 << 24) |
		    (sense7->info_2 << 16) | (sense7->info_3 << 8) |
		    sense7->info_4);
	}
	printf("\n");
#endif SDERRORS
}


/*
 * Close scsi disk
 *
 * We must close the host adapter too.
 */
int
sdclose(sip)
	struct saioreq *sip;
{
	devclose(((struct sdparam *)sip->si_devdata)->subsip);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.