h02041
s 00033/00045/02010
d D 1.10 94/06/22 12:57:57 hjs 16 15
c  address code review comments of various sorts; cstyle -p clean
e
s 00020/00020/02035
d D 1.9 94/06/21 12:55:36 hjs 15 14
c cstyle clean
e
s 00000/00000/02055
d D 1.8 94/06/21 12:47:22 hjs 14 13
i 11
c Merged changes between child workspace "/work/ddk/myws" and
c  parent workspace "/work/ddk/ws_ddk_494".
c 
e
s 00008/00013/02047
d D 1.7 94/06/17 13:34:44 hjs 13 12
c b_error --> bioerror()
e
s 00151/00234/01909
d D 1.6 94/06/10 12:47:11 hjs 12 6
c merged x86/sparc; cstyle-clean; uses scsi_errmsg
e
s 00013/00013/02047
d D 1.5.1.5 94/06/10 12:30:40 hjs 11 10
c use generic SCSI_ERR for scsi_errmsg
e
s 00043/00090/02017
d D 1.5.1.4 94/06/10 12:22:19 hjs 10 9
c now uses scsi_errmsg, no DDICT ifdef's ...
e
s 00011/00047/02096
d D 1.5.1.3 94/06/09 13:51:40 hjs 9 8
c works, about to address various comments
e
s 00076/00067/02067
d D 1.5.1.2 94/06/09 13:27:28 hjs 8 7
c cstyle clean
e
s 00041/00050/02093
d D 1.5.1.1 94/06/09 13:11:31 hjs 7 6
c merged, works on sparc and x86, ddict-clean
e
s 00116/00002/02027
d D 1.5 94/05/20 14:34:20 hjs 6 5
c backed in the backed-out changes
e
s 00003/00003/02026
d D 1.4 94/05/19 14:03:16 hjs 5 4
c changed b_forw to b_private
e
s 00001/00115/02028
d D 1.3 94/05/19 13:32:54 hjs 4 3
c merged for EAs
e
s 00025/00009/02118
d D 1.2 94/04/04 14:04:47 hjs 3 1
c DDICT-clean
e
s 00000/00000/00000
d R 1.2 94/03/16 14:41:32 Codemgr 2 1
c SunPro Code Manager data about conflicts, renames, etc...
c Name history : 1 0 src/driver_dev/sst/sst.c
e
s 02127/00000/00000
d D 1.1 94/03/16 14:41:31 hjs 1 0
c date and time created 94/03/16 14:41:31 by hjs
e
u
U
f e 0
t
T
I 1
/*
 * sst.c - Simple SCSI Target driver; a template character SCSA target
 *	   driver for Solaris 2.x.
 *
 * This file is a product of Sun Microsystems, Inc. and is provided for
 * unrestricted use provided that this legend is included on all tape
 * media and as a part of the software program in whole or part.  Users
 * may copy or modify this file without charge, but are not authorized to
 * license or distribute it to anyone else except as part of a product
 * or program developed by the user.
 *
 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
 *
 * This file is provided with no support and without any obligation on the
 * part of Sun Microsystems, Inc. to assist in its use, correction,
 * modification or enhancement.
 *
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS FILE
 * OR ANY PART THEREOF.
 *
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
 * or profits or other special, indirect and consequential damages, even
 * if Sun has been advised of the possibility of such damages.
 *
 * Sun Microsystems, Inc.
 * 2550 Garcia Avenue
 * Mountain View, California  94043
 *
 * ------------------------------------------------------------------
 *
 * This driver is intended as an example of programming a SCSA
 * target driver for Solaris 2.X; it is not intended for any particular
 * device.
 *
 * Areas where you may need to change this code or add your own to
 * deal with your specific device are marked "Note".
 * Other warnings are marked "WARNING"
 *
 * To compile:
 *	% cc -D_KERNEL -c sst.c
 *	% ld -r sst.o -o sst
D 9
D 12
 * WARNING: Only the -Xa and -Xt (the default) cc flags will work! The header
 *	    files don't conform to strict ANSI C; -Xs and -Xc will fail.
E 9
E 12
 *
 * To install:
 * 1. Copy the module (sst) and config file (sst.conf) into /usr/kernel/drv
 * 2. Add an entry to /etc/devlink.tab, of the form:
 *	"type=sample_driver;name=sst;minor=character        rsst\A1"
 *    This will cause devlinks(1M) to create link(s) to /devices with
 *    names of the form "/dev/rsstX" where X is the SCSI target number.
 * 3. Run add_drv(1M).
 *
D 9
D 12
 * Note: you only need to run add_drv the very first time you introduce
 *	 the driver to the system. Thereafter you can use modunload, and
 *	 just access the driver to reload it.
 *
 * Note: Modload/unload won't call the probe/attach routines. If you want
 *	 to repeat the whole thing, run rem_drv(1M) and then add_drv again.
 *
E 9
E 12
 * Setting variables
 *	Variables can be explicitly set from the /etc/system file, by
 *	adding an entry of the form
 *		"set sst:<variable name>=<value>"
 *	Alternatively, you can use adb to set variables and debug as
 *	follows:
 *		# adb -kw /dev/ksyms /dev/mem
 *	The /etc/system file is read only once at boot time, if you change
 *	it you must reboot for the change to take effect.
 */

#pragma	ident	"%Z%%M% %I%	%E% SMI"

/*
 * Includes, Declarations and Local Data
 */

#include <sys/scsi/scsi.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include "sst_def.h"

/*
 * Local Function Prototypes
 */
static int sst_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
static int sst_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
static int sst_read(dev_t dev, struct uio *uio, cred_t *cred_p);
static int sst_write(dev_t dev, struct uio *uio, cred_t *cred_p);
static int sst_ioctl(dev_t, int, int, int, cred_t *, int *);

static int sst_strategy(struct buf *bp);
static int sst_ioctl_cmd(dev_t, struct uscsi_cmd *, enum uio_seg, enum uio_seg);

static int sst_unit_ready(dev_t dev);
static void sst_done(struct scsi_target *targ, struct buf *bp);
static void sst_restart(caddr_t arg);
static void sst_callback(struct scsi_pkt *pkt);
D 8
D 12
static struct scsi_pkt *sst_make_cmd(struct scsi_target *targ, struct buf *bp, struct scsi_pkt *pktp);
D 3
void sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ, struct buf *bp, long flags);
E 3
I 3
static void sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ, struct buf *bp, long flags);
E 8
I 8
static struct scsi_pkt *sst_make_cmd(struct scsi_target *targ, struct buf *bp,
    struct scsi_pkt *pktp);
static void sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ,
    struct buf *bp, long flags);
E 8
E 12
I 12
static struct scsi_pkt *sst_make_cmd(struct scsi_target *targ, struct buf *bp,
    struct scsi_pkt *pktp);
static void sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ,
    struct buf *bp, long flags);
E 12
E 3
static int sst_handle_incomplete(struct scsi_target *targ);
static int sst_handle_arq(struct scsi_pkt *pktp, struct scsi_target *targ,
    struct buf *bp);
static int sst_handle_sense(struct scsi_target *targ, struct buf *bp);
static int sst_check_error(struct scsi_target *targ, struct buf *bp);
static void sst_log(struct scsi_device *devp, int level, const char *fmt, ...);
D 10
D 12
static void sst_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt,
								int level);
E 10
E 12
static void hex_print(char *msg, char *cp, int len);

/*
 * Local Static Data
 */
static int sst_io_time		= SST_IO_TIME;
static int sst_retry_count	= SST_RETRY_COUNT;
static void *sst_state;

/*
 * Errors at or above this level will be reported
 */
D 11
D 12
static int sst_error_reporting = SST_ERR_RETRYABLE;
E 11
I 11
static int sst_error_reporting = SCSI_ERR_RETRYABLE;
E 11
E 12
I 12
static int sst_error_reporting = SCSI_ERR_RETRYABLE;
E 12

/*
 * Enable the driver debugging code if DEBUG is defined (DEBUG also enables
 * other debugging code, e.g. ASSERT statements).
 */
#ifdef	DEBUG
#define	SST_DEBUG
#endif	DEBUG


/*
 * Debug message control
 * Debug Levels:
 *	0 = no messages
 *	1 = Errors
 *	2 = Subroutine calls & control flow
 *	3 = I/O Data (verbose!)
 * Can be set with adb or in the /etc/system file with
 * "set sst:sst_debug=<value>"
 * turn on diagnostics if DEBUG is defined (DEBUG also enables
 * other debugging code, e.g. ASSERT statements).
 */

#ifdef	SST_DEBUG
static int sst_debug = 3;
#else
static int sst_debug = 0;
#endif /* SST_DEBUG */

D 8
D 12
/* -----------------------------------------------------------------------------
E 8
I 8
/*
I 10
 * Array of commands supported by the device, suitable for
 * scsi_errmsg(9f)
 * Note: Add or remove commands here as appropriate for
 *	 your device.
 */
static struct scsi_key_strings sst_cmds[] = {
	0x00, "test unit ready",
	0x01, "rezero/rewind",
	0x03, "request sense",
	0x04, "format",
	0x05, "read block limits",
	0x07, "reassign",
	0x08, "read",
	0x0a, "write",
	0x0b, "seek",
	0x0f, "read reverse",
	0x10, "write file mark",
	0x12, "inquiry",
	0x13, "verify",
	0x14, "recover buffered data",
	0x15, "mode select",
	0x16, "reserve",
	0x17, "release",
	0x18, "copy",
	0x19, "erase tape",
	0x1a, "mode sense",
	0x1b, "start/stop/load",
	0x1e, "door lock",
	0x37, "read defect data",
	-1, NULL,
};

/*
E 10
 * -----------------------------------------------------------------------------
E 8
E 12
I 12
/*
 * Array of commands supported by the device, suitable for
 * scsi_errmsg(9f)
 * Note: Add or remove commands here as appropriate for
 *	 your device.
 */
static struct scsi_key_strings sst_cmds[] = {
	0x00, "test unit ready",
	0x01, "rezero/rewind",
	0x03, "request sense",
	0x04, "format",
	0x05, "read block limits",
	0x07, "reassign",
	0x08, "read",
	0x0a, "write",
	0x0b, "seek",
	0x0f, "read reverse",
	0x10, "write file mark",
	0x12, "inquiry",
	0x13, "verify",
	0x14, "recover buffered data",
	0x15, "mode select",
	0x16, "reserve",
	0x17, "release",
	0x18, "copy",
	0x19, "erase tape",
	0x1a, "mode sense",
	0x1b, "start/stop/load",
	0x1e, "door lock",
	0x37, "read defect data",
	-1, NULL,
};

/*
 * -----------------------------------------------------------------------------
E 12
 *	Module Loading/Unloading and Autoconfiguration Routines
 */

/*
 * Device driver ops vector - cb_ops(9s) structure
 * Device switch table fields (equivalent to the old 4.x cdevsw and bdevsw).
 * Unsupported entry points (e.g. for xxprint() and xxdump()) are set to nodev,
 * except for the poll routine, which is set to nochpoll(), a routine that
 * returns ENXIO.
 * Note	This uses ddi_prop_op for the prop_op(9e) routine. If your device
 *	has its own properties, you should implement a sst_prop_op() routine
 *	to manage them.
 */
static struct cb_ops sst_cb_ops = {
	sst_open,		/* b/c open */
	sst_close,		/* b/c close */
	sst_strategy,		/* b strategy */
	nodev,			/* b print */
	nodev,			/* b dump */
	sst_read,		/* c read */
	sst_write,		/* c write */
	sst_ioctl,		/* c ioctl */
	nodev,			/* c devmap */
	nodev,			/* c mmap */
	nodev,			/* c segmap */
	nochpoll,		/* c poll */
	ddi_prop_op,		/* cb_prop_op */
	0,			/* streamtab  */
	D_MP | D_NEW		/* Driver compatibility flag */

};


/*
 * dev_ops(9S) structure, defined in sys/devops.h.
 * Device Operations table, for autoconfiguration
 * Note	If you replace the sst_detach entry here with "nulldev", it
 *	implies that the detach is always successful. We need a real detach to
 *	free the sense packet and the unit structure. If you don't want the
 *	driver to ever be unloaded, replace the sst_detach entry with "nodev"
 *	(which always fails).
 */
static int sst_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
		void **result);
static int sst_identify(dev_info_t *dip);
static int sst_probe(dev_info_t *dip);
static int sst_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
static int sst_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);

static struct dev_ops sst_ops = {
	DEVO_REV,		/* devo_rev, */
	0,			/* refcnt  */
	sst_info,		/* info */
	sst_identify,		/* identify */
	sst_probe,		/* probe */
	sst_attach,		/* attach */
	sst_detach,		/* detach */
	nodev,			/* reset */
	&sst_cb_ops,		/* driver operations */
	(struct bus_ops *)0	/* bus operations */
};

/*
 * Module Loading and Unloading
 * See modctl.h for external structure definitions.
 */

static struct modldrv modldrv = {
	&mod_driverops,			/* Type of module (driver). */
D 6
	"SCSI Simple Target Driver, Version %I%",  /* Description */
E 6
I 6
	"SCSI Simple Target Driver, Version 1.2",  /* Description */
E 6
	&sst_ops,			/* driver ops */
};

static struct modlinkage modlinkage = {
	MODREV_1, (void *)&modldrv, NULL
};

/*
 * Tell the system that we depend on the general scsi support routines,
 * i.e the scsi "misc" module must be loaded
 */
D 16
#ifndef lint
E 16
D 3
static char _depends_on[] = "misc/scsi";
E 3
I 3
char _depends_on[] = "misc/scsi";
E 3
D 16
#endif /* lint */
E 16

/*
 * Module Installation
 * Install the driver and "pre-allocate" space for INIT_UNITS units,
 * i.e. instances of the driver.
 */
int
_init(void)
{
	int e;

	if ((e = ddi_soft_state_init(&sst_state, sizeof (struct scsi_target),
								0)) != 0) {
		SST_LOG(0, SST_CE_DEBUG2,
			"_init, ddi_soft_state_init failed: 0x%x\n", e);
		return (e);
	}

	if ((e = mod_install(&modlinkage)) != 0) {
		SST_LOG(0, SST_CE_DEBUG2,
				"_init, mod_install failed: 0x%x\n", e);
		ddi_soft_state_fini(&sst_state);
	}

	SST_LOG(0, SST_CE_DEBUG2, "_init succeeded\n");
	return (e);
}


/*
 * Module removal
 */
int
_fini(void)
{
	int e;

	if ((e = mod_remove(&modlinkage)) != 0) {
		SST_LOG(0, SST_CE_DEBUG1, "_fini mod_remove failed, 0x%x\n", e);
		return (e);
	}

	ddi_soft_state_fini(&sst_state);

	SST_LOG(0, SST_CE_DEBUG2, "_fini succeeded\n");
	return (e);
}

/*
 * Return module info
 */
int
_info(struct modinfo *modinfop)
{
	SST_LOG(0, SST_CE_DEBUG2, "_info\n");
	return (mod_info(&modlinkage, modinfop));
}

/*
 * Autoconfiguration Routines
 */

/*
 * identify(9e) - are we the right driver?
 * Called during autoconfiguration to match a found dev_info node with
 * a driver
 */
static int
sst_identify(dev_info_t *dev)
{
	SST_LOG(0, SST_CE_DEBUG2, "sst_identify: %s\n", ddi_get_name(dev));
	if (strcmp(ddi_get_name(dev), "sst") == 0) {
		return (DDI_IDENTIFIED);
	} else {
		return (DDI_NOT_IDENTIFIED);
	}
}


/*
 * probe(9e) - Check that we're talking to the right device on the SCSI bus.
 * Calls scsi_probe(9f) to see if there's a device at our target id. If
 * there is, scsi_probe will fill in the sd_inq struct (in the devp
 * scsi device struct) with the inquiry data. Validate the data here,
 * allocate a request sense packet, and start filling in the private data
 * structure.
 * Note: Probe should have no side-effects. Just check that we have the right
 *	 device, don't set up any data or initialize the device here. Also,
 *	 it's a Sun convention to probe quietly; send messages to the log
 *	 file only, not to the console.
 * Note: The host adapter driver sets up the scsi_device structure and puts
 *	 it into the dev_info structure with ddi_set_driver_private().
 * Note: No need to allow for probing/attaching in the open() routine because
 *	 of the loadability - the first reference to the device will auto-load
 *	 it, i.e. will call this routine.
 */
#define	VIDSZ		8	/* Vendor Id length in Inquiry Data */
#define	PIDSZ		16	/* Product Id length in Inquiry Data */

static int
sst_probe(dev_info_t *dip)
{
	register struct scsi_device *devp;
	int	err, rval = DDI_PROBE_FAILURE;
	int	tgt, lun;
	char	vpid[VIDSZ+PIDSZ+1];

D 16
	devp = (struct scsi_device *) ddi_get_driver_private(dip);
E 16
I 16
	devp = (struct scsi_device *)ddi_get_driver_private(dip);
E 16
	tgt = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "target", -1);
	lun = ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "lun", -1);

	SST_LOG(devp, SST_CE_DEBUG2, "sst_probe: target %d, lun %d\n",
	    tgt, lun);

	/*
	 * Call the routine scsi_probe to do some of the dirty work.
	 * This routine uses the SCSI Inquiry command to  test for the
	 * presence of the device. If it's successful, it will fill in
	 * the sd_inq field in the scsi_device structure.
	 */
	switch (err = scsi_probe(devp, NULL_FUNC)) {
	case SCSIPROBE_NORESP:
		sst_log(devp, CE_CONT, "No response from target %d, lun %d\n",
		    tgt, lun);
		rval = DDI_PROBE_FAILURE;
		break;

	case SCSIPROBE_NONCCS:
	case SCSIPROBE_NOMEM:
	case SCSIPROBE_FAILURE:
	default:
		SST_LOG(devp, SST_CE_DEBUG1,
		    "sst_probe: scsi_slave failed, 0x%x\n", err);
		rval = DDI_PROBE_FAILURE;
		break;

	case SCSIPROBE_EXISTS:
		/*
		 * Inquiry succeeded, devp->sd_inq is now filled in
		 * Note: Check inq_dtype, inq_vid, inq_pid and any other
		 *	 fields to make sure the target/unit is what's
		 *	 expected (sd_inq is a struct scsi_inquiry,
		 *	 defined in scsi/generic/inquiry.h).
		 * Note: Put device-specific checking into the appropriate
		 *	 case statement, and delete the rest.
		 * Note: The DTYPE_* defines are from <scsi/generic/inquiry.h>,
		 *	 this is the full list as of "now", check it for new
		 *	 types.
		 */
		switch (devp->sd_inq->inq_dtype) {
		case DTYPE_PROCESSOR:
		case DTYPE_OPTICAL:
		case DTYPE_DIRECT:
		case DTYPE_SEQUENTIAL:
		case DTYPE_PRINTER:
		case DTYPE_WORM:
		case DTYPE_RODIRECT:
		case DTYPE_SCANNER:
		case DTYPE_CHANGER:
		case DTYPE_COMM:
			/*
			 * Print what was found on the console. For your
			 * device, you should send the 'found' message to
			 * the system log file only, by inserting an
			 * exclamation point, "!", as the first character of
			 * the message - see cmn_err(9f).
			 */
			sst_log(devp, CE_CONT,
			    "found %s device at tgt%d, lun%d\n",
			    scsi_dname((int)devp->sd_inq->inq_dtype), tgt, lun);
			bcopy((caddr_t)devp->sd_inq->inq_vid, (caddr_t)vpid,
			    VIDSZ);
			bcopy((caddr_t)devp->sd_inq->inq_pid,
			    (caddr_t)vpid+VIDSZ, PIDSZ);
			vpid[VIDSZ+PIDSZ] = 0;
			sst_log(devp, CE_CONT, "Vendor/Product ID = %s\n",
			    vpid);
			rval = DDI_PROBE_SUCCESS;
			break;

		case DTYPE_NOTPRESENT:
			sst_log(devp, CE_NOTE,
			    "Target reports no device present\n");
			rval = DDI_PROBE_FAILURE;
			break;

		default:
			sst_log(devp, CE_NOTE,
			    "Unrecognized device type: 0x%x\n",
			    devp->sd_inq->inq_dtype);
			rval = DDI_PROBE_FAILURE;
			break;
		}
	}
	scsi_unprobe(devp);	/* it's OK to call this if scsi_probe failed */
	return (rval);
}



/*
 * Attach
 *	- create minor device nodes
 *	- initialize per-instance mutex's & condition variables
 *	- device-specific initialization (e.g. read disk label)
 */
/*ARGSUSED*/
static int
sst_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
	int			instance;
	struct	scsi_pkt	*rqpkt;
	struct scsi_target	*targ;
	struct scsi_device	*devp;
	struct buf		*bp;

	if (cmd != DDI_ATTACH) {
		SST_LOG(0, SST_CE_DEBUG1, "sst_attach: unsupported cmd 0x%x\n",
		    cmd);
		return (DDI_FAILURE);
	}

D 16
	devp = (struct scsi_device *) ddi_get_driver_private(dip);
E 16
I 16
	devp = (struct scsi_device *)ddi_get_driver_private(dip);
E 16
	instance = ddi_get_instance(dip);
	SST_LOG(devp, SST_CE_DEBUG2, "sst_attach: instance %d\n", instance);

	/*
	 * Re-probe the device to get the Inquiry data; it's used
	 * elsewhere in the driver. The Inquiry data was validated in
	 * sst_probe so there's no need to look at it again here.
	 */
	if (scsi_probe(devp, NULL_FUNC) != SCSIPROBE_EXISTS) {
		SST_LOG(0, SST_CE_DEBUG1, "sst_attach: re-probe failed\n");
		scsi_unprobe(devp);
		return (DDI_FAILURE);
	}

	if (ddi_soft_state_zalloc(sst_state, instance) != DDI_SUCCESS) {
		scsi_unprobe(devp);
		return (DDI_FAILURE);
	}

	targ = ddi_get_soft_state(sst_state, instance);
D 16
	devp->sd_private = (opaque_t) targ;
E 16
I 16
	devp->sd_private = (opaque_t)targ;
E 16

	targ->targ_sbufp = getrbuf(KM_NOSLEEP);
	if (targ->targ_sbufp == NULL) {
		goto error;
	}

	targ->targ_devp = devp;

	/*
	 * Set auto-rqsense, per-target; record whether it's allowed
	 * in targ_arq
	 */
D 9
D 12
	targ->targ_arq = scsi_ifsetcap(ROUTE(targ), "auto-rqsense", 1, 1);
E 9
I 9
	targ->targ_arq = (scsi_ifsetcap(ROUTE(targ),
	    "auto-rqsense", 1, 1) == 1) ? 1 : 0;
E 9
E 12
I 12
	targ->targ_arq = (scsi_ifsetcap(ROUTE(targ),
	    "auto-rqsense", 1, 1) == 1) ? 1 : 0;
E 12
	SST_LOG(devp, SST_CE_DEBUG2, "sst_attach: Auto Sensing %s\n",
	    targ->targ_arq ? "enabled" : "disabled");

	if (!targ->targ_arq) {
		/*
		 * Allocate a Request Sense packet
		 */
		bp = scsi_alloc_consistent_buf(&devp->sd_address, NULL,
		    SENSE_LENGTH, B_READ, NULL_FUNC, NULL);
		if (!bp) {
			goto error;
		}

		rqpkt = scsi_init_pkt(&devp->sd_address, NULL, bp, CDB_GROUP0,
D 8
D 12
		              targ->targ_arq ? sizeof (struct scsi_arq_status) : 1, 
		              0, PKT_CONSISTENT, NULL_FUNC, NULL);
E 8
I 8
		    targ->targ_arq ? sizeof (struct scsi_arq_status) : 1,
		    0, PKT_CONSISTENT, NULL_FUNC, NULL);
E 8
E 12
I 12
		    targ->targ_arq ? sizeof (struct scsi_arq_status) : 1,
		    0, PKT_CONSISTENT, NULL_FUNC, NULL);
E 12
		if (!rqpkt) {
			goto error;
		}
D 16
		devp->sd_sense = (struct scsi_extended_sense *) bp->b_un.b_addr;
E 16
I 16
		devp->sd_sense = (struct scsi_extended_sense *)bp->b_un.b_addr;
E 16

		makecom_g0(rqpkt, devp, FLAG_NOPARITY, SCMD_REQUEST_SENSE, 0,
		    SENSE_LENGTH);

		rqpkt->pkt_comp = sst_callback;
		rqpkt->pkt_time = sst_io_time;
		rqpkt->pkt_flags |= FLAG_SENSING;
		targ->targ_rqs = rqpkt;
I 6
D 7
D 12
#ifdef	sparc
E 7
I 7
D 9
/* #ifdef	sparc */
E 9
E 7
E 12
E 6
I 3
D 4
#ifdef	sparc
E 4
E 3
		targ->targ_rqbp = bp;
I 6
D 7
D 12
#endif
E 7
I 7
D 9
/* #endif */
E 9
E 7
E 12
E 6
I 3
D 4
#endif
E 4
E 3
	}

	/*
	 * Create the minor node(s), see the man page
	 * for ddi_create_minor_node(9f).
	 * The 2nd parameter is the minor node name; drvconfig(1M)
	 * appends it to the /devices entry, after the colon.
	 * The 4th parameter ('instance') is the actual minor number,
	 * put into the /devices entry's inode and passed to the driver.
	 * The 5th parameter ("sample_driver") is the node type; it's used
	 * by devlinks to match an entry in /etc/devlink.tab to create
	 * the link from /dev to /devices. The #defines are in <sys/sunddi.h>.
	 */
	if (ddi_create_minor_node(dip, "character", S_IFCHR, instance,
	    "sample_driver", 0) == DDI_FAILURE) {
		SST_LOG(0, SST_CE_DEBUG1, "Create Minor Failed\n");
		goto error;
	}

	/*
	 * Initialize the condition variables.
	 * Note: We don't need to initialize the mutex (SST_MUTEX)
	 *	 because it's actually devp->sd_mutex (in the struct
	 *	 scsi_device) and is initialized by our parent, the
	 *	 host adapter driver.
	 * Note: We don't really need targ_sbuf_cv, we could just wait
	 *	 for targ_pkt_cv instead, but it's clearer this way.
	 */
	cv_init(&targ->targ_sbuf_cv, "targ_sbuf_cv", CV_DRIVER, NULL);
	cv_init(&targ->targ_pkt_cv, "targ_pkt_cv", CV_DRIVER, NULL);

	/*
	 * Note: Do any other pre-open target initialization here,
	 *	 e.g. read/verify the disk label for a fixed-disk drive.
	 */

	ddi_report_dev(dip);
	SST_LOG(devp, SST_CE_DEBUG2, "Attached sst driver\n");
	targ->targ_state = SST_STATE_CLOSED;
	return (DDI_SUCCESS);

error:
	if (bp) {
		scsi_free_consistent_buf(bp);
	}
	if (rqpkt) {
		scsi_destroy_pkt(rqpkt);
	}
	if (targ->targ_sbufp) {
D 8
D 12
		freerbuf (targ->targ_sbufp);
E 8
I 8
		freerbuf(targ->targ_sbufp);
E 8
E 12
I 12
		freerbuf(targ->targ_sbufp);
E 12
	}
	ddi_soft_state_free(sst_state, instance);
D 16
	devp->sd_private = (opaque_t) 0;
	devp->sd_sense = (struct scsi_extended_sense *) 0;
E 16
I 16
	devp->sd_private = (opaque_t)0;
	devp->sd_sense = (struct scsi_extended_sense *)0;
E 16
	scsi_unprobe(devp);
	return (DDI_FAILURE);
}


/*
 * Detach
 * Free resources allocated in sst_attach
 * Note: If you implement a timeout routine in this driver, cancel it
 *	 here. Note that scsi_init_pkt is called with SLEEP_FUNC, so it
 *	 will wait for resources if none are available. Changing it to
 *	 a callback constitutes a timeout; however this detach routine
 *	 will be called only if the driver is not open, and there should be
 *	 no outstanding scsi_init_pkt's if we're closed.
 */
/*ARGSUSED*/
static int
sst_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
	int			instance;
	register struct scsi_device	*devp;
	register struct scsi_target	*targ;


	if (cmd != DDI_DETACH) {
		SST_LOG(0, SST_CE_DEBUG1, "sst_detach: bad cmd 0x%x\n", cmd);
		return (DDI_FAILURE);
	}

D 16
	devp = (struct scsi_device *) ddi_get_driver_private(dip);
E 16
I 16
	devp = (struct scsi_device *)ddi_get_driver_private(dip);
E 16
	instance = ddi_get_instance(dip);
	SST_LOG(devp, SST_CE_DEBUG2, "sst_detach: unit %d\n", instance);

	if ((targ = ddi_get_soft_state(sst_state, instance)) == NULL) {
		SST_LOG(devp, CE_WARN, "No Target Struct for sst%d\n",
		    instance);
		return (DDI_SUCCESS);
	}

	/*
	 * Note: Do unit-specific detaching here; e.g. shut down the device
	 */

	/*
	 * Remove other data structures allocated in sst_attach()
	 */
	cv_destroy(&targ->targ_sbuf_cv);
	cv_destroy(&targ->targ_pkt_cv);
I 6
D 7
D 12
#ifdef	sparc
E 7
I 7
D 9
/* #ifdef	sparc */
E 9
E 7
E 12
E 6
I 3
D 4
#ifdef	sparc
E 4
E 3
	if (targ->targ_rqbp) {
		scsi_free_consistent_buf(targ->targ_rqbp);
	}
I 6
D 7
D 12
#endif
E 7
I 7
D 9
/* #endif */
E 9
E 7
E 12
E 6
I 3
D 4
#endif
E 4
E 3
	if (targ->targ_rqs) {
		scsi_destroy_pkt(targ->targ_rqs);
	}
	if (targ->targ_sbufp) {
D 8
D 12
		freerbuf (targ->targ_sbufp);
E 8
I 8
		freerbuf(targ->targ_sbufp);
E 8
E 12
I 12
		freerbuf(targ->targ_sbufp);
E 12
	}
	ddi_soft_state_free(sst_state, instance);
D 16
	devp->sd_private = (opaque_t) 0;
	devp->sd_sense = (struct scsi_extended_sense *) 0;
E 16
I 16
	devp->sd_private = (opaque_t)0;
	devp->sd_sense = (struct scsi_extended_sense *)0;
E 16
	ddi_remove_minor_node(dip, NULL);
	scsi_unprobe(devp);
	return (DDI_SUCCESS);
}


D 8
D 12
/* -----------------------------------------------------------------------------
E 8
I 8
/*
 * -----------------------------------------------------------------------------
E 8
D 9
 * Unix Entry Points
E 9
I 9
 * Entry Points
E 9
E 12
I 12
/*
 * -----------------------------------------------------------------------------
 * Entry Points
E 12
 */


/*
 * open(9e)
 * Called for each open(2) call on the device.
 * Make sure the device is present and correct. Do any initialization that's
 * needed (start it up, load media, etc).
 * Note: Credp can be used to restrict access to root, by calling drv_priv(9f);
 *	 see also cred(9s).
 *	 Flag shows the access mode (read/write). Check it if the device is
 *	 read or write only, or has modes where this is relevant.
 *	 Otyp is an open type flag, see open.h.
 *
 * WARNING: Unfortunately there is a bug in SunOS 5.0 that affects driver
 * open(). The file's reference count is incremented before the driver's
 * open is called. This means that if another process closes (last close)
 * the device while we're in the open routine, the close routine will not
 * be called. If the open then fails (e.g. it's an exclusive open device),
 * the file's ref count is decremented again, but the device is now in an
 * inconsistent state - the driver thinks it's open (close was never called),
 * but it's really closed. If it is an exclusive open device, it's now
 * unusable. This is a particular problem if you want to block in the open
 * routine until someone closes the device - close will never be called!
 */
/*ARGSUSED*/
static int
sst_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
{
	register dev_t			dev = *dev_p;
	register struct scsi_target	*targ;

	SST_LOG(0, SST_CE_DEBUG2, "sst_open\n");

	/*
	 * Test the open type flag
	 */
	if (otyp != OTYP_CHR) {
		SST_LOG(0, SST_CE_DEBUG1, "Unsupported open type %d\n", otyp);
		return (EINVAL);
	}

	if ((targ = ddi_get_soft_state(sst_state, getminor(dev))) == NULL) {
		return (ENXIO);		/* invalid minor number */
	}

D 9
D 12

E 9
E 12
	/*
	 * This is an exclusive open device; fail if it's not closed.
	 * Otherwise, set the state to open - this will lock out any
	 * other access attempts. We need the mutex here because the
	 * state must not change between the test for closed and the
	 * set to open.
	 * Note	With an exclusive open device, we know that no one else
	 *	will access our data structures so strictly mutexes are
	 *	not required. However since this is an example driver, and
	 *	you may want shared access, the rest of the driver is
	 *	coded with mutexes.
	 * Note	If you need shared access, it's more complex. See bst.c
	 */
	/* SST_MUTEX(targ) returns sd_mutex in the scsi_device struct */
	mutex_enter(SST_MUTEX(targ));		/* LOCK the targ data struct */
	if (targ->targ_state != SST_STATE_CLOSED) {
D 8
D 12
		mutex_exit (SST_MUTEX(targ));
E 8
I 8
		mutex_exit(SST_MUTEX(targ));
E 8
E 12
I 12
		mutex_exit(SST_MUTEX(targ));
E 12
		return (EBUSY);
	}
	targ->targ_state = SST_STATE_OPEN;	/* lock out other accesses */
D 8
D 12
	mutex_exit (SST_MUTEX(targ));		/* UNLOCK targ data struct */
E 8
I 8
	mutex_exit(SST_MUTEX(targ));		/* UNLOCK targ data struct */
E 8
E 12
I 12
	mutex_exit(SST_MUTEX(targ));		/* UNLOCK targ data struct */
E 12

	/*
	 * Test to make sure unit still is powered on and is ready
	 * by sending the SCSI Test Unit Ready command.
	 *
	 * If this is, for instance, a CD-ROM, we may get an error on the
	 * first TUR if the disk has never been accessed (a Check Condition
	 * with extended sense data to tell us why) so do one sst_unit_ready
	 * and ignore the result.
	 */
	(void) sst_unit_ready(dev);

	if (sst_unit_ready(dev) == 0) {
		SST_LOG(0, SST_CE_DEBUG1, "sst%d_open: not ready\n",
		    getminor(dev));
		targ->targ_state = SST_STATE_CLOSED;
		return (EIO);
	}

	/*
	 * Do any other initalization work here, e.g. send
	 * Mode Sense/Select commands to get the target in the
	 * right state.
	 */

	return (0);

}


/*
 * close(9e)
 * Called on final close only, i.e. the last close(2) call.
 * Shut down the device, and mark it closed in the unit structure.
 */
/*ARGSUSED*/
static int
sst_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
{
	register struct scsi_target	*targ;

	SST_LOG(0, SST_CE_DEBUG2, "sst_close\n");

	if ((targ = ddi_get_soft_state(sst_state, getminor(dev))) == NULL) {
		return (ENXIO);
	}

	/*
	 * Note: Close processing here, eg rewind if it's a tape;
	 *	 mark offline if removable media, etc.
	 * WARNING: Since this is an exclusive open device, other
	 *	accesses will be locked out until the state is set
	 *	to closed. If you make the device shareable, you
	 *	need to cope with the open routine being called while
	 *	we're in the close routine, and vice-versa. You could
	 *	serialize open/close calls with a semaphore or with
	 *	a condition variable. See bst.c.
	 */

	targ->targ_state = SST_STATE_CLOSED;
	return (0);
}


/*
 * Device Configuration Routine
 * link instance number (unit) with dev_info structure
 */
/*ARGSUSED*/
static int
sst_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
	dev_t			dev;
	struct scsi_target	*targ;
	int			instance, error;

I 7
D 9
#if 0
E 9
E 7
	SST_LOG(0, SST_CE_DEBUG2, "sst_info\n");
I 7
D 9
#endif
E 9
E 7

	switch (infocmd) {
	case DDI_INFO_DEVT2DEVINFO:
D 16
		dev = (dev_t) arg;
E 16
I 16
		dev = (dev_t)arg;
E 16
		instance = getminor(dev);
		if ((targ = ddi_get_soft_state(sst_state, instance)) == NULL)
			return (DDI_FAILURE);
		*result = (void *) targ->targ_devp->sd_dev;
		error = DDI_SUCCESS;
		break;
	case DDI_INFO_DEVT2INSTANCE:
D 16
		*result = (void *)getminor((dev_t) arg);
E 16
I 16
		*result = (void *)getminor((dev_t)arg);
E 16
		error = DDI_SUCCESS;
		break;
	default:
		error = DDI_FAILURE;
	}
	return (error);
}


/*
 * Character (raw) read and write routines, called via read(2) and
 * write(2). These routines perform "raw" (i.e. unbuffered) i/o.
 * Just and call strategy via physio. Physio(9f) will take care of
 * address mapping and locking, and will split the transfer if ncessary,
 * based on minphys, possibly calling the strategy routine multiple times.
 */
/* ARGSUSED2 */
static int
sst_read(dev_t dev, struct uio *uio, cred_t *cred_p)
{
	SST_LOG(0, SST_CE_DEBUG2, "Read\n");
D 16
	return (physio(sst_strategy, (struct buf *) 0, dev, B_READ,
E 16
I 16
	return (physio(sst_strategy, (struct buf *)0, dev, B_READ,
E 16
	    minphys, uio));
}

/* ARGSUSED2 */
static int
sst_write(dev_t dev, struct uio *uio, cred_t *cred_p)
{
	SST_LOG(0, SST_CE_DEBUG2, "Write\n");
D 16
	return (physio(sst_strategy, (struct buf *) 0, dev, B_WRITE,
E 16
I 16
	return (physio(sst_strategy, (struct buf *)0, dev, B_WRITE,
E 16
	    minphys, uio));
}


/*
 * strategy
 * Main routine for commands to the device. since this is a character
 * device, this routine is called only from the read/write routines above,
 * and sst_ioctl_cmd for the pass through ioctl (USCSICMD).
 * The cv_wait prevents this routine from being called simultaneously by
 * two threads.
 */
static int
sst_strategy(struct buf *bp)
{
	register struct scsi_target	*targ;

	if (!(targ = ddi_get_soft_state(sst_state, getminor(bp->b_edev)))) {
		bp->b_resid = bp->b_bcount;
D 13
		bp->b_error = ENXIO;
		bp->b_flags |= B_ERROR;
E 13
I 13
		bioerror(bp, ENXIO);
E 13
		biodone(bp);
		return (0);
	}

	SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "sst_strategy\n");

	/*
	 * Wait for the current request to finish. We can safely release
	 * the mutex once we have the pkt, because anyone else calling
	 * strategy will wait here until we release it with a cv_signal.
	 */
	mutex_enter(SST_MUTEX(targ));
	while (targ->targ_pkt_busy) {
		cv_wait(&targ->targ_pkt_cv, SST_MUTEX(targ));
	}
	targ->targ_pkt_busy =  1;		/* mark busy */
	mutex_exit(SST_MUTEX(targ));

D 8
D 12
	if (((targ->targ_pkt = sst_make_cmd(targ, bp, (struct scsi_pkt *)NULL))) == NULL) {
E 8
I 8
	if (((targ->targ_pkt = sst_make_cmd(targ, bp,
	    (struct scsi_pkt *)NULL))) == NULL) {
E 8
E 12
I 12
	if (((targ->targ_pkt = sst_make_cmd(targ, bp,
	    (struct scsi_pkt *)NULL))) == NULL) {
E 12
		SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
		    "Unable to create SCSI command\n");
D 13
		bp->b_flags |= B_ERROR;
E 13
		bp->b_resid = bp->b_bcount;
D 13
		bp->b_error = EIO;
E 13
I 13
		bioerror(bp, EIO);
E 13
		biodone(bp);
I 13
		return (0);
E 13
	}

	bp->b_resid = 0;
D 13
	bp->b_flags &= ~(B_DONE|B_ERROR);
E 13

	if (scsi_transport(targ->targ_pkt) != TRAN_ACCEPT) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
		    "Command transport failed\n");
D 13
		bp->b_flags |= B_ERROR;
E 13
		bp->b_resid = bp->b_bcount;
D 13
		bp->b_error = EIO;
E 13
I 13
		bioerror(bp, EIO);
E 13
		biodone(bp);
	}

D 13

E 13
	return (0);
}


/*
 * ioctl calls.
 * Ioctls are device specific. Three are provided here as examples:
 * SSTIOC_READY: Send a Test Unit Ready command to the device. This fills
 *		 in the uscsi_cmd structure in the unit struct. The actual
 *		 cdb to be sent to the device is created here; the union
 *		 scsi_cdb is defined in /usr/include/sys/scsi/impl/commands.h.
 * SST_ERRLEV:	Change the error reporting level.
 * USCSICMD:	Pass through. Send the user-supplied command to the device. Very
 *		little checking is done - it's left up to the caller to supply
 *		a valid cdb.
 */
/* ARGSUSED3 */
static int
sst_ioctl(dev_t dev, int cmd, int arg, int flag, cred_t *cred_p, int *rval_p)
{
	register int			err = 0;
	auto struct scsi_target		*targ;
	auto struct uscsi_cmd		scmd;
	auto char			cmdblk[CDB_GROUP0];

	if ((targ = ddi_get_soft_state(sst_state, getminor(dev))) == NULL) {
		return (ENXIO);		/* invalid minor number */
	}

	SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "sst_ioctl: cmd = 0x%x\n", cmd);

	bzero((caddr_t)&scmd, sizeof (struct uscsi_cmd));

	switch (cmd) {
	case SSTIOC_READY:		/* Send a Test Unit Ready command */
		scmd.uscsi_bufaddr = 0;
		scmd.uscsi_buflen = 0;
		bzero(cmdblk, CDB_GROUP0);
D 16
		cmdblk[0] = (char) SCMD_TEST_UNIT_READY;
E 16
I 16
		cmdblk[0] = (char)SCMD_TEST_UNIT_READY;
E 16
		scmd.uscsi_flags = USCSI_DIAGNOSE|USCSI_SILENT|USCSI_WRITE;
		scmd.uscsi_cdb = cmdblk;
		scmd.uscsi_cdblen = CDB_GROUP0;

		err = sst_ioctl_cmd(dev, &scmd, UIO_SYSSPACE, UIO_SYSSPACE);
		break;

	case SSTIOC_ERRLEV:		/* Set the error reporting level */
		if (copyin((caddr_t)arg, (caddr_t)&sst_error_reporting,
		    sizeof (int))) {
			return (EFAULT);
		}
		break;

	case USCSICMD:
		/*
		* Check root permissions
		*/
		if (drv_priv(cred_p) != 0) {
			return (EPERM);
		}

		/*
		* Run a generic ucsi.h command.
		*/
		if (copyin((caddr_t)arg, (caddr_t)&scmd, sizeof (scmd))) {
			return (EFAULT);
		}

		err = sst_ioctl_cmd(dev, &scmd, UIO_USERSPACE, UIO_USERSPACE);
		if (copyout((caddr_t)&scmd, (caddr_t)arg, sizeof (scmd))) {
			err = EFAULT;
		}
		break;

	default:
		err = ENOTTY;
		break;
	}
	return (err);
}


/*
 * Run a command for user (from sst_ioctl) or from someone else in the driver.
 *
 * cdbspace is for address space of cdb; dataspace is for address space
 * of the buffer - user or kernel.
 */
static int
sst_ioctl_cmd(dev_t dev, struct uscsi_cmd *scmd,
    enum uio_seg cdbspace, enum uio_seg dataspace)
{
	caddr_t			cdb, user_cdbp;
	register int			err, rw;
	register struct buf		*bp;
	register struct scsi_target	*targ;

	if ((targ = ddi_get_soft_state(sst_state, getminor(dev))) == NULL) {
		return (ENXIO);
	}

	SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "sst_ioctl_cmd\n");

	/*
	 * The uscsi structure itself is already in kernel space (copied
	 * in by sst_ioctl, or declared there by our caller); but
	 * we need to copy in the cdb here.
	 */
D 8
D 12
	cdb = kmem_zalloc ((size_t) scmd->uscsi_cdblen, KM_SLEEP);
E 8
I 8
	cdb = kmem_zalloc((size_t) scmd->uscsi_cdblen, KM_SLEEP);
E 8
E 12
I 12
D 16
	cdb = kmem_zalloc((size_t) scmd->uscsi_cdblen, KM_SLEEP);
E 16
I 16
	cdb = kmem_zalloc((size_t)scmd->uscsi_cdblen, KM_SLEEP);
E 16
E 12
	if (cdbspace == UIO_SYSSPACE) {
D 8
D 12
		bcopy (scmd->uscsi_cdb, cdb, scmd->uscsi_cdblen);
E 8
I 8
		bcopy(scmd->uscsi_cdb, cdb, scmd->uscsi_cdblen);
E 8
E 12
I 12
		bcopy(scmd->uscsi_cdb, cdb, scmd->uscsi_cdblen);
E 12
	} else if (copyin(scmd->uscsi_cdb, cdb, (u_int) scmd->uscsi_cdblen)) {
D 16
		kmem_free(cdb, (size_t) scmd->uscsi_cdblen);
E 16
I 16
		kmem_free(cdb, (size_t)scmd->uscsi_cdblen);
E 16
		return (EFAULT);
	}

	/*
	 * The cdb pointer in the structure passed by the user is pointing
	 * to user space. We've just copied the cdb into a local buffer,
	 * so point uscsi_cdb to it now. We'll restore hte user's pointer
	 * at the end.
	 */
	user_cdbp = scmd->uscsi_cdb;	/* save the user's pointer */
	scmd->uscsi_cdb = cdb;		/* point to the local cdb buffer */
	rw = (scmd->uscsi_flags & USCSI_READ) ? B_READ : B_WRITE;

	/*
	 * Get the 'special command' buffer.
	 * First lock the targ struct; if the buffer's busy, wait for
	 * it to become free. Once we get the buffer, mark it busy to
	 * lock out other requests for it.
	 * Note	cv_wait will release the mutex, allowing other parts
	 *	of the driver to acquire it.
	 * Note	Once we have the special buffer, we can safely release
	 *	the mutex; the buffer is now busy and another thread will
	 *	block in the cv_wait until we release it. All the code
	 *	from here until we unset the busy flag is non-reentrant,
	 *	including the physio/strategy/start/callback/done thread.
	 */
	mutex_enter(SST_MUTEX(targ));
	while (targ->targ_sbuf_busy) {
		cv_wait(&targ->targ_sbuf_cv, SST_MUTEX(targ));
	}
	targ->targ_sbuf_busy = 1;
	mutex_exit(SST_MUTEX(targ));

	bp = targ->targ_sbufp;

	if (scmd->uscsi_buflen) {
		/*
		 * We're sending/receiving data; create a uio structure and
		 * call physio to do the right things.
		 */
		auto struct 	iovec	aiov;
		auto struct 	uio	auio;
		register struct uio	*uio = &auio;

D 16
		bzero((caddr_t) &auio, sizeof (struct uio));
		bzero((caddr_t) &aiov, sizeof (struct iovec));
E 16
I 16
		bzero((caddr_t)&auio, sizeof (struct uio));
		bzero((caddr_t)&aiov, sizeof (struct iovec));
E 16
		aiov.iov_base = scmd->uscsi_bufaddr;
		aiov.iov_len = scmd->uscsi_buflen;
		uio->uio_iov = &aiov;

		uio->uio_iovcnt = 1;
		uio->uio_resid = scmd->uscsi_buflen;
		uio->uio_segflg = dataspace;
		uio->uio_offset = 0;
		uio->uio_fmode = 0;

		/*
		 * Let physio do the rest...
		 */
D 5
		bp->b_forw = (struct buf *) scmd;
E 5
I 5
		bp->b_private = (void *) scmd;
E 5
		err = physio(sst_strategy, bp, dev, rw, minphys, uio);
	} else {
		/*
		 * No data transfer, we can call sst_strategy directly
		 */
D 5
		bp->b_forw = (struct buf *) scmd;
E 5
I 5
		bp->b_private = (void *) scmd;
E 5
		bp->b_flags = B_BUSY | rw;
		bp->b_edev = dev;
		bp->b_bcount = bp->b_blkno = 0;
		(void) sst_strategy(bp);
		err = biowait(bp);
	}

	/*
	 * get the status block, if any, and
	 * release any resources that we had.
	 */
	scmd->uscsi_status = 0;
	scmd->uscsi_status = SCBP_C(targ->targ_pkt);

	/*
	 * Lock the targ struct. Clearing the 'busy' flag and signalling
	 * must be made atomic.
	 */
	mutex_enter(SST_MUTEX(targ));		/* LOCK the targ struct */
D 8
D 12
     	if (targ->targ_pkt != NULL)
               scsi_destroy_pkt(targ->targ_pkt);
E 8
I 8
	if (targ->targ_pkt != NULL)
		scsi_destroy_pkt(targ->targ_pkt);
E 8
E 12
I 12
	if (targ->targ_pkt != NULL)
		scsi_destroy_pkt(targ->targ_pkt);
E 12
	targ->targ_sbuf_busy = 0;
	cv_signal(&targ->targ_sbuf_cv);		/* release the special buffer */
	targ->targ_pkt_busy = 0;
	cv_signal(&targ->targ_pkt_cv);		/* release the packet */
	mutex_exit(SST_MUTEX(targ));		/* UNLOCK the targ struct */

D 16
	kmem_free(scmd->uscsi_cdb, (size_t) scmd->uscsi_cdblen);
E 16
I 16
	kmem_free(scmd->uscsi_cdb, (size_t)scmd->uscsi_cdblen);
E 16
	scmd->uscsi_cdb = user_cdbp;	/* restore the user's pointer */
	return (err);
}


/*
 * Check to see if the unit will respond to a Test Unit Ready
 * Returns true or false
 */
static int
sst_unit_ready(dev_t dev)
{
	auto struct uscsi_cmd scmd, *com = &scmd;
	auto char	cmdblk[CDB_GROUP0];
	auto int	err;

	com->uscsi_bufaddr = 0;
	com->uscsi_buflen = 0;
	bzero(cmdblk, CDB_GROUP0);
D 16
	cmdblk[0] = (char) SCMD_TEST_UNIT_READY;
E 16
I 16
	cmdblk[0] = (char)SCMD_TEST_UNIT_READY;
E 16
	com->uscsi_flags = USCSI_DIAGNOSE|USCSI_SILENT|USCSI_WRITE;
	com->uscsi_cdb = cmdblk;
	com->uscsi_cdblen = CDB_GROUP0;

	if (err = sst_ioctl_cmd(dev, com, UIO_SYSSPACE, UIO_SYSSPACE)) {
		SST_LOG(0, SST_CE_DEBUG1, "sst_unit_ready failed: 0x%x\n", err);
		return (0);
	}
	return (1);
}


/*
 * Done with a command.
 * Start the next command and then call biodone() to tell physio or
 * sst_ioctl_cmd that this i/o has completed.
 *
 */
static void
sst_done(struct scsi_target *targ, register struct buf *bp)
{
	SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "sst_done\n");

	/*
	 * Lock the targ struct; we don't want targ_pkt to change
	 * between taking a copy of it and zeroing it.
	 */
	mutex_enter(SST_MUTEX(targ));

	/*
	 * For regular commands (i.e. not using the special buffer),
	 * free resources and clear the current request. Sst_ioctl_cmd
	 * will do its own freeing for special commands. We need the lock
	 * here because targ_pkt must not change during the operations.
	 */
	if (bp != targ->targ_sbufp) {
		scsi_destroy_pkt(targ->targ_pkt);
		targ->targ_pkt_busy = 0;
		cv_signal(&targ->targ_pkt_cv);
	}

	mutex_exit(SST_MUTEX(targ));		/* UNLOCK the targ struct */

	/*
	 * Tell interested parties that the i/o is done
	 */
	biodone(bp);
}


/*
 * Allocate resources for a SCSI command - call scsi_init_pkt to get
 * a packet and allocate DVMA resources, and create the SCSI CDB.
 *
D 9
D 12
 * On x86:
E 9
E 12
 * Also used to continue an in-progress packet; simply calls scsi_init_pkt
 * to update the DMA resources to the next chunk, and re-creates the
 * SCSI command.
 *
D 9
D 12
 * NOTE: There are differences in the DMA subsystem between the SPARC
E 9
I 9
 * Note: There are differences in the DMA subsystem between the SPARC
E 9
D 8
 *       and x86 platforms. For example, on the x86 platform, DMA uses 
E 8
I 8
 *       and x86 platforms. For example, on the x86 platform, DMA uses
E 8
E 12
I 12
 * Note: There are differences in the DMA subsystem between the SPARC
D 15
 *       and x86 platforms. For example, on the x86 platform, DMA uses
E 12
 *       physical rather than virtual addresses as a result the DMA buffer
 *       may not be contiguous.
E 15
I 15
 *	and x86 platforms. For example, on the x86 platform, DMA uses
 *	physical rather than virtual addresses as a result the DMA buffer
 *	may not be contiguous.
E 15
D 8
D 12
 * 
 *       Because of these differences, the system may not be able to fully 
 *       satisfy a DMA allocation request from the target driver with resources 
E 8
I 8
 *
 *       Because of these differences, the system may not be able to fully
 *       satisfy a DMA allocation request from the target driver with resources
E 8
E 12
I 12
 *
D 15
 *       Because of these differences, the system may not be able to fully
 *       satisfy a DMA allocation request from the target driver with resources
E 12
 *       attached to one packet. As a solution, the scsi_init_pkt() routine
 *       should be called with the PKT_DMA _PARTIAL flag to allow the system
D 8
D 12
 *       to break up the DMA request. If a single DMA allocation cannot be 
E 8
I 8
 *       to break up the DMA request. If a single DMA allocation cannot be
E 8
E 12
I 12
 *       to break up the DMA request. If a single DMA allocation cannot be
E 12
 *       done, the HBA driver sets the pkt_resid in the scsi_pkt structure
D 8
D 12
 *       to the number of bytes of DMA resources it was able to  allocate. 
E 8
I 8
 *       to the number of bytes of DMA resources it was able to  allocate.
E 8
E 12
I 12
 *       to the number of bytes of DMA resources it was able to  allocate.
E 12
 *       The target driver needs to modify the SCSI command it places into
D 8
D 12
 *       the packet for transport to request the proper amount of data specified 
E 8
I 8
 *       the packet for transport to request the proper amount of data specified
E 8
E 12
I 12
 *       the packet for transport to request the proper amount of data specified
E 12
 *       in pkt_resid. When the packet's completion routine is called, the
 *       process is repeated again.
E 15
I 15
 *	Because of these differences, the system may not be able to fully
 *	satisfy a DMA allocation request from the target driver with resources
 *	attached to one packet. As a solution, the scsi_init_pkt() routine
 *	should be called with the PKT_DMA _PARTIAL flag to allow the system
 *	to break up the DMA request. If a single DMA allocation cannot be
 *	done, the HBA driver sets the pkt_resid in the scsi_pkt structure
 *	to the number of bytes of DMA resources it was able to  allocate.
 *	The target driver needs to modify the SCSI command it places into
 *	the packet for transport to request the proper amount of data specified
 *	in pkt_resid. When the packet's completion routine is called, the
 *	process is repeated again.
E 15
D 8
D 12
 *       
E 8
I 8
 *
E 8
E 12
I 12
 *
E 12
 */
static struct scsi_pkt *
sst_make_cmd(struct scsi_target *targ, struct buf *bp, struct scsi_pkt *pkt)
{
D 5
	struct uscsi_cmd *scmd = (struct uscsi_cmd *) bp->b_forw;
E 5
I 5
D 16
	struct uscsi_cmd *scmd = (struct uscsi_cmd *) bp->b_private;
E 16
I 16
	struct uscsi_cmd *scmd = (struct uscsi_cmd *)bp->b_private;
E 16
E 5
D 3
	int		flags, tval, pktalloc = 0;
E 3
I 3
	int		flags, tval;
E 3

I 6
D 7
D 12
#ifdef	i386
E 7
E 12
	int			pktalloc = 0;
	struct sst_private	*sstprivp;

D 7
D 12
#endif

E 7
E 12
E 6
I 3
D 4
#ifdef	i386
	int			pktalloc = 0;
	struct sst_private	*sstprivp;

#endif

E 4
E 3
	SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
	    "sst_make_cmd: block %d, count=%d\n", bp->b_blkno, bp->b_bcount);

I 6
D 7
D 12
#ifdef i386
E 7
D 8
	/* 
E 8
I 8
	/*
E 8
E 12
I 12
	/*
E 12
	 * If called with pkt == NULL, this is first time, and we
D 8
D 12
	 * must allocate and initialize the packet 
 	 */
E 8
I 8
	 * must allocate and initialize the packet
	 */
E 8
E 12
I 12
	 * must allocate and initialize the packet
	 */
E 12
	if (pkt == (struct scsi_pkt *)NULL)
		pktalloc = 1;

D 7
D 12
#endif

E 7
E 12
E 6
D 4
#ifdef i386
	/* 
	 * If called with pkt == NULL, this is first time, and we
	 * must allocate and initialize the packet 
 	 */
	if (pkt == (struct scsi_pkt *)NULL)
		pktalloc = 1;

#endif

E 4
	flags = 0;

	if (bp != targ->targ_sbufp) {
		/*
		 * Allocate a packet.
		 * ROUTE(targ) is shorthand for sd_address
		 * Note that if auto request sensing is enabled, we
		 * specify the status length to hold sense data if needed
		 */
I 6
D 7
D 12
#ifdef i386
E 7
E 12
		if (pktalloc) {
D 7
D 12
#endif
E 7
E 6
D 4
#ifdef i386
		if (pktalloc) {
#endif
E 4
D 8
			pkt = scsi_init_pkt(ROUTE(targ), 
			       (struct scsi_pkt *)NULL,
			       (opaque_t)bp, 
			       CDB_GROUP1,
			       targ->targ_arq ? sizeof (struct scsi_arq_status) : 1, 
I 6
D 7
#ifdef i386
			       sizeof(struct sst_private), 0, 
#else
E 6
D 4
#ifdef i386
			       sizeof(struct sst_private), 0, 
#else
E 4
				0,0,
I 6
#endif
E 7
I 7
			       sizeof(struct sst_private), PKT_DMA_PARTIAL, 
E 7
E 6
D 4
#endif
E 4
			       SLEEP_FUNC, 0);
E 8
I 8
			pkt = scsi_init_pkt(ROUTE(targ),
			    (struct scsi_pkt *)NULL,
			    (opaque_t)bp,
			    CDB_GROUP1,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    sizeof (struct sst_private), PKT_DMA_PARTIAL,
			    SLEEP_FUNC, 0);
E 8
E 12
I 12
			pkt = scsi_init_pkt(ROUTE(targ),
			    (struct scsi_pkt *)NULL,
			    (opaque_t)bp,
			    CDB_GROUP1,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    sizeof (struct sst_private), PKT_DMA_PARTIAL,
			    SLEEP_FUNC, 0);
E 12
D 16
			if (pkt == (struct scsi_pkt *) 0) {
E 16
I 16
			if (pkt == (struct scsi_pkt *)0) {
E 16
				return (NULL);
			}
I 6
D 7
D 12
#ifdef i386
E 7
E 12
		} else {
			/*
D 8
D 12
 			 * Here we're simply calling scsi_init_pkt() for the
E 8
I 8
			 * Here we're simply calling scsi_init_pkt() for the
E 8
E 12
I 12
			 * Here we're simply calling scsi_init_pkt() for the
E 12
			 * next section of DMA resource for the current
			 * I/O request (in bp); we needn't worry about
			 * the associated lengths, or possible failure,
			 * since scsi_init_pkt() is just moving the DMA win
			 */
D 8
D 12
			pkt = scsi_init_pkt(ROUTE(targ), 
                              pkt, (opaque_t)bp,0, 
			      targ->targ_arq ? sizeof (struct scsi_arq_status) : 1, 
D 7
			      0, 0, NULL_FUNC, 0);
E 7
I 7
			      0, PKT_DMA_PARTIAL, NULL_FUNC, 0);
E 8
I 8
			pkt = scsi_init_pkt(ROUTE(targ), pkt, (opaque_t) bp, 0,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    0, PKT_DMA_PARTIAL, NULL_FUNC, 0);
E 8
E 7
E 12
I 12
D 16
			pkt = scsi_init_pkt(ROUTE(targ), pkt, (opaque_t) bp, 0,
E 16
I 16
			pkt = scsi_init_pkt(ROUTE(targ), pkt, (opaque_t)bp, 0,
E 16
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    0, PKT_DMA_PARTIAL, NULL_FUNC, 0);
E 12
		}
D 8
D 12
			
E 8
I 8

E 8
E 12
I 12

E 12
		SST_LOG(targ->targ_devp, SST_CE_DEBUG3,
		    "sst_make_cmd: pkt_resid: %d\n", pkt->pkt_resid);
E 6
D 4
#ifdef i386
		} else {
			/*
 			 * Here we're simply calling scsi_init_pkt() for the
			 * next section of DMA resource for the current
			 * I/O request (in bp); we needn't worry about
			 * the associated lengths, or possible failure,
			 * since scsi_init_pkt() is just moving the DMA win
			 */
			pkt = scsi_init_pkt(ROUTE(targ), 
                              pkt, (opaque_t)bp,0, 
			      targ->targ_arq ? sizeof (struct scsi_arq_status) : 1, 
			      0, 0, NULL_FUNC, 0);
		}
			
		SST_LOG(targ->targ_devp, SST_CE_DEBUG3,
		    "sst_make_cmd: pkt_resid: %d\n", pkt->pkt_resid);
E 4

I 6
		sstprivp = (struct sst_private *)pkt->pkt_private;

		if (pktalloc) {
			sstprivp->priv_bp = bp;
			sstprivp->priv_amtdone = 0;
I 7
			sstprivp->priv_amt = bp->b_bcount - pkt->pkt_resid;
E 7
I 12
			sstprivp->priv_amt = bp->b_bcount - pkt->pkt_resid;
E 12
		}

D 7
D 12
#endif

E 7
E 6
D 4
		sstprivp = (struct sst_private *)pkt->pkt_private;

		if (pktalloc) {
			sstprivp->priv_bp = bp;
			sstprivp->priv_amtdone = 0;
		}

#endif

E 4
D 8
                sst_fill_cdb(pkt, targ, bp, flags);
E 8
I 8
		sst_fill_cdb(pkt, targ, bp, flags);
E 8
E 12
I 12
		sst_fill_cdb(pkt, targ, bp, flags);
E 12
		pkt->pkt_flags = flags;
		tval = sst_io_time;
	} else {
		/*
		 * All special command come through sst_ioctl_cmd, which
		 * uses the uscsi interface. Just need to get the CDB
		 * from scmd and plug it in. Still call makecom_g0 because
		 * it fills in some of the pkt field for us. Its cdb
		 * manipulations will be overwritten by the bcopy.
		 */
		if (scmd->uscsi_flags & USCSI_SILENT)
			flags |= FLAG_SILENT;
		if (scmd->uscsi_flags & USCSI_DIAGNOSE)
			flags |= FLAG_DIAGNOSE;
		if (scmd->uscsi_flags & USCSI_ISOLATE)
			flags |= FLAG_ISOLATE;
		if (scmd->uscsi_flags & USCSI_NODISCON)
			flags |= FLAG_NODISCON;
		if (scmd->uscsi_flags & USCSI_NOPARITY)
			flags |= FLAG_NOPARITY;
I 6
D 7
D 12
#ifdef i386
E 7
I 7

E 7
E 12
I 12

E 12
		if (pktalloc) {
D 8
D 12
			pkt = scsi_init_pkt(ROUTE(targ), 
			        (struct scsi_pkt *)NULL, 
				bp->b_bcount ? (opaque_t)bp : 0,
				scmd->uscsi_cdblen, 
			        targ->targ_arq ? sizeof (struct scsi_arq_status) : 1, 
D 7
				sizeof(struct sst_private), 0, 
E 7
I 7
				sizeof(struct sst_private), PKT_DMA_PARTIAL, 
E 7
				SLEEP_FUNC, 0);
E 8
I 8
			pkt = scsi_init_pkt(ROUTE(targ),
			    (struct scsi_pkt *)NULL,
			    bp->b_bcount ? (opaque_t)bp : 0,
			    scmd->uscsi_cdblen,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    sizeof (struct sst_private), PKT_DMA_PARTIAL,
			    SLEEP_FUNC, 0);
E 8
E 12
I 12
			pkt = scsi_init_pkt(ROUTE(targ),
			    (struct scsi_pkt *)NULL,
			    bp->b_bcount ? (opaque_t)bp : 0,
			    scmd->uscsi_cdblen,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    sizeof (struct sst_private), PKT_DMA_PARTIAL,
			    SLEEP_FUNC, 0);
E 12
			if (!pkt) {
				return (NULL);
			}
		} else {
D 8
D 12
			pkt = scsi_init_pkt(ROUTE(targ), pkt, 
			        bp->b_bcount ? (opaque_t)bp : 0,0, 
				targ->targ_arq ? sizeof (struct scsi_arq_status) : 1,
D 7
			        0, 0, NULL_FUNC, 0);
E 7
I 7
			        0, PKT_DMA_PARTIAL, NULL_FUNC, 0);
E 8
I 8
			pkt = scsi_init_pkt(ROUTE(targ), pkt,
			    bp->b_bcount ? (opaque_t)bp : 0, 0,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    0, PKT_DMA_PARTIAL, NULL_FUNC, 0);
E 8
E 7
E 12
I 12
			pkt = scsi_init_pkt(ROUTE(targ), pkt,
			    bp->b_bcount ? (opaque_t)bp : 0, 0,
			    targ->targ_arq ?
			    sizeof (struct scsi_arq_status) : 1,
			    0, PKT_DMA_PARTIAL, NULL_FUNC, 0);
E 12
		}
D 8
D 12
		
E 8
I 8

E 8
E 12
I 12

E 12
		sstprivp = (struct sst_private *)pkt->pkt_private;
		if (pktalloc) {
			sstprivp->priv_bp = bp;
			sstprivp->priv_amtdone = 0;
I 7
			sstprivp->priv_amt = bp->b_bcount - pkt->pkt_resid;
E 7
I 12
			sstprivp->priv_amt = bp->b_bcount - pkt->pkt_resid;
E 12
		}

D 7
D 12
#endif i386
#ifdef sparc
E 6
D 4
#ifdef i386
		if (pktalloc) {
			pkt = scsi_init_pkt(ROUTE(targ), 
			        (struct scsi_pkt *)NULL, 
				bp->b_bcount ? (opaque_t)bp : 0,
				scmd->uscsi_cdblen, 
			        targ->targ_arq ? sizeof (struct scsi_arq_status) : 1, 
				sizeof(struct sst_private), 0, 
				SLEEP_FUNC, 0);
			if (!pkt) {
				return (NULL);
			}
		} else {
			pkt = scsi_init_pkt(ROUTE(targ), pkt, 
			        bp->b_bcount ? (opaque_t)bp : 0,0, 
				targ->targ_arq ? sizeof (struct scsi_arq_status) : 1,
			        0, 0, NULL_FUNC, 0);
		}
		
		sstprivp = (struct sst_private *)pkt->pkt_private;
		if (pktalloc) {
			sstprivp->priv_bp = bp;
			sstprivp->priv_amtdone = 0;
		}

#endif i386
#ifdef sparc
E 4
		pkt = scsi_init_pkt(ROUTE(targ), NULL,
			bp->b_bcount ? (opaque_t)bp : 0,
			scmd->uscsi_cdblen,
			targ->targ_arq ? sizeof (struct scsi_arq_status) : 1,
			0, 0, SLEEP_FUNC, 0);
		if (!pkt) {
			return (NULL);
		}
I 6
#endif sparc
E 7
E 12
E 6
D 4
#endif sparc
E 4
		makecom_g0(pkt, targ->targ_devp, flags, scmd->uscsi_cdb[0],
		    0, 0);
D 16
		bcopy(scmd->uscsi_cdb, (caddr_t) pkt->pkt_cdbp,
E 16
I 16
		bcopy(scmd->uscsi_cdb, (caddr_t)pkt->pkt_cdbp,
E 16
		    scmd->uscsi_cdblen);
		tval = scmd->uscsi_timeout;
	}

D 7
D 12

E 7
E 12
	pkt->pkt_comp = sst_callback;
	pkt->pkt_time = tval;

I 6
D 7
D 12
#ifdef i386
E 7
I 7
D 9
#if 0
E 7
	/* save return from scsi_init_pkt as I/O length (priv_amt) */
	sstprivp->priv_amt = pkt->pkt_resid;
D 7
#else
E 6
D 4
#ifdef i386
	/* save return from scsi_init_pkt as I/O length (priv_amt) */
	sstprivp->priv_amt = pkt->pkt_resid;
#else
E 4
	pkt->pkt_private = (opaque_t) bp;
E 7
I 6
#endif
E 6
D 4
#endif
E 4

E 9
E 12
#ifdef SST_DEBUG
	if (sst_debug > 2) {
D 16
		hex_print("sst_make_cmd, CDB", (caddr_t) pkt->pkt_cdbp, 6);
E 16
I 16
		hex_print("sst_make_cmd, CDB", (caddr_t)pkt->pkt_cdbp, 6);
E 16
	}
#endif SST_DEBUG

	return (pkt);
}


/*
 * Stuff CDB with SCSI command for current I/O request
 */

D 8
D 12
static void 
sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ, 
                     struct buf *bp, long flags)
E 8
I 8
static void
sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ, struct buf *bp,
    long flags)
E 8
E 12
I 12
static void
sst_fill_cdb(struct scsi_pkt *pkt, struct scsi_target *targ, struct buf *bp,
    long flags)
E 12
{
I 6
D 7
D 12
#ifdef i386
E 7
E 12
	struct sst_private *sstprivp;
D 7
D 12
#endif
E 7
E 12
E 6
D 4
#ifdef i386
	struct sst_private *sstprivp;
#endif
E 4
	u_int blkno, len;
	u_int com;
D 8
D 12
	int use_g1_cmd = 0;	
E 8
I 8
	int use_g1_cmd = 0;
E 8
E 12
I 12
	int use_g1_cmd = 0;
E 12

	if ((scsi_options & SCSI_OPTIONS_DR) == 0)
		flags |= FLAG_NODISCON;

I 6
D 7
D 12
#ifdef i386
E 7
E 12
	sstprivp = (struct sst_private *)(pkt->pkt_private);

	blkno = bp->b_blkno + (sstprivp->priv_amtdone >> DEV_BSHIFT);
	/* use result of scsi_init_pkt() as I/O length */
D 7
D 12
	len = pkt->pkt_resid;
#else
E 6
D 4
#ifdef i386
	sstprivp = (struct sst_private *)(pkt->pkt_private);

	blkno = bp->b_blkno + (sstprivp->priv_amtdone >> DEV_BSHIFT);
	/* use result of scsi_init_pkt() as I/O length */
	len = pkt->pkt_resid;
#else
E 4
	blkno = bp->b_blkno;
	len = bp->b_bcount;
I 6
#endif
E 7
I 7
	len = sstprivp->priv_amt; /* pkt->pkt_resid; */
E 7
E 6
D 4
#endif
E 4
D 8
	
E 8
I 8

E 8
E 12
I 12
	len = sstprivp->priv_amt; /* pkt->pkt_resid; */

E 12
	SST_LOG(targ->targ_devp, SST_CE_DEBUG3,
	    "sst_fill_cdb: blkno %x len %x\n", blkno, len);
	/*
	 * Note: We use the group 0 Read/Write commands here
D 15
	 *       unless the starting block number or blocks
D 8
D 12
	 *  	 requested is too large.
E 8
I 8
	 *       requested is too large.
E 8
E 12
I 12
	 *       requested is too large.
E 12
	 *	 If your device needs different commands for normal
	 *	 data transfer (e.g. Send/Receive, read/write buffer),
	 *	 change it here.
E 15
I 15
	 *	unless the starting block number or blocks
	 *	requested is too large.
	 *	If your device needs different commands for normal
	 *	data transfer (e.g. Send/Receive, read/write buffer),
	 *	change it here.
E 15
	 */

	if ((blkno > 0x1FFFFF) || ((len >> DEV_BSHIFT) > 0xFF)) {

		SST_LOG(targ->targ_devp, SST_CE_DEBUG3,
		    "sst_make_cmd: using g1 command\n");
		com = (bp->b_flags & B_READ) ? SCMD_READ_G1 : SCMD_WRITE_G1;
		use_g1_cmd = 1;
	} else {
		com = (bp->b_flags & B_READ) ? SCMD_READ : SCMD_WRITE;
	}

	/*
	 * Note: The CDB creation differs for sequential and
	 *	 direct access devices. We do both here, but
	 *	 you should need only one. For sequential access,
	 *	 we assume a fixed 512 byte block size. If you
	 *	 have a variable block size device, ask for the
	 *	 actual number of bytes wanted, and change the last
	 *	 parameter, 'fixbit' (1) to zero.
	 */
D 8
D 12
	if (targ->targ_devp->sd_inq->inq_dtype == DTYPE_DIRECT || 
E 8
I 8
	if (targ->targ_devp->sd_inq->inq_dtype == DTYPE_DIRECT ||
E 8
E 12
I 12
	if (targ->targ_devp->sd_inq->inq_dtype == DTYPE_DIRECT ||
E 12
	    targ->targ_devp->sd_inq->inq_dtype == DTYPE_RODIRECT) {
		if (use_g1_cmd)
			makecom_g1(pkt, targ->targ_devp, flags, com,
			    blkno, len >> DEV_BSHIFT);
		else
			makecom_g0(pkt, targ->targ_devp, flags, com,
			    blkno, len >> DEV_BSHIFT);
	} else {
		makecom_g0_s(pkt, targ->targ_devp, flags, com,
		    len >> DEV_BSHIFT,
		    1);		/* 'fixbit': fixed block size */
	}
}


D 8
D 12
/* -----------------------------------------------------------------------------
E 8
I 8
/*
 * -----------------------------------------------------------------------------
E 8
E 12
I 12
/*
 * -----------------------------------------------------------------------------
E 12
 * Interrupt Service Routines
 */

/*
 * Restart a command - the device was either busy or not ready
 */
static void
sst_restart(caddr_t arg)
{
D 16
	struct scsi_target	*targ = (struct scsi_target *) arg;
E 16
I 16
	struct scsi_target	*targ = (struct scsi_target *)arg;
E 16
	struct scsi_pkt		*pkt;
	struct buf		*bp;

	SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "sst_restart\n");

	/*
	 * No need to lock the targ structure because any other threads
	 * will wait in sst_strategy for the packet.
	 */
	pkt = targ->targ_pkt;
D 16
	bp = (struct buf *) pkt->pkt_private;
E 16
I 16
	bp = (struct buf *)pkt->pkt_private;
E 16

	if (bp) {
		struct scsi_pkt *pkt = targ->targ_pkt;

		if (pkt->pkt_flags & FLAG_SENSING) {
			pkt = targ->targ_rqs;
		}

		if (scsi_transport(pkt) != TRAN_ACCEPT) {
			bp->b_resid = bp->b_bcount;
D 13
			bp->b_flags |= B_ERROR;
E 13
I 13
			bioerror(bp, ENXIO);
E 13
			sst_done(targ, bp);
		}
	}
}

I 6

E 6
D 4

E 4
/*
 * Command completion processing, called by the host adapter driver
 * when it's done with the command.
 * No need for mutexes in this routine - there's only one active command
 * at a time, anyone else wanting to send a command will wait in strategy
 * until we call sst_done.
 */
static void
sst_callback(struct scsi_pkt *pkt)
{
	struct scsi_target	*targ;
	struct buf		*bp;
	int			action;
I 7
	struct sst_private	*sstprivp;
E 7
I 12
	struct sst_private	*sstprivp;
E 12

I 4
D 6

E 6
E 4
D 7
D 12
	bp = (struct buf *) pkt->pkt_private;
E 7
I 7
	sstprivp = (struct sst_private *)pkt->pkt_private;
	bp = sstprivp->priv_bp;
E 7
E 12
I 12
	sstprivp = (struct sst_private *)pkt->pkt_private;
	bp = sstprivp->priv_bp;
E 12
	targ = ddi_get_soft_state(sst_state, getminor(bp->b_edev));

	SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
	"sst_callback: pkt_reason = 0x%x, pkt_flags = 0x%x, pkt_state = 0x%x\n",
	    pkt->pkt_reason, pkt->pkt_flags, pkt->pkt_state);

I 16
	mutex_enter(SST_MUTEX(targ));

E 16
	if (pkt->pkt_reason != CMD_CMPLT) {
		/*
		 * The command did not complete. Retry if possible.
		 */
		action = sst_handle_incomplete(targ);
	} else if (targ->targ_arq && pkt->pkt_state & STATE_ARQ_DONE) {
		/*
		 * The auto-rqsense happened, and the packet has a
		 * filled-in scsi_arq_status structure, pointed to by
		 * pkt_scbp.
		 */
		action = sst_handle_arq(pkt, targ, bp);
	} else if (pkt->pkt_flags & FLAG_SENSING) {
		/*
		 * We were running a REQUEST SENSE. Decode the
		 * sense data and decide what to do next.
		 */
		pkt = targ->targ_pkt;	/* get the pkt for the orig command */
		pkt->pkt_flags &= ~FLAG_SENSING;
		action = sst_handle_sense(targ, bp);
	} else {
		/*
		 * Command completed and we're not getting sense. Check
		 * for errors and decide what to do next.
		 */
		action = sst_check_error(targ, bp);
	}
I 16
	mutex_exit(SST_MUTEX(targ));
E 16

	switch (action) {
	case QUE_SENSE:
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Getting Sense\n");
		pkt->pkt_flags |= FLAG_SENSING;
D 16
		targ->targ_rqs->pkt_private = (opaque_t) bp;
E 16
I 16
		targ->targ_rqs->pkt_private = (opaque_t)bp;
E 16
		bzero((caddr_t)targ->targ_devp->sd_sense, SENSE_LENGTH);
		if (scsi_transport(targ->targ_rqs) == TRAN_ACCEPT) {
			break;
		}
		SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
		    "Request Sense transport failed\n");
		/*FALLTHROUGH*/
	case COMMAND_DONE_ERROR:
		bp->b_resid = bp->b_bcount;
D 13
		bp->b_flags |= B_ERROR;
E 13
I 13
		bioerror(bp, ENXIO);
E 13
		/*FALLTHROUGH*/
	case COMMAND_DONE:
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Command Done\n");
		sst_done(targ, bp);
		break;

	case QUE_COMMAND:
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Retrying Command\n");
		if (scsi_transport(targ->targ_pkt) != TRAN_ACCEPT) {
			SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
			    "Retry transport failed\n");
			bp->b_resid = bp->b_bcount;
D 13
			bp->b_flags |= B_ERROR;
E 13
I 13
			bioerror(bp, ENXIO);
E 13
			sst_done(targ, bp);
			return;
		}
		break;
	case JUST_RETURN:
		break;
I 6
D 7
D 12
#ifdef i386
E 7
I 7

E 7
E 12
I 12

E 12
	case CONTINUE_PKT:
		/*
		 * Back from a chunk of a split-up bp.  Do next chunk or
		 * finish up.
		 */
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Continuing packet\n");
		(void) sst_make_cmd(targ, bp, pkt);
		if (scsi_transport(pkt) != TRAN_ACCEPT) {
			SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
			    "Command transport failedn");
D 13
			bp->b_flags |= B_ERROR;
E 13
			bp->b_resid = bp->b_bcount;
D 13
			bp->b_error = EIO;
E 13
I 13
			bioerror(bp, EIO);
E 13
			biodone(bp);
		}
D 7
D 12
#endif
E 7
E 12
E 6
D 4
#ifdef i386
	case CONTINUE_PKT:
		/*
		 * Back from a chunk of a split-up bp.  Do next chunk or
		 * finish up.
		 */
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Continuing packet\n");
D 3
		sst_make_cmd(targ, bp, pkt);
		if ((i = scsi_transport(pkt)) != TRAN_ACCEPT) {
E 3
I 3
		(void) sst_make_cmd(targ, bp, pkt);
		if (scsi_transport(pkt) != TRAN_ACCEPT) {
E 3
			SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
D 3
			    "Command transport failed: %d\n", i);
E 3
I 3
			    "Command transport failedn");
E 3
			bp->b_flags |= B_ERROR;
			bp->b_resid = bp->b_bcount;
			bp->b_error = EIO;
			biodone(bp);
		}
#endif
E 4
	}

}


/*
 * Incomplete command handling. Figure out what to do based on
 * how far the command did get.
 */
static int
sst_handle_incomplete(struct scsi_target *targ)
{
	register int	rval = COMMAND_DONE_ERROR;
	register struct scsi_pkt	*pkt = targ->targ_pkt;

	if (!targ->targ_arq && pkt->pkt_flags & FLAG_SENSING) {
		pkt = targ->targ_rqs;
	}

	/*
	 * The target may still be running the  command,
	 * so try and reset it, to get it into a known state.
	 * Note: This is forcible, there may be a more polite
	 *	 method for your device.
D 16
	 * WARNING: If the targets reset fails, we give up, we do
	 *	not reset the entire bus! Resetting the bus can
	 *	have grave effects if the system disk is on it.
	 *	Just give up, print a message and let the user
	 *	decide what to do. If your device is critical to the
	 *	system's operation, you can reset the bus by #define-ing
	 *	SCSI_BUS_RESET. However this is not recommended. Note that
	 *	the bus can also be reset in sst_check_error().
E 16
	 */
	if ((pkt->pkt_statistics &
	    (STAT_BUS_RESET|STAT_DEV_RESET|STAT_ABORTED)) == 0) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG1, "Aborting Command\n");
D 16
		if (!(scsi_abort(ROUTE(targ), (struct scsi_pkt *) 0))) {
E 16
I 16
		if (!(scsi_abort(ROUTE(targ), (struct scsi_pkt *)0))) {
E 16
			SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
			    "Resetting Target\n");
			if (!(scsi_reset(ROUTE(targ), RESET_TARGET))) {
D 16
#ifdef SCSI_BUS_RESET
E 16
				SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
				    "Resetting SCSI Bus\n");
				if (!scsi_reset(ROUTE(targ), RESET_ALL)) {
					sst_log(targ->targ_devp, CE_WARN,
					    "SCSI bus reset failed\n");
				}
D 16
#else SCSI_BUS_RESET
				sst_log(targ->targ_devp, CE_WARN,
				    "Reset Target failed\n");
#endif SCSI_BUS_RESET
E 16
				return (COMMAND_DONE_ERROR);
			}
		}
	}

	/*
	 * If we were running a request sense, try it again if possible.
	 * Some devices can handle retries, others will not.
	 */
	if (pkt->pkt_flags & FLAG_SENSING) {
		if (targ->targ_retry_ct++ < sst_retry_count) {
			rval = QUE_SENSE;
		}
	} else if (targ->targ_retry_ct++ < sst_retry_count) {
		rval = QUE_COMMAND;
	} else {
		rval = COMMAND_DONE_ERROR;
	}

	SST_LOG(targ->targ_devp, SST_CE_DEBUG1, "Cmd incomplete, %s\n",
	    (rval == COMMAND_DONE_ERROR) ? "giving up" : "retrying");

	return (rval);
}


/*
 * Decode sense data
 */
static int
sst_handle_sense(struct scsi_target *targ, struct buf *bp)
{
	struct scsi_pkt	*rqpkt = targ->targ_rqs;
	register	rval = COMMAND_DONE_ERROR;
	int		level, amt;


	if (SCBP(rqpkt)->sts_busy) {
		if (targ->targ_retry_ct++ < sst_retry_count) {
D 8
D 12
			(void) timeout (sst_restart, (caddr_t)targ,
E 8
I 8
			(void) timeout(sst_restart, (caddr_t)targ,
E 8
E 12
I 12
			(void) timeout(sst_restart, (caddr_t)targ,
E 12
			    SST_BSY_TIMEOUT);
			rval = JUST_RETURN;
		}
		SST_LOG(targ->targ_devp, SST_CE_DEBUG1, "Target Busy, %s\n",
		    (rval == JUST_RETURN) ? "restarting" : "giving up");
		return (rval);
	}

	if (SCBP(rqpkt)->sts_chk) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
		    "Check Condition on Request Sense!\n");
		return (rval);
	}

	amt = SENSE_LENGTH - rqpkt->pkt_resid;
	if ((rqpkt->pkt_state & STATE_XFERRED_DATA) == 0 || amt == 0) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "no sense data\n");
		return (rval);
	}

	/*
	 * Now, check to see whether we got enough sense data to make any
	 * sense out if it (heh-heh).
	 */
	if (amt < SUN_MIN_SENSE_LENGTH) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
		    "not enough sense data\n");
		return (rval);
	}

	if (sst_debug > 2) {
		hex_print("sst Sense Data", (caddr_t)targ->targ_devp->sd_sense,
		    SENSE_LENGTH);
	}

	/*
	 * Decode the sense data
	 * Note: We only looking at the sense key here. Most devices
	 *	 have unique additional sense codes & qualifiers, so
	 *	 it's often more useful to look at them instead.
	 *
	 */
	switch (targ->targ_devp->sd_sense->es_key) {
	case KEY_NOT_READY:
		/*
		 * If we get a not-ready indication, wait a bit and
		 * try it again, unless this is a special command with
		 * the 'fail on error' (FLAG_DIAGNOSE) option set.
		 */
		if ((bp == targ->targ_sbufp) &&
		    (targ->targ_pkt->pkt_flags & FLAG_DIAGNOSE)) {
			rval = COMMAND_DONE_ERROR;
D 11
D 12
			level = SST_ERR_FATAL;
E 11
I 11
			level = SCSI_ERR_FATAL;
E 11
D 8
		} else if (targ->targ_retry_ct++ < sst_retry_count){
E 8
I 8
		} else if (targ->targ_retry_ct++ < sst_retry_count) {
E 8
E 12
I 12
			level = SCSI_ERR_FATAL;
		} else if (targ->targ_retry_ct++ < sst_retry_count) {
E 12
			(void) timeout(sst_restart, (caddr_t)targ,
			    SST_BSY_TIMEOUT);
			rval = JUST_RETURN;
D 11
D 12
			level = SST_ERR_RETRYABLE;
E 11
I 11
			level = SCSI_ERR_RETRYABLE;
E 11
E 12
I 12
			level = SCSI_ERR_RETRYABLE;
E 12
		} else {
			rval = COMMAND_DONE_ERROR;
D 11
D 12
			level = SST_ERR_FATAL;
E 11
I 11
			level = SCSI_ERR_FATAL;
E 11
E 12
I 12
			level = SCSI_ERR_FATAL;
E 12
		}
		break;

	case KEY_ABORTED_COMMAND:
	case KEY_UNIT_ATTENTION:
		rval = QUE_COMMAND;
D 11
D 12
		level = SST_ERR_INFORMATIONAL;
E 11
I 11
		level = SCSI_ERR_INFO;
E 11
E 12
I 12
		level = SCSI_ERR_INFO;
E 12
		break;
	case KEY_RECOVERABLE_ERROR:
	case KEY_NO_SENSE:
		rval = COMMAND_DONE;
D 11
D 12
		level = SST_ERR_RECOVERED;
E 11
I 11
		level = SCSI_ERR_RECOVERED;
E 11
E 12
I 12
		level = SCSI_ERR_RECOVERED;
E 12
		break;
	case KEY_HARDWARE_ERROR:
	case KEY_MEDIUM_ERROR:
	case KEY_MISCOMPARE:
	case KEY_VOLUME_OVERFLOW:
	case KEY_WRITE_PROTECT:
	case KEY_BLANK_CHECK:
	case KEY_ILLEGAL_REQUEST:
	default:
		rval = COMMAND_DONE_ERROR;
D 11
D 12
		level = SST_ERR_FATAL;
E 11
I 11
		level = SCSI_ERR_FATAL;
E 11
E 12
I 12
		level = SCSI_ERR_FATAL;
E 12
		break;
	}

	/*
	 * If this was for a special command, check the options
	 */
	if (bp == targ->targ_sbufp) {
		if ((rval == QUE_COMMAND) &&
		    (targ->targ_pkt->pkt_flags & FLAG_DIAGNOSE)) {
			rval = COMMAND_DONE_ERROR;
		}
		if (((targ->targ_pkt->pkt_flags & FLAG_SILENT) == 0) ||
		    sst_debug) {
D 10
D 12
			sst_errmsg(targ->targ_devp, targ->targ_pkt, level);
E 10
I 10
			scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
			    level, bp->b_blkno, 0, sst_cmds,
			    targ->targ_devp->sd_sense);
E 10
E 12
I 12
			scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
			    level, bp->b_blkno, 0, sst_cmds,
			    targ->targ_devp->sd_sense);
E 12
		}
	} else if ((level >= sst_error_reporting) || sst_debug) {
D 10
D 12
		sst_errmsg(targ->targ_devp, targ->targ_pkt, level);
E 10
I 10
		scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
		    level, bp->b_blkno, 0, sst_cmds, targ->targ_devp->sd_sense);
E 10
E 12
I 12
		scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
		    level, bp->b_blkno, 0, sst_cmds, targ->targ_devp->sd_sense);
E 12
	}

	return (rval);
}


#define	ARQP(pktp) 	((struct scsi_arq_status *)((pktp)->pkt_scbp))

/*
 * Decode auto-rqsense data
 */
static int
sst_handle_arq(struct scsi_pkt *pktp, struct scsi_target *targ, struct buf *bp)
{
	int	level, amt, rval = COMMAND_DONE_ERROR;

	SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Auto Request Sense done\n");

	if (ARQP(pktp)->sts_rqpkt_status.sts_chk) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
		    "Check Condition on Auto Request Sense!\n");
		return (rval);
	}

	amt = SENSE_LENGTH - ARQP(pktp)->sts_rqpkt_resid;
	if ((ARQP(pktp)->sts_rqpkt_state & STATE_XFERRED_DATA) == 0 ||
	    amt == 0) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "no auto sense data\n");
		return (rval);
	}

	/*
	 * Stuff the sense data pointer into sd_sense
	 */
	targ->targ_devp->sd_sense = &(ARQP(pktp)->sts_sensedata);

	/*
	 * Now, check to see whether we got enough sense data to make any
	 * sense out if it (heh-heh).
	 */
	if (amt < SUN_MIN_SENSE_LENGTH) {
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
		    "not enough auto sense data\n");
		return (rval);
	}

	if (sst_debug > 2) {
		hex_print("sst Auto Sense Data",
		    (caddr_t)&(ARQP(pktp)->sts_sensedata), SENSE_LENGTH);
	}

	/*
	 * Decode the sense data
	 * Note: I'm only looking at the sense key here. Most devices
	 *	 have unique additional sense codes & qualifiers, so
	 *	 it's often more useful to look at them instead.
	 *
	 */
	switch (ARQP(pktp)->sts_sensedata.es_key) {
	case KEY_NOT_READY:
		/*
		 * If we get a not-ready indication, wait a bit and
		 * try it again, unless this is a special command with
		 * the 'fail on error' (FLAG_DIAGNOSE) option set.
		 */
		if ((bp == targ->targ_sbufp) &&
		    (targ->targ_pkt->pkt_flags & FLAG_DIAGNOSE)) {
			rval = COMMAND_DONE_ERROR;
D 11
D 12
			level = SST_ERR_FATAL;
E 11
I 11
			level = SCSI_ERR_FATAL;
E 11
D 8
		} else if (targ->targ_retry_ct++ < sst_retry_count){
E 8
I 8
		} else if (targ->targ_retry_ct++ < sst_retry_count) {
E 8
E 12
I 12
			level = SCSI_ERR_FATAL;
		} else if (targ->targ_retry_ct++ < sst_retry_count) {
E 12
			(void) timeout(sst_restart, (caddr_t)targ,
			    SST_BSY_TIMEOUT);
			rval = JUST_RETURN;
D 11
D 12
			level = SST_ERR_RETRYABLE;
E 11
I 11
			level = SCSI_ERR_RETRYABLE;
E 11
E 12
I 12
			level = SCSI_ERR_RETRYABLE;
E 12
		} else {
			rval = COMMAND_DONE_ERROR;
D 11
D 12
			level = SST_ERR_FATAL;
E 11
I 11
			level = SCSI_ERR_FATAL;
E 11
E 12
I 12
			level = SCSI_ERR_FATAL;
E 12
		}
		break;

	case KEY_ABORTED_COMMAND:
	case KEY_UNIT_ATTENTION:
		rval = QUE_COMMAND;
D 11
D 12
		level = SST_ERR_INFORMATIONAL;
E 11
I 11
		level = SCSI_ERR_INFO;
E 11
E 12
I 12
		level = SCSI_ERR_INFO;
E 12
		break;
	case KEY_RECOVERABLE_ERROR:
	case KEY_NO_SENSE:
		rval = COMMAND_DONE;
D 11
D 12
		level = SST_ERR_RECOVERED;
E 11
I 11
		level = SCSI_ERR_RECOVERED;
E 11
E 12
I 12
		level = SCSI_ERR_RECOVERED;
E 12
		break;
	case KEY_HARDWARE_ERROR:
	case KEY_MEDIUM_ERROR:
	case KEY_MISCOMPARE:
	case KEY_VOLUME_OVERFLOW:
	case KEY_WRITE_PROTECT:
	case KEY_BLANK_CHECK:
	case KEY_ILLEGAL_REQUEST:
	default:
		rval = COMMAND_DONE_ERROR;
D 11
D 12
		level = SST_ERR_FATAL;
E 11
I 11
		level = SCSI_ERR_FATAL;
E 11
E 12
I 12
		level = SCSI_ERR_FATAL;
E 12
		break;
	}

	/*
	 * If this was for a special command, check the options
	 */
	if (bp == targ->targ_sbufp) {
		if ((rval == QUE_COMMAND) &&
		    (targ->targ_pkt->pkt_flags & FLAG_DIAGNOSE)) {
			rval = COMMAND_DONE_ERROR;
		}
		if (((targ->targ_pkt->pkt_flags & FLAG_SILENT) == 0) ||
		    sst_debug) {
D 10
D 12
			sst_errmsg(targ->targ_devp, targ->targ_pkt, level);
E 10
I 10
			scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
			    level, bp->b_blkno, 0, sst_cmds,
			    targ->targ_devp->sd_sense);
E 10
E 12
I 12
			scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
			    level, bp->b_blkno, 0, sst_cmds,
			    targ->targ_devp->sd_sense);
E 12
		}
	} else if ((level >= sst_error_reporting) || sst_debug) {
D 10
D 12
		sst_errmsg(targ->targ_devp, targ->targ_pkt, level);
E 10
I 10
		scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
		    level, bp->b_blkno, 0, sst_cmds, targ->targ_devp->sd_sense);
E 10
E 12
I 12
		scsi_errmsg(targ->targ_devp, targ->targ_pkt, "sst",
		    level, bp->b_blkno, 0, sst_cmds, targ->targ_devp->sd_sense);
E 12
	}

	return (rval);
}


/*
 * Command completion routine. Check the returned status of the
 * command
 */
static int
sst_check_error(struct scsi_target *targ, struct buf *bp)
{
	struct scsi_pkt	*pkt = targ->targ_pkt;
	int		action;
I 7
	struct sst_private *sstprivp = (struct sst_private *)(pkt->pkt_private);
E 7
I 12
	struct sst_private *sstprivp = (struct sst_private *)(pkt->pkt_private);
E 12

	if (SCBP(pkt)->sts_busy) {
		/*
		 * Target was busy. If we're not out of retries, call
		 * timeout to restart in a bit; otherwise give up and
		 * reset the target. If the fail on error flag is
		 * set, give up immediately.
		 */
		int tval = (pkt->pkt_flags & FLAG_DIAGNOSE) ? 0
							    : SST_BSY_TIMEOUT;

		if (SCBP(pkt)->sts_is) {
			/*
			 * Implicit assumption here is that a device
			 * will only be reserved long enough to
			 * permit a single i/o operation to complete.
			 */
			tval = sst_io_time * drv_usectohz(1000000);
		}

D 16
		if ((int) targ->targ_retry_ct++ < sst_retry_count) {
E 16
I 16
		if ((int)targ->targ_retry_ct++ < sst_retry_count) {
E 16
			if (tval) {
				(void) timeout(sst_restart, (caddr_t)targ,
				    tval);
				action = JUST_RETURN;
				SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
				    "Target busy, retrying\n");
			} else {
				action = COMMAND_DONE_ERROR;
				SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
				    "Target busy, no retries\n");
			}
		} else {
			/*
			 * WARNING: See the warning in sst_handle_incomplete
			 */
			SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
			    "Resetting Target\n");
			if (!scsi_reset(ROUTE(targ), RESET_TARGET)) {
#ifdef SCSI_BUS_RESET
				SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
				    "Resetting SCSI Bus\n");
				if (!scsi_reset(ROUTE(targ), RESET_ALL)) {
					sst_log(targ->targ_devp, CE_WARN,
					    "SCSI bus reset failed\n");
				}
#else SCSI_BUS_RESET
				sst_log(targ->targ_devp, CE_WARN,
				    "Reset Target failed\n");
#endif SCSI_BUS_RESET
			}
			action = COMMAND_DONE_ERROR;
		}
	} else if (SCBP(pkt)->sts_chk) {
		action = QUE_SENSE;	/* check condition - get sense */
		if (targ->targ_arq) {
			SST_LOG(targ->targ_devp, SST_CE_DEBUG1,
			    "Check Condition with Auto Sense enabled!\n");
		} else {
			SST_LOG(targ->targ_devp, SST_CE_DEBUG2,
			    "Check Condition\n");
		}
	} else {
I 7
D 9
#if 0
E 7
D 12
		action = COMMAND_DONE;	/* assume command completed OK */

E 12
I 12
		targ->targ_retry_ct = 0;
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Command Complete\n");
E 12
		/*
		 * pkt_resid will reflect, at this point, a residual
		 * of how many bytes were not transferred; a non-zero
		 * pkt_resid is an error.
D 12
		 * Note: This error is declared only by the driver, it's
		 * not a SCSI error.
E 12
		 */
		if (pkt->pkt_resid) {
			action = COMMAND_DONE_ERROR;
			bp->b_resid += pkt->pkt_resid;
I 12
		} else {
			sstprivp->priv_amtdone += sstprivp->priv_amt;
			if (sstprivp->priv_amtdone < bp->b_bcount)
				action = CONTINUE_PKT;
			else
				action = COMMAND_DONE;
E 12
		}
E 9
D 12
		targ->targ_retry_ct = 0;
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Command Complete\n");
I 7
D 9
#else

		targ->targ_retry_ct = 0;
		SST_LOG(targ->targ_devp, SST_CE_DEBUG2, "Command Complete\n");
E 9
		/*
		 * pkt_resid will reflect, at this point, a residual
		 * of how many bytes were not transferred; a non-zero
		 * pkt_resid is an error.
		 */
		if (pkt->pkt_resid) {
			action = COMMAND_DONE_ERROR;
			bp->b_resid += pkt->pkt_resid;
		} else {
			sstprivp->priv_amtdone += sstprivp->priv_amt;
D 8
			if (sstprivp->priv_amtdone < bp->b_bcount) 
				action = CONTINUE_PKT;	
E 8
I 8
			if (sstprivp->priv_amtdone < bp->b_bcount)
				action = CONTINUE_PKT;
E 8
			else
				action = COMMAND_DONE;
		}
D 9
#endif
E 9
E 7
E 12
	}
	return (action);
}


D 8
D 12
/* -----------------------------------------------------------------------------
E 8
I 8
/*
 * -----------------------------------------------------------------------------
E 8
E 12
I 12
/*
 * -----------------------------------------------------------------------------
E 12
 *	Error Message Data and Routines
 */

/*
 * Log a message to the console and/or syslog with cmn_err
 */
/*ARGSUSED*/
static void
sst_log(struct scsi_device *devp, int level, const char *fmt, ...)
{
	auto char name[16];
	auto char buf[256];
	va_list ap;

	if (devp) {
		(void) sprintf(name, "%s%d", ddi_get_name(devp->sd_dev),
		    ddi_get_instance(devp->sd_dev));
	} else {
		(void) sprintf(name, "sst");
	}

	va_start(ap, fmt);
	(void) vsprintf(buf, fmt, ap);
	va_end(ap);

	switch (level) {
	case CE_CONT:
	case CE_NOTE:
	case CE_WARN:
	case CE_PANIC:
		cmn_err(level, "%s:\t%s", name, buf);
		break;

	case SST_CE_DEBUG4: if (sst_debug < 4) break;
	/*FALLTHROUGH*/
	case SST_CE_DEBUG3: if (sst_debug < 3) break;
	/*FALLTHROUGH*/
	case SST_CE_DEBUG2: if (sst_debug < 2) break;
	/*FALLTHROUGH*/
	case SST_CE_DEBUG1:
	/*FALLTHROUGH*/
	default:
		cmn_err(CE_CONT, "^%s:\t%s", name, buf);
		break;
	}
}

D 10
D 12

I 3
#ifndef	_DDICT
E 10
E 12
E 3
/*
D 10
D 12
 * Array of commands supported by the device, suitable for
 * scsi_decode_cmd()
 * Note: Add or remove commands here as appropriate for
 *	 your device.
 */
static char *sst_cmds[] = {
	"\000test unit ready",		/* 0x00 */
	"\001rezero/rewind",		/* 0x01 */
	"\003request sense",		/* 0x03 */
	"\004format",			/* 0x04 */
	"\005read block limits",	/* 0x05 */
	"\007reassign",			/* 0x07 */
	"\010read",			/* 0x08 */
	"\012write",			/* 0x0a */
	"\013seek",			/* 0x0b */
	"\017read reverse",		/* 0x0f */
	"\020write file mark",		/* 0x10 */
	"\022inquiry",			/* 0x12 */
	"\023verify",			/* 0x13 */
	"\024recover buffered data",	/* 0x14 */
	"\025mode select",		/* 0x15 */
	"\026reserve",			/* 0x16 */
	"\027release",			/* 0x17 */
	"\030copy",			/* 0x18 */
	"\031erase tape",		/* 0x19 */
	"\032mode sense",		/* 0x1a */
	"\033start/stop/load",		/* 0x1b */
	"\036door lock",		/* 0x1e */
	"\067read defect data",		/* 0x37 */
	NULL,
};


/*
 * Extended Sense Error Codes - unique to the device.
 * Note: Fill in from your device's hardware manual, same format
 *	 as the sst_cmds array above, i.e. the octal code followed
 *	 by the ascii string.
 */
static char *sst_errors[] = {
NULL
};
I 3
#endif	/* _DDICT */
E 3

/*
E 10
E 12
 * Print a readable error message
 * Note: This uses the arrays 'sst_cmds' and 'sst_errors' defined in
 *	 this file.
 */
I 3

E 3
#define	BUFSZ	256
I 9
D 10

E 9
I 3
D 12
#ifdef	_DDICT
/*ARGSUSED*/
D 9
#endif	/* _DDICT */
E 9
E 3
static void
sst_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, int level)
{
I 3
D 9
#ifndef _DDICT
E 9
I 9
}
#else	/* _DDICT */
static void
sst_errmsg(struct scsi_device *devp, struct scsi_pkt *pkt, int level)
{
E 9
E 3
	auto char	buf[BUFSZ];

	static char *error_classes[] = {
		"All          ", "Unknown      ", "Informational",
		"Recovered    ", "Retryable    ", "Fatal        "
	};

	static int map_to_cmnerr[] = {
		CE_WARN, CE_WARN, CE_NOTE, CE_NOTE, CE_NOTE, CE_WARN
	};

D 3
#ifndef _DDICT
E 3
	(void) sprintf(buf, "Error on command '%s', Level: %s\n",
	    scsi_cname(CDBP(pkt)->scc_cmd, sst_cmds), error_classes[level]);
	sst_log(devp, map_to_cmnerr[level], buf);

	sst_log(devp, CE_CONT, "Sense Key: %s\n",
	    sense_keys[devp->sd_sense->es_key]);
D 3
#endif
E 3

	if (devp->sd_sense->es_code) {
		sst_log(devp, CE_CONT, "Extended error code (0x%x): %s\n",
		    devp->sd_sense->es_code,
		    scsi_cname(devp->sd_sense->es_code, sst_errors));
	}
I 3
D 9
#endif
E 9
E 3
D 8
	return;
E 8
}
I 9
#endif	/* _DDICT */
E 9

E 10
E 12

/*
 * Print a buffer readably
 */
static void
hex_print(char *msg, char *cp, int len)
{
	int i = 0, j;
	char	buf[BUFSZ];

	bzero(buf, BUFSZ);
	for (i = 0; i < len; i++) {
		if ((j = strlen(buf)) >= BUFSZ) {
			buf[BUFSZ-2] = '>';
			buf[BUFSZ-1] = 0;
			break;		/* cp too long, give up */
		}
		(void) sprintf(&buf[j], "%x ", cp[i]);
	}
D 3

E 3
I 3
	cmn_err(CE_CONT, "^%s: %s\n", msg, buf);
E 3
D 15
}	
E 15
I 15
}
E 15
E 1
