4.4BSD/usr/src/sys/dev/scsi/scsivar.h

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratories.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)scsivar.h	8.1 (Berkeley) 6/10/93
 *
 * from: $Header: scsivar.h,v 1.7 92/12/02 03:54:05 torek Exp $ (LBL)
 */

/*
 * SCSI variables.
 *
 * Each SCSI Host Bus Adapter (hba) has:
 *	a target queue head and tail
 *	eight targets (for units to enqueue on)
 *	a list of all units on all targets
 *	its target number (the number cpu uses in initiating requests)
 *	a driver
 * Each SCSI target has:
 *	a forward link so that it can sit on a SCSI host bus adapter queue
 *	a unit queue head and tail
 * Each SCSI unit has:
 *	a forward link so that it can sit on a SCSI target queue
 *	a driver
 *	an hba & driver (so that we need not chase parent pointers)
 */

/*
 * Downcalls.  These are usually made from hba to unit, but can be
 * hba->target->unit (when there are multiple units on a target).
 */
/* device go function (`you got bus') */
typedef void (*scdgo_fn) __P((struct device *, struct scsi_cdb *));

/* intr function (`you no got bus no more') */
typedef void (*scintr_fn) __P((struct device *, int stat, int resid));

/*
 * Upcalls.  These are usually made from unit to hba, but can be
 * unit->target->hba.
 */
/* bus alloc function (`please get me bus') */
struct sq; struct buf;
typedef void (*scstart_fn) __P((struct device *, struct sq *, struct buf *,
				scdgo_fn, struct device *));

/* bus go function (`I have bus and I set up cmd, so start it up') */
typedef int (*scbusgo_fn) __P((struct device *, int targ,
				scintr_fn, struct device *,
				struct buf *, int pad));

/* bus release function (`I have bus but do not need it after all') */
typedef void (*scbusrel_fn) __P((struct device *));

/*
 * SCSI Queue.  This is an element in a queue of devices (targets
 * and/or units) waiting for the bus.
 */
struct sq {
	struct	sq *sq_forw;		/* forward link */
	struct	buf *sq_bp;		/* buffer for transfer */
	scdgo_fn sq_dgo;		/* device-go to call when got bus */
	struct	device *sq_dev;		/* device argument to sq_dgo */
};

struct hba_softc {
	struct	device hba_dev;		/* generic part */
	struct	sq *hba_head, *hba_tail;/* io queue (u's/t's wanting bus) */
	char	hba_busy;		/* true => will inspect qhead later */
	struct	targ *hba_targets[8];	/* the 8 possible targets */
	struct	hbadriver *hba_driver;	/* hba driver */
	scintr_fn hba_intr;		/* current interrupt function */
	struct	device *hba_intrdev;	/* arg 0 for hba_intr */
};

struct targ {
	struct	device t_dev;		/* generic part */
	struct	sq t_forw;		/* forward link, etc, on hba queue */
	struct	sq *t_head, *t_tail;	/* io queue */
	char	t_busy;			/* true => will inspect qhead later */
	char	t_targ;			/* target number */
	char	t_nunits;		/* count of live units */
	char	t_firstunit;		/* the first live unit */
	struct	unit *t_units[8];	/* the 8 possible units */
	scintr_fn t_intr;		/* current interrupt function */
	struct	device *t_intrdev;	/* arg 0 for t_intr */
};

/* since a unit may be a disk, tape, etc., it has only pointer to dev */
struct unit {
	struct	device *u_dev;		/* backpointer to generic */
	int	u_unit;			/* unit number on target */
	scstart_fn u_start;		/* upcall to get bus */
	scbusgo_fn u_go;		/* upcall to use bus */
	scbusrel_fn u_rel;		/* upcall to release bus early */
	struct	device *u_updev;	/* device for upcalls */
	struct	sq u_forw;		/* forward link on target or hba q */
	struct	unitdriver *u_driver;	/* unit driver */
/* the following three fields are copied from target & hba, for quick lookup */
	int	u_targ;			/* target number */
	struct	hba_softc *u_hba;	/* hba, from parent */
	struct	hbadriver *u_hbd;	/* hba driver, from parent */
};

/*
 * SCSI hba driver.
 */
struct hbadriver {
	/* immediate command; should not depend on receiving interrupts */
	int	(*hd_icmd) __P((struct hba_softc *, int targ,
				struct scsi_cdb *cmd,
				caddr_t addr, int len, int rw));
	/* crash dump: like icmd(B_WRITE), but possibly from physmem */
	int	(*hd_dump) __P((struct hba_softc *, int targ,
				struct scsi_cdb *cmd, caddr_t addr, int len));
	scstart_fn hd_start;	/* allocate DMA & bus */
	scbusgo_fn hd_go;	/* start DMA xfer on bus */
	scbusrel_fn hd_rel;	/* release bus early */
	void	(*hd_reset) __P((struct hba_softc *, int));
};

/*
 * SCSI unit driver (`downcalls' from hba to unit).
 */
struct unitdriver {
	void	(*ud_reset) __P((struct unit *));	/* SCSI bus reset */
};

/*
 * The generic SCSI target probe code passes the following to
 * unit configuration `match' routines.
 */
struct scsi_attach_args {
	int	sa_targ;		/* target number */
	int	sa_unit;		/* unit number */
	int	sa_req_status;		/* status from REQUEST SENSE */
	struct	scsi_sense sa_sn;	/* contents from same */
	int	sa_inq_status;		/* status from INQUIRY command */
	struct	scsi_inquiry sa_si;	/* contents from same */
};

/*
 * The SCSICMDLEN macro gives the SCSI-standard-defined length of
 * a given SCSI command.  This is 0 if the command is in an undefined
 * group (see scsi.h).
 */
extern const char scsicmdlen[8];
#define	SCSICMDLEN(cmd) scsicmdlen[(cmd) >> 5]

/*
 * The SCSIMSGLEN macro gives the SCSI-standard-defined length of
 * a given SCSI message byte.  This is -1 if the message byte is
 * undefined, -3 if it is an identify, -2 for an extended message,
 * 0 if it is normal completion, otherwise positive.
 */
#define	SMLEN_IDENTIFY	-3
#define	SMLEN_EXTENDED	-2
#define	SMLEN_UNDEF	-1
#define	SMLEN_DONE	0
extern const signed char scsimsglen[0x24];
#define	SCSIMSGLEN(msg) ((msg) & MSG_IDENTIFY ? SMLEN_IDENTIFY : \
			 (msg) > 0x24 ? SMLEN_UNDEF : scsimsglen[msg])

/*
 * Declarations for exported functions in scsi_subr.c
 */
int	scsi_test_unit_ready __P((struct hba_softc *, int targ, int unit));
int	scsi_request_sense __P((struct hba_softc *, int, int, caddr_t, int));
void	scsi_hbaattach __P((struct hba_softc *));
void	scsi_establish __P((struct unit *, struct device *, int));
void	scsi_printinq __P((struct scsi_inquiry *));
void	scsi_inq_ansi __P((struct scsi_inq_ansi *, char *, char *, char *));
void	scsi_reset_units __P((struct hba_softc *));

#define	SCSI_FOUNDTARGET(hba, targ) { \
	extern int scsi_targprint(void *, char *); \
	int _t = targ; \
	config_found(&(hba)->hba_dev, (void *)&_t, scsi_targprint); \
}