192 lines
6.5 KiB
C
192 lines
6.5 KiB
C
|
/*
|
||
|
* Copyright (c) 1992 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.
|
||
|
*
|
||
|
* %sccs.include.redist.c%
|
||
|
*
|
||
|
* %W% (Berkeley) %G%
|
||
|
*
|
||
|
* from: Header: scsivar.h,v 1.7 92/12/02 03:54:05 torek Exp (LBL)
|
||
|
* $Id: scsivar.h,v 1.1 1993/10/27 17:48:42 deraadt Exp $
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* 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); \
|
||
|
}
|